投稿記事

小ネタの記事 (3)

des 2021/08/07 09:26

VBAを活用してウディタで中国語を表示する方法

(21/8/31執筆、9/9修正)

備考

・翻訳支援ツールが製作中との事ですのでそちらが販売されるまでの暫定的な対応です。
・フォントの利用規約を十分確認してください。今回使用しているMSゴシック及びMSPゴシックは画像として配布さえしなければ問題ないフォントの筈です。
・触り始めて5ヶ月のクソコードです。他の方が公開されているサンプルコードを参考にしました。

本題


(2行目の1文字目が対象)

1年半くらい前の記事ではウディタを用いた変換用の記号への変換と表示について書きましたが、今回は最近裏で覚えたVBAを用いた内容です。
予定には無かったのですが、7月にテキスト画像の背景を透明にして保存する簡単な方法という記事を見つけた結果として今回の方法と完全な実装が実現しました。
この場をお借りしてお礼申し上げます。

フォントの取得

今回の方法ではcsvファイルに格納した文字列を使用します。
私は https://uic.jp/charset/supported_list/ 様から取得しましたが、文字の被り等を考えると後で楽できるようUnicodeの文字コードを取得したほうが良いです。
今回は昔に用意した中国語用の文字コードを使用します。

(サンプルコード)
Sub フォント出力()
Application.ScreenUpdating = False
Dim code As String
code = InputBox("取得元の言語を入力(chs,cht)")
Dim fold As String
'保存先フォルダを指定

If code = "chs" Then
code = "chslist.xlsx"
fold = "chs"
ElseIf code = "cht" Then
code = "chtlist.xlsx"
fold = "cht"
Else
MsgBox "エラーが発生しました。処理を終了します。"
End
End If

'エラー対策(既にリストが開かれていないかの確認)
Dim wb As Workbook, flag As Boolean
For Each wb In Workbooks
If wb.Name = code Then
flag = True
Exit For
End If
Next wb
'開かれてない時だけ開く
If Not flag Then
Workbooks.Open Filename:= _
ThisWorkbook.Path & "/" & code
End If

'雑に変数宣言(細かな設定を弄るならここで)
Dim size As Integer
size = 14

'まずフォルダを作る
If Dir(fold & size, vbDirectory) = "" Then
MkDir fold & size
End If

'下の文字数を減らす為にワークシート名を全て指定
Dim filei As String
filei = "Book2"
Dim file As String
'xlsmから開いた場合と実行後のhtmの場合があるので両方に対応

flag = False
For Each wb In Workbooks
If wb.Name = "Book2.xlsm" Then
flag = True
Exit For
End If
Next wb

If flag = True Then
file = filei & ".xlsm"

'fileをアクティブに
Windows(file).Activate
'xlsmなら一度保存してhtmにする
'警告非表示
Application.DisplayAlerts = False
ActiveWorkbook.SaveAs Filename:= _
ThisWorkbook.Path & "\Book2.htm", _
FileFormat:=xlHtml, ReadOnlyRecommended:=False, CreateBackup:=False
End If
'file名を置き換え
file = filei & ".htm"

'ワークシートの指定はアクティブシートしか反映されないので宣言前にActivateを挟む
Windows(code).Activate
Dim 保存 As Worksheet
Set 保存 = Worksheets("Sheet1")

Dim mes As String
Dim x, y As Long
Dim x16 As String
Dim savef As String

'フォントサイズに応じてテキストボックスのサイズを調整
Windows(file).Activate
If size = 24 Then
With ActiveSheet.Shapes.Range(Array("TextBox 1"))
.Width = 25.5118110236
.Height = 25.5118110236
End With
ElseIf size = 14 Then
With ActiveSheet.Shapes.Range(Array("TextBox 1"))
.Width = 13.8897637795
.Height = 13.8897637795
End With
End If

'途中から再開用
Dim r As Long
r = 2

'動作チェックのため途中で止める
For y = r To Range("a2").End(xlDown).Row
' For y = 2 To 2

Windows(code).Activate
x16 = Cells(y, 1).Value

For x = 2 To 17
Windows(code).Activate
mes = 保存.Cells(y, x).Value
If mes = "" Then
GoTo nx
End If

'保存名を設定(一番上にあるのでそれを利用)
savef = x16 & Cells(1, x)

'元のシートに戻ってテキストボックスに貼り付け
Windows(file).Activate
ActiveSheet.Shapes.Range(Array("TextBox 1")).Select
'文字を指定
Selection.ShapeRange(1).TextFrame2.TextRange.Characters.Text = mes
'書式設定
Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, 1).ParagraphFormat. _
FirstLineIndent = 0
With Selection.ShapeRange(1).TextFrame2.TextRange.Characters(1, 1).Font
'色
.Fill.ForeColor.RGB = RGB(255, 255, 255)
.Fill.Transparency = 0
.Fill.Solid
'サイズ
.size = size
.Name = "+mn-lt"
.NameComplexScript = "+mn-cs"
.NameFarEast = "+mn-ea"
End With
Application.EnableEvents = False

'警告非表示
Application.DisplayAlerts = False
'保存、ThisWorkbook.Pathはこのブックの保存場所
ActiveWorkbook.SaveAs Filename:= _
ThisWorkbook.Path & "\Book2.htm", _
FileFormat:=xlHtml, ReadOnlyRecommended:=False, CreateBackup:=False
FileCopy ThisWorkbook.Path & "/book2.files/image001.png", ThisWorkbook.Path & "/" & fold & size & "/" & savef & ".png"

file = "Book2.htm"

'空白の場合の飛ばし先
nx:
Next
Next
Application.CutCopyMode = False
Application.ScreenUpdating = True
End Sub


Shift-JISの文字を含めた全ての文字を取得するコードでした。
Shift-JIS以外の文字のみにしたい場合は以下の部分を変えてください。
(変更前)
mes = 保存.Cells(y, x).Value
If mes = "" Then
GoTo nx
End If

(Shift-JISの文字を弾くよう変更した場合)
mes = 保存.Cells(y, x).Value
If mes = "" Then
GoTo nx
ElseIf mes <> "?" And _
Asc(mes) = Asc("?") Then
Else
GoTo nx
End If

問題が起こり途中で止まらなければ6時間ほどで保存用フォルダに全ての文字のpng画像が保存されます。
私の環境では1度固まってました。

変換用記号への変換・復号

Excelの該当箇所にコピーして実行すると変換と復号が行われるコードです。

Sub 文章置換()
Application.ScreenUpdating = False

Windows("呼出元.xlsm").Activate
Worksheets("置換").Select
Range("A2", Range("a2").End(xlDown)).Copy
Range("B2").PasteSpecial
Range("C2").PasteSpecial
Application.CutCopyMode = False

Dim code As String
code = InputBox("取得元の言語を入力(chs,cht)")
Dim fold As String
'保存先フォルダを指定

If code = "chs" Then
code = "chslist.xlsx"
fold = "chs"
ElseIf code = "cht" Then
code = "chtlist.xlsx"
fold = "cht"
Else
MsgBox "エラーが発生しました。処理を終了します。"
End
End If
'エラー対策(既にリストが開かれていないかの確認)
Dim wb As Workbook, flag As Boolean
For Each wb In Workbooks
If wb.Name = code Then
flag = True
Exit For
End If
Next wb
'開かれてない時だけ開く
If Not flag Then
Workbooks.Open Filename:= _
ThisWorkbook.Path & "/" & code
End If

Dim 行数 As Long
行数 = Range("a2").End(xlDown).Row
Dim 先頭 As String
Dim x As Long
Dim y As Long
Dim 保存 As String

Dim ループ As Long
For ループ = 2 To 行数

Do Until Cells(ループ, 2) = ""
先頭 = Mid(Cells(ループ, 2), 1, 1)
If 先頭 <> "?" And _
Asc(先頭) = Asc("?") Then

Windows(code).Activate
Cells.Find(What:=先頭, After:=ActiveCell, LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, MatchByte:=False, SearchFormat:=False).Activate
x = ActiveCell.Column
y = ActiveCell.Row
保存 = Cells(y, 1).value & Cells(1, x).value

Windows("呼出元.xlsm").Activate
'機種依存文字を置き換える
Range("A2", Range("a2").End(xlDown)).Offset(0, 2).Select
Selection.Replace What:=先頭, Replacement:="\" & fold & "[" & 保存 & "]", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False


End If
'処理済みの文字を消す
Range("A2", Range("a2").End(xlDown)).Offset(0, 1).Select
Selection.Replace What:=先頭, Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False
Loop

Next
Application.ScreenUpdating = True
End Sub


文章の復号は上の内容より厄介です。

Sub 文章復号()
Application.ScreenUpdating = False

Windows("呼出元.xlsm").Activate
Worksheets("置換").Select
Range("A2", Range("a2").End(xlDown)).Copy
Range("B2").PasteSpecial
Range("C2").PasteSpecial
Application.CutCopyMode = False

Dim code As String
code = InputBox("取得元の言語を入力(chs,cht)")
Dim fold As String
'保存先フォルダを指定

If code = "chs" Then
code = "chslist.xlsx"
fold = "chs"
ElseIf code = "cht" Then
code = "chtlist.xlsx"
fold = "cht"
Else
MsgBox "エラーが発生しました。処理を終了します。"
End
End If
'エラー対策(既にリストが開かれていないかの確認)
Dim wb As Workbook, flag As Boolean
For Each wb In Workbooks
If wb.Name = code Then
flag = True
Exit For
End If
Next wb
'開かれてない時だけ開く
If Not flag Then
Workbooks.Open Filename:= _
ThisWorkbook.Path & "/" & code
End If

Dim 行数 As Long
行数 = Range("a2").End(xlDown).Row
Dim 先頭 As String
Dim x, y As Long
Dim 保存 As String
Dim 置換 As String
Dim ax, ay As String
Dim folen As Integer
folen = Len(fold)

Dim ループ As Long
For ループ = 2 To 行数

Do Until Cells(ループ, 2) = ""
先頭 = Mid(Cells(ループ, 2), 1, folen + 2)
If 先頭 = "\" & fold & "[" Then '一致するなら次の4文字を3文字と1文字で取得 ay = Mid(Cells(ループ, 2), folen + 3, 3) '+1 ax = Mid(Cells(ループ, 2), folen + 6, 1) 'folen +2 + 3 +1 '先頭を]までに置き換える
先頭 = Mid(Cells(ループ, 2), 1, folen + 7) 'folen + (2+4+1)

Windows(code).Activate
Range("a2", Range("a2").End(xlDown)).Select
Cells.Find(What:=ay, After:=ActiveCell, LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, MatchByte:=False, SearchFormat:=False).Activate
y = ActiveCell.Row

'0が入る場合に正常に処理されないので例外
If ax <> "0" Then
Range("b1", Range("b1").End(xlToRight)).Select
Cells.Find(What:=ax, After:=ActiveCell, LookIn:=xlFormulas, LookAt:= _
xlPart, SearchOrder:=xlByRows, SearchDirection:=xlNext, MatchCase:=False _
, MatchByte:=False, SearchFormat:=False).Activate
x = ActiveCell.Column

Else
x = 2

End If

保存 = Cells(y, x).value

Windows("呼出元.xlsm").Activate
'機種依存文字を置き換える
Range("A2", Range("a2").End(xlDown)).Offset(0, 2).Select
Selection.Replace What:=先頭, Replacement:=保存, LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False

Else
'異なるなら1文字だけ取得し削除
先頭 = Mid(Cells(ループ, 2), 1, 1)

End If

'処理済みの文字を消す
Range("A2", Range("a2").End(xlDown)).Offset(0, 1).Select
Selection.Replace What:=先頭, Replacement:="", LookAt:=xlPart, _
SearchOrder:=xlByRows, MatchCase:=False, SearchFormat:=False, _
ReplaceFormat:=False

Loop

Next
Application.ScreenUpdating = True
End Sub


上のコードは、例として\chs[FFF0]という変換用の記号を復号する場合に、『\』、『chs』、『[』、『FFF』、『0』、『]』という6つのブロックに分けて置換を行うというやり方です。
実際に動かすとこんな風になります。(置換)



あとはウディタ側で\chs[ と \cht[ を\img[(ファイルパス) へ置き換えるように書いて文章を表示させる前に処理を挟めば完成です。

以上ですが、全部の文字を入れると約38MBになり、また1度の暗号化作業に30分ほど掛かります。
とても扱いにくい代物ですので、先にゲーム名を合わせた状態で暗号化フォルダを限定するからフォントが入っているフォルダを.wolf形式に変換し、その.wolfファイルを開発用フォルダに入れ元のフォルダは別の所に移しておく事をお勧めします。
ゲーム内ではちゃんと表示され、またゲームデータの作成に掛かる時間も短縮できます。

des 2019/09/21 12:13

【小ネタ】引数対策

定期進捗

(今やってる事)
・バグ取り
・演出やUIの修正
・アイコンの作成
(前回の記事についてあれから)
・2つ目の問題に関しては良い解決策を思いついたので問題はなくなりました。(エロを求めている方にはちょっとどころではなく大変な仕様になりそうですが……)
・1つ目の問題は…………。



下に貼った画像を隠したかったので演出用に作った画像でカモフラージュ

本題

今回も小ネタ(というより急いで対策した挙動)です。

注意

今回の内容はあまり広げるべきではない内容なのですが、過去の内容も十分広げるべきではない内容ですのでネタと備忘録として記事に残しておきます。

色々調べ物をしていた所、ウディタの開発者であるSmokingWOLF氏が2011年にこのような呟きをしていたのを見つけました。
https://twitter.com/WO_LF/status/30203006473474049

知らなかった そんなの・・・(画像略)
……公式チート機能じゃないですかこれ。

問題点

・基本システムのような「元々何が入るか決まっている枠」の書き換えが容易にできてしまう。
・セーブで保存される部分はセーブする事で以降も保持できてしまう。
・F12キーやタイトルに戻るで初期化した時は再び代入される。
・変数呼び出し値で設定可能な場所であればなんでも書き換えられる。
 ただし保存されない部分はセーブデータをロードする事で元の値に戻される、と思われる。
(UDBを変更した場合の参考動画)

試してみた

※画像の枚数が多くなりそうでしたのでbatファイルの内容をそのまま貼り付けてあります。
※文字列の代入はUTF-8で保存したbatファイルだと文字化けします。BOM付きで保存するとGame.exeが起動すらしません。文字コードをShift-JISかANSIにする事で確認した限りでは正常に表示されてました。
※条件は分かりませんが、変数を変更した後に文字列変数を変更して起動しようとすると起動しなくなる事があります。その時は文字コードの再設定をすると解消できます。

通常変数

Start Game.exe -vinput 2000000 16

文字列変数

Start Game.exe -sinput 3000000 あ

コモンセルフ変数

Start Game.exe -vinput 15000000 99

システム変数

※Sys110番の「現在の乱数のシード」を使用
Start Game.exe -vinput 9000110 255

可変データベース

Start Game.exe -sinput 1100000000 文章

ユーザーデータベース

Start Game.exe -sinput 1000000000 ウホウホ

システムデータベース

※弄っても面白い物がないのでSDB12番にある文字色の変更を使用
Start Game.exe -vinput 1312000000 255 -vinput 1312000001 0 -vinput 1312000002 0

セルフ変数

Start Game.exe -vinput 1000000 16
→ウインドウは立ち上がるもののすぐに強○終了。

弄られる事によって生じる問題

致命的な物

・ユーザーデータベースの値を弄る事により装備のパラメータやアイテムの効果を任意の値に設定できるため容易にバランスを破壊できます。
・特定のフラグを立てたりできる為、データの保存方法によってはゲームとして成立しなくなります。
(同人エロゲとしての観点だとフラグ管理をスイッチのように管理している場合は回想シーンを無理やり全開放できる場合があります。)

対策

この隠し機能を本気で対策するとなると以下のような処理を組む必要があり、はっきり言ってかなり面倒くさいです。

対策方法の一例(括弧内に各動作の詳細)

1.通常変数かどこかにフラグ管理用の変数を用意し、該当の変数が条件を満たしていれば起動時に自動実行されるコモンイベントを作っておく。(4の処理が終わり次第遊べるようにするためのイベントを書く)
2.起動した直後に全てのCDB、通常変数、システム変数、文字列変数、コモンセルフ変数を初期化する。(セーブで保存される部分の初期化処理、CSV化しておき起動時に読み込むのが簡単?)
3.はじめからを押したら、直後に使わないマップへ移動させフラグ管理用の変数を立て、使わない枠にセーブ。セーブ完了後すぐに該当セーブデータをロードする。(セーブで保存されない部分の初期化処理。使わないマップに移動させないとマップに自動実行イベントが設定されている場合にマップイベントが優先される)
4.1でイベントを作ったならば3でセーブデータをロードした時に1のイベントが起こるようになるので、フラグ管理用のフラグを消した状態でセーブし直し1のコモンイベントを経由してはじめから遊べるようにする。

……オンライン対応だとこのくらい対策をしなきゃいけない気もしますが、今回は「データを弄る方法が他にある以上、弄りたいなら弄れるようにする」というスタンスを貫き複数の回避方法を取れる雑な方法で対策しました。

凄く雑な対策

■文字列操作:CSelf5 =<→のフォルダのファイルリスト取得> ""
■文字列操作:CSelf5 =<から文字列を置換> "B" → "b"
■文字列操作:CSelf5 =<から文字列を置換> "A" → "a"
■文字列操作:CSelf5 =<から文字列を置換> "T" → "t"
▼ batファイルが含まれているなら起動を中断
■条件分岐(文字): 【1】 CSelf5が ".bat" を含む
-◇分岐: 【1】 CSelf5 ".bat" を含む の場合↓
|■ループ開始
| |■ウェイト:1 フレーム
| |■
|◇ループここまで◇◇
|■
◇分岐終了◇
■文字列操作:CSelf5 = ""

上の説明

1.まずGame.exeがあるフォルダのファイルリストを取得
2.拡張子に大文字が含まれていると正しく判定できないので該当文字列を全て小文字に変更
3.拡張子がbatのファイルがあれば無限ループを起こすよう条件分岐
※凄く雑な対策ですので「.bat.txt」等のファイル名に複数の拡張子が含まれている場合に誤検出が起きます。

という訳で引数対策の記事でした。
あとで色々直さないと……。

des 2019/09/06 19:56

(9/10追記有)【小ネタ】ウディタでコマンドプロンプトを操作するCSVファイルを生成する

追記(9月10日)

本文に誤りがありましたので訂正いたしました。
謹んでお詫び申し上げます。



出せるネタが無いのでゲームとは関係の無いタイトルどおり小ネタです。
「ウディタで」とは書きましたが、ファイルを出力できるツール類なら何でも可能です。というかここまでまどろっこしい事をする必要はありません。

前提となる解説は下記の記事を読んだほうが早いのでまずはこちらを。

覆された常識、CSVファイルでウイルス感染 - 日経 xTECH 2018/05/30 05:00
https://tech.nikkeibp.co.jp/atcl/nxt/column/18/00001/00535/

仕組みとしてはExcelがダウンロードされているPCは初期設定だとCSVファイルはExcelで開かれてしまう事を利用し、悪意のある関数等が書き込まれたファイルを開かせてどうのこうのするという手法らしいです。
この挙動は何かに使えそうという事で、ネット上に公開されていた電卓を起動するサンプルコードをお借りして試しに起動させてみました。

サンプルコード

DDEAUTO {C:\Windows\System32\cmd.exe}
=cmd|'/C "calc"'!a2

※1行目はDDE関数を用いてコマンドプロンプトを開くコードなので変更不可。→必要ありませんでした。(9月10日修正)
※/Cを/Kにするとコマンドプロンプトを表示したままにできるので確認時は少し楽です。

と、確かに電卓が起動しました。
ちなみにこのコードにある「"calc"」はsystem32内にあるファイル名を表していると思われます。(一部開かないファイルがあるので不確定)
ですので、以下のように変えるとsystem32内の別ファイルを起動できます。
(例)
"notepad":メモ帳
"mspaint":旧版のペイント
"control":コントロールパネル
"dxdiag":DirectX 診断ツール
"Taskmgr":タスクマネージャ(挙動が怪しいので使わないほうがいいかも)

もう少し踏み込んでsystem32外にあるファイルを指定します。

サンプルコード

注意:原因は分かりませんがCookieが破損する事があります。(1敗)
DDEAUTO {C:\Windows\System32\cmd.exe}
=cmd|'/C "C:\Program Files (x86)\Google\Chrome\Application\chrome.exe"'!a1


このファイルを開くとGoogle Chromeが立ち上がります。
気合で弄ってたら開くようになったので理由は知りませんが、ファイルパスを直接指定すると開くようです。

ここからが本番で、CDBにコードを書き込んでcsvファイルで出力します。
まずコモンイベントを雑に作ります。


※1行目はデータ名が入るので!a1を!a2に変えておく。
単にcsvファイルにするだけならtxtファイルとして保存する機能を用いてもできますが、保存先の利便性の都合で今回はCDBを使います。

テストプレイで起動し実行

できました。

という訳でゲーム面で使う機会のない小ネタでした。

最後に一言。
csvファイルをExcelで開く時は気を付けよう!

追記(9月10日)

ADV170021 | Microsoft Office の多層防御機能の更新プログラム - Microsoft 最終更新日 : 2019/08/13
https://portal.msrc.microsoft.com/ja-jp/security-guidance/advisory/ADV170021
さらに調べた所1年ほど前のアップデートで対策パッチが配布されてました。

おまけ

拡張子をxlsにして出力してもなぜか動きました。
txtファイルと互換性があるんですね……。

フォロワー以上限定無料

追記(今回の内容に関連した過去記事の補足)

無料

記事のタグから探す

月別アーカイブ

限定特典から探す

記事を検索