[Scummvm-git-logs] scummvm-tools master -> 12ca962b150f2eca76785827c361ede3cbbde29b
sev-
sev at scummvm.org
Sun Dec 6 17:08:20 UTC 2020
This automated email contains information about 167 new commits which have been
pushed to the 'scummvm-tools' repo located at https://github.com/scummvm/scummvm-tools .
Summary:
28f00e58cd TOOLS: PETKA: Initial commit
f0008988a6 TOOLS: PETKA: Objects and scenes
9c043f222a TOOLS: PETKA: Fix from loading DEMO
8f3e8e5d64 TOOLS: PETKA: Canvas rendering, BMP loading
37c26c9520 TOOLS: PETKA: Resource list
7d64e0d2b5 TOOLS: PETKA: Select part, select resource
9405a96b3a TOOLS: PETKA: Fix unloading stores
b2342c929b TOOLS: PETKA: Switchable canvas and frame
acea4a19eb TOOLS: PETKA: Siwtchable interface works, outline mode
cdb9edbb36 TOOLS: PETKA: Info panel fixes (not yet finished)
42806a5366 TOOLS: PETKA: Switchable interface works
86a8ced5ac TOOLS: PETKA: Fix unloading stores
8f81a2b914 TOOLS: PETKA: Refine outline information
dd01092a27 TOOLS: PETKA: Refine outline information
f7dfc9c6f1 TOOLS: PETKA: Hyperlinks in info panel
8ed83d8ed4 TOOLS: PETKA: Info panel works, refactor
56e1eaa097 TOOLS: PETKA: Names and invntr information
0600e6948c TOOLS: PETKA: Names anr invntr order as in file
82c8104b14 TOOLS: PETKA: Open aliases and invntr from objects, refactor
b62ea77dc2 TOOLS: PETKA: Cleanup removed links
4d17a6243e TOOLS: PETKA: Cleanup removed links
715ed6ef51 TOOLS: PETKA: Resource filters
47a787d10e TOOLS: PETKA: Refactor, scene referenced objects
26b39b9aa3 TOOLS: PETKA: Refactor navigation
9b4d47482c TOOLS: PETKA: Refactor: objects, scenes, parts workss again
4b7bd0f016 TOOLS: PETKA: Refactor: names and invntr works
0c54fa10a2 TOOLS: PETKA: Refactor: names and invntr works
6cad232811 TOOLS: PETKA: Refactor: test image and info panel
b7adac7302 TOOLS: PETKA: Refactor: switch info and canvas
72bf691b39 TOOLS: PETKA: Refactor: resources works (filter and all list)
4f62901edd TOOLS: PETKA: Refactor image loading
11850e3b02 TOOLS: PETKA: Refactor image loading
c86264eca6 TOOLS: PETKA: Initial Pillow support
bfabee3932 TOOLS: PETKA: Pillow support (not finished)
b9c84877f9 TOOLS: PETKA: Reading BMP with PILLOW (baggy)
2603ab1f9b TOOLS: PETKA: Reading BMP with PILLOW (baggy)
cf98f30a46 TOOLS: PETKA: BMP can be loaded correctly most times
8afb6d50b0 TOOLS: PETKA: Select only one item in listbox, refine
e98266437b TOOLS: PETKA: REfactor: internal locations and text tagging
8c273ad397 TOOLS: PETKA: Information for bmp and same
c6045ebfa0 TOOLS: PETKA: fix
593103b907 TOOLS: PETKA: Fix switchinf resource filter
c508e1a902 TOOLS: PETKA: View FLC files (pallette not loaded)
73d0812642 TOOLS: PETKA: Messages works
f7fa014126 TOOLS: PETKA: Messages works
ee14e7f6c3 TOOLS: PETKA: Dialogue.fix groups (partial)
423e063c13 TOOLS: PETKA: dialogues works
d3f052e1bd TOOLS: PETKA: links from messages to dialoggroups
a1665895e4 TOOLS: PETKA: refactor
58398995a4 TOOLS: PETKA: refactor
ac443fbabf TOOLS: PETKA: links from dialog acts to objects
f6dc6ed300 TOOLS: PETKA: refactor
ace7622382 TOOLS: PETKA: more links to dialogs
720c836c5d TOOLS: PETKA: fix underline on win
b3e0b4b37b TOOLS: PETKA: History (only back)
0430f3a412 TOOLS: PETKA: History (only back)
0e69814055 TOOLS: PETKA: History fixed for not item selected
05a3a11403 TOOLS: PETKA: History fixed for not item selected
655ff79ed9 TOOLS: PETKA: History back and forward works
a7922be8fa TOOLS: PETKA: Clear history on part change
eec272940b TOOLS: PETKA: Open dialog, small fixes
d2c1894e9c TOOLS: PETKA: ref to object from action handler
b590021b4c TOOLS: PETKA: Dist file for cx_Freeze
726a9148be TOOLS: PETKA: release 0.2a (fix using resources in freeze mode)
71e35612b7 TOOLS: PETKA: release 0.2b (fix errors when no data loaded, add support information)
df73109607 TOOLS: PETKA: release 0.2c (fix support page)
ccbd3e23f8 TOOLS: PETKA: release 0.2c
706c7d5b1a TOOLS: PETKA: Fix gui, wat to fix path with incorrect loading
186095934c TOOLS: PETKA: Help pages
f3918517d0 TOOLS: PETKA: refactor internal paths
c2f1863df4 TOOLS: PETKA: refactor onjs and scenes
9b7ff2f6ff TOOLS: PETKA: refactor
92814b2799 TOOLS: PETKA: refactor
855c321e5a TOOLS: PETKA: Casts data
5faa366358 TOOLS: PETKA: Casts data
d8cc88b71b TOOLS: PETKA: refactor
82d97637d1 TOOLS: PETKA: refactor
e5adc359d0 TOOLS: PETKA: Context help
fc10e027f2 TOOLS: PETKA: Info, help pages
1bd7e2b3b9 TOOLS: PETKA: help pages
1f44482793 TOOLS: PETKA: fixes
5aa3199fde TOOLS: PETKA: Open data and select item from command line
d1f513f432 TOOLS: PETKA: fix dist
30075a2450 TOOLS: PETKA: Commant for dialog opcode 8
aa5eafc13a TOOLS: PETKA: code position for dialog opcodes
5e4bfe56ef TOOLS: PETKA: Improved help system
ce018979a3 TOOLS: PETKA: More dialog opcodes information in MENU
55c1dac47c TOOLS: PETKA: More dialog opcodes information in MENU
1caee4daec TOOLS: PETKA: More dialog opcodes for BREAK
86b69588ea TOOLS: PETKA: fix
45ef71d4bb TOOLS: PETKA: Decompile highlighting
adf0fe0f22 TOOLS: PETKA: Display cast colors
83c51d77a6 TOOLS: PETKA: Show where object used in TALK opcode
611c55928c TOOLS: PETKA: Show where object used in TALK opcode
3223278961 TOOLS: PETKA: Show where object used in all opcodes
c32cf831b5 TOOLS: PETKA: search opcodes refs in scenes too
5c26722f94 TOOLS: PETKA: test export .pot files
91b4caf9ce TOOLS: PETKA: Translation tools
81d2dbbea5 TOOLS: PETKA: add help file for translations
ece09a8a91 TOOLS: PETKA: Add license file
2ecdc95048 TOOLS: PETKA: refactor
adc0fdd3ae TOOLS: PETKA: Fix loading BGS.INI, add support info about start scene
641d9860b5 TOOLS: PETKA: Fix loading BGS.INI, add support info about start scene
c3fc6f0331 TOOLS: PETKA: Add enter areas information
c31c1f8f7d TOOLS: PETKA: transliterate templates
396efadba7 TOOLS: PETKA: release 0.2n; remove tranliterate library
01173a0031 TOOLS: PETKA: release 0.2n; remove tranliterate library
740c900e52 TOOLS: PETKA: release 0.2l
f0d14889aa TOOLS: PETKA: fix version
80f87766e1 TOOLS: PETKA: fix resource opening
73ead29a64 TOOLS: PETKA: Fix translit Capital cyrillic E
d81b65fe32 TOOLS: PETKA: Standalone decompiler for SCRIPT.DAT
668a706517 TOOLS: PETKA: Compiler for SCRIPT.DAT
c4a8a50350 TOOLS: PETKA: Decompiler for DIALOGUE.FIX and .LOD
68e2468825 TOOLS: PETKA: Compile dialog - dialogue.lod
1f1901479c TOOLS: PETKA: Compiler for dialogs
bd67cfbdba TOOLS: PETKA: fix doc
ce8130943d TOOLS: PETKA: Fixes
2e1f405a36 TOOLS: PETKA: Fixes
75743464db TOOLS: PETKA: license.txt оÑÑедакÑиÑован онлайн на Bitbucket
8aa21d6ce2 TOOLS: PETKA: Add opcodes and dialog opcodes statistic
736358e9a0 TOOLS: PETKA: Fix group display
a954806273 TOOLS: PETKA: Fix changes
b33be223a7 TOOLS: PETKA: Fix loading FLC with Pillow
aa0c112ff3 TOOLS: PETKA: changes
b380b5dfc8 TOOLS: PETKA: add stores info
f30896d019 TOOLS: PETKA: Store and file view works
97f1822092 TOOLS: PETKA: Display sorted wav list in messages section
aa4025e708 TOOLS: PETKA: Extract STR files
6c2a6061ae TOOLS: PETKA: testing page modes
0add1b8e92 TOOLS: PETKA: show history path
9128fae7fa TOOLS: PETKA: sort modes for messages
1e024eabb3 TOOLS: PETKA: add label to toolbar
d87373a2bf TOOLS: PETKA: files related info
98b6710ceb TOOLS: PETKA: fix bunch of error. improvements
f5c4aa3cdc TOOLS: PETKA: sort files, files in stores
65bbf7768e TOOLS: PETKA: fix long lists
2be7275bd5 TOOLS: PETKA: fix tab for opcodes
56a2a6b1c1 TOOLS: PETKA: decode MSK, LEG, OFF. display MSK, LEG, OFF, FLC
36514cf080 TOOLS: PETKA: fix doc
040c526b50 TOOLS: PETKA: fix doc, fix other
7c2bb9349c TOOLS: PETKA: enchance
08e06d907b TOOLS: PETKA: fixes
78fd00b49c TOOLS: PETKA: canv resize
56d009d9d5 TOOLS: PETKA: refactor bgs loading
17d4eba581 TOOLS: PETKA: save decoding
762ebd64ed TOOLS: PETKA: saved decoding: inventory
a820343b11 TOOLS: PETKA: saves decoding: charter positions, cursor resources
d8b4720443 TOOLS: PETKA: saves: struct decoded
34ad33b6b1 TOOLS: PETKA: saves display
b266ee00dd TOOLS: PETKA: fixes
f5a459b9ae TOOLS: PETKA: fix dislog opcodes info
7f09c7ed2a TOOLS: PETKA: saves almost decoded
21155abca7 TOOLS: PETKA: saves loading in engine (wip)
31cf5f8126 TOOLS: PETKA: fix compiler: creating scenes with zero references to objects
9f0f8c56ea TOOLS: PETKA: change save decoding
3219f4b115 TOOLS: PETKA: add interlinks for objetcs and dialog groups. allow open home sites
461afeebad TOOLS: PETKA: fix scenes with no referenced objects. add interlinks between objects and scenes
ba42c34aa5 TOOLS: PETKA: Refactor GUI to separate file
b6ef152bc3 TOOLS: PETKA: refactor gui
950acde83a TOOLS: PETKA: Fixes for gui
49cc81971b TOOLS: PETKA: linefeed do not break color tags
9f235c5d8e TOOLS: PETKA: refactor markup
66a62d9911 TOOLS: PETKA: replace html parser with HtmlParser
bfb4aa5058 TOOLS: PETKA: Add new dump function - for automatic testing generated data
0225608fd3 TOOLS: PETKA: Bring to modern python3
12ca962b15 JANITORIAL: Remove trailing spaces
Commit: 28f00e58cd27ee86e25da4ec0a959ee261895e3c
https://github.com/scummvm/scummvm-tools/commit/28f00e58cd27ee86e25da4ec0a959ee261895e3c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Initial commit
Changed paths:
A engines/petka/p12explore.py
A engines/petka/petka/__init__.py
A engines/petka/petka/engine.py
A engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
new file mode 100755
index 000000000..9d7e1969e
--- /dev/null
+++ b/engines/petka/p12explore.py
@@ -0,0 +1,87 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import sys, os
+import tkinter
+from tkinter import ttk
+
+import petka
+
+APPNAME = "P1&2 Explorer"
+
+class App(tkinter.Frame):
+ def __init__(self, master):
+ tkinter.Frame.__init__(self, master)
+ master.title(APPNAME)
+ self.pack(fill = tkinter.BOTH, expand = 1)
+ self.createWidgets()
+ self.createMenu()
+
+ self.sim = None
+
+ def createWidgets(self):
+
+ ttk.Style().configure("Tool.TButton", width = -1) # minimal width
+ #ttk.Style().configure("TLabel", padding = PADDING)
+
+
+ def createMenu(self):
+ self.menubar = tkinter.Menu(self.master)
+ self.master.configure(menu = self.menubar)
+
+ self.menufile = tkinter.Menu(self.master, tearoff = 0)
+ self.menubar.add_cascade(menu = self.menufile,
+ label="File")
+ self.menufile.add_command(
+ command = self.on_open_data,
+ label="Open data...")
+ self.menufile.add_separator()
+ self.menufile.add_command(
+ command = self.on_exit,
+ label="Quit")
+
+ self.menuedit = tkinter.Menu(self.master, tearoff = 0)
+ self.menubar.add_cascade(menu = self.menuedit,
+ label="Edit")
+ self.menuedit.add_command(
+ command = self.on_select_chapter,
+ label="Select chapter")
+
+ def on_exit(self):
+ self.master.destroy()
+
+ def on_open_data(self):
+ # open data - select TODO
+ pass
+
+ def on_select_chapter(self):
+ # TODO
+ pass
+
+ def open_data_from(self, folder):
+ self.sim = petka.Engine()
+ self.sim.load_data(folder, "cp1251")
+ self.sim.open_part(0, 0)
+
+def main():
+ root = tkinter.Tk()
+ app = App(master = root)
+ if len(sys.argv) > 1:
+ fn = sys.argv[1]
+ else:
+ fn = "."
+ app.open_data_from(fn)
+
+ app.mainloop()
+ #fman = petka.FileManager(".")
+ #fman.load_store("patch.str")
+ #fman.load_store("main.str")
+ #for k, v in fman.strtable.items():
+ # print(k, "=", v)
+ # cleanup
+ #fman.unload_stores()
+
+if __name__ == "__main__":
+ main()
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
new file mode 100644
index 000000000..5bcfed3b5
--- /dev/null
+++ b/engines/petka/petka/__init__.py
@@ -0,0 +1,4 @@
+# pass
+
+from .fman import FileManager
+from .engine import Engine
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
new file mode 100644
index 000000000..69bf403b3
--- /dev/null
+++ b/engines/petka/petka/engine.py
@@ -0,0 +1,86 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import os
+import struct
+
+from . import FileManager
+
+class Engine:
+ def __init__(self):
+ self.fman = None
+ self.parts = []
+ self.start_part = None
+ self.start_chap = None
+ self.start_scene = None
+
+ self.curr_part = None
+ self.curr_chap = None
+
+ self.curr_path = None
+ self.curr_speech = None
+ self.curr_diskid = None
+
+
+ def parse_ini(self, f):
+ # parse ini settings
+ curr_sect = None
+ ini = {}
+ for line in f.readlines():
+ line = line.decode(self.enc).strip()
+ if len(line) == 0: continue
+ if line[:1] == ";": continue
+ if line[:1] == "[" and line[-1:] == "]":
+ curr_sect = line[1:-1].strip()
+ ini[curr_sect] = {}
+ continue
+ kv = line.split("=", 1)
+ if len(kv) != 2: continue
+ ini[curr_sect][kv[0].strip()] = kv[1].strip()
+ return ini
+
+ def load_data(self, folder, enc):
+ self.fman = FileManager(folder)
+ self.enc = enc
+ # load PARTS.INI
+ pf = self.fman.find_path("parts.ini")
+ f = open(pf, "rb")
+ try:
+ self.parts_ini = self.parse_ini(f)
+ finally:
+ f.close()
+ if "All" in self.parts_ini:
+ if "Part" in self.parts_ini["All"]:
+ self.start_part = int(self.parts_ini["All"]["Part"])
+ if "Chapter" in self.parts_ini["All"]:
+ self.start_chap = int(self.parts_ini["All"]["Chapter"])
+ for sect, data in self.parts_ini.items():
+ if sect == "All":
+ if "Part" in data:
+ self.start_part = int(data["Part"]) - 1
+ if "Chapter" in data:
+ self.start_chap = int(data["Chapter"]) - 1
+ elif sect[:5] == "Part ":
+ self.parts.append(data)
+ # load BGS.INI
+ pf = self.fman.find_path("bgs.ini")
+ f = open(pf, "rb")
+ try:
+ self.bgs_ini = self.parse_ini(f)
+ finally:
+ f.close()
+ if "Settings" in self.bgs_ini:
+ if "StartRoom" in self.bgs_ini["Settings"]:
+ self.start_scene = self.bgs_ini["Settings"]["StartRoom"]
+
+ def open_part(self, part, chap):
+ pname = "Part {}".format(part)
+ pcname = pname
+ if chap:
+ pcname += " Chapter {}".format(chap)
+ self.curr_path = self.parts_ini[pname]["CurrentPath"]
+ self.curr_speech = self.parts_ini[pname]["PathSpeech"]
+ self.curr_diskid = self.parts_ini[pname]["DiskID"]
+
+
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
new file mode 100644
index 000000000..ade282255
--- /dev/null
+++ b/engines/petka/petka/fman.py
@@ -0,0 +1,72 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import os
+import struct
+
+# manage files data
+class FileManager:
+ def __init__(self, root):
+ self.root = root
+
+ self.strfd = []
+ self.strtable = {}
+
+ def find_path(self, path):
+ # search case insensive from root
+ dpath = []
+ npath = self.root
+ for item in path.split("/"):
+ if not item: continue
+ ok = False
+ for ritem in os.listdir(npath):
+ if item.lower() != ritem.lower(): continue
+ npath = os.path.join(npath, ritem)
+ ok = True
+ break
+ if not ok: return None
+ return npath
+
+
+
+ def load_store(self, name):
+ path = self.find_path(name)
+ if path is None:
+ print("DEBUG: Store \"{}\" not found".format(name))
+ return
+ # scan table
+ f = open(path, "rb")
+ # check magic string "StOR"
+ magic = f.read(4)
+ if magic != b"StOR":
+ print("DEBUG: Bad magic in \"{}\"".format(name))
+ return
+ # read index table ref
+ temp = f.read(4)
+ index_ref = struct.unpack_from("<I", temp)[0]
+ f.seek(index_ref)
+ # index table length
+ temp = f.read(4)
+ index_len = struct.unpack_from("<I", temp)[0]
+ index_table = []
+ for iref in range(index_len):
+ temp = f.read(12)
+ data = struct.unpack_from("<III", temp)
+ index_table.append((data[1], data[2]))
+ data = f.read().decode("ascii")
+ for idx, fname in enumerate(data.split("\x00")):
+ if idx < index_len and fname not in self.strtable:
+ self.strtable[fname] = (len(self.strfd), ) + \
+ tuple(index_table[idx])
+ # add file descriptor
+ self.strfd.append((f, name))
+
+
+ def unload_stores(self):
+ for fd, name in self.strfd:
+ try:
+ if fd: fd.close()
+ except Exception as e:
+ print("DEBUG: Can't unload \"{}\":".format(name) + str(e))
+
Commit: f0008988a68e33186323a3ae80175ad8ead07268
https://github.com/scummvm/scummvm-tools/commit/f0008988a68e33186323a3ae80175ad8ead07268
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Objects and scenes
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9d7e1969e..720fe9876 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -64,6 +64,9 @@ class App(tkinter.Frame):
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
self.sim.open_part(0, 0)
+ #self.sim.open_part(1, 0)
+ #self.sim.open_part(2, 0)
+ #self.sim.open_part(3, 0)
def main():
root = tkinter.Tk()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 69bf403b3..ac7196309 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -7,6 +7,11 @@ import struct
from . import FileManager
+class ScrObject:
+ def __init__(self, idx, name):
+ self.idx = idx
+ self.name = name
+
class Engine:
def __init__(self):
self.fman = None
@@ -63,24 +68,107 @@ class Engine:
self.start_chap = int(data["Chapter"]) - 1
elif sect[:5] == "Part ":
self.parts.append(data)
- # load BGS.INI
- pf = self.fman.find_path("bgs.ini")
- f = open(pf, "rb")
- try:
- self.bgs_ini = self.parse_ini(f)
- finally:
- f.close()
- if "Settings" in self.bgs_ini:
- if "StartRoom" in self.bgs_ini["Settings"]:
- self.start_scene = self.bgs_ini["Settings"]["StartRoom"]
+ # std stores
+ self.fman.load_store("patch.str")
+ self.fman.load_store("main.str")
def open_part(self, part, chap):
+ self.fman.unload_stores(1)
pname = "Part {}".format(part)
pcname = pname
if chap:
pcname += " Chapter {}".format(chap)
- self.curr_path = self.parts_ini[pname]["CurrentPath"]
- self.curr_speech = self.parts_ini[pname]["PathSpeech"]
- self.curr_diskid = self.parts_ini[pname]["DiskID"]
+ ini = self.parts_ini[pname]
+ self.curr_path = ini["CurrentPath"]
+ self.curr_speech = ini["PathSpeech"]
+ self.curr_diskid = ini["DiskID"]
+ # load BGS.INI
+ self.bgs_ini = {}
+ self.start_scene = None
+ pf = self.fman.find_path(self.curr_path + "bgs.ini")
+ print(self.curr_path)
+ if pf:
+ f = open(pf, "rb")
+ try:
+ self.bgs_ini = self.parse_ini(f)
+ finally:
+ f.close()
+ if "Settings" in self.bgs_ini:
+ if "StartRoom" in self.bgs_ini["Settings"]:
+ self.start_scene = self.bgs_ini["Settings"]["StartRoom"]
+ # load .STR
+ strs = ["Flics", "Background", "Wav", "Music", "SFX"]
+ for strf in strs:
+ pf = self.fman.find_path(self.curr_path + "bgs.ini")
+ if not pf: continue
+ if strf in ini:
+ self.fman.load_store(ini[strf], 1)
+ # load script
+ self.load_script()
+
+ def load_script(self):
+ self.objects = []
+ self.scenes = []
+ self.obj_idx = {}
+ self.scn_idx = {}
+
+ data = self.fman.read_data(self.curr_path + "script.dat")
+ num_obj, num_scn = struct.unpack_from("<II", data[:8])
+ off = 8
+ def read_rec(off):
+ obj_id, name_len = struct.unpack_from("<HI", data[off:off + 6])
+ off += 6
+ name = data[off:off + name_len].decode(self.enc)
+ off += name_len
+ num_act = struct.unpack_from("<I", data[off:off + 4])[0]
+ off += 4
+ acts = []
+ for i in range(num_act):
+ act_id, act_cond, act_arg, num_op = struct.unpack_from(\
+ "<HBHI", data[off:off + 9])
+ off += 9
+ ops = []
+ for j in range(num_op):
+ op = struct.unpack_from("<5H", data[off:off + 10])
+ off += 10
+ ops.append(op)
+ acts.append([act_id, act_cond, act_arg, ops])
+ rec = ScrObject(obj_id, name)
+ rec.acts = acts
+ return off, rec
+ for i in range(num_obj):
+ off, obj = read_rec(off)
+ self.objects.append(obj)
+ self.obj_idx[obj.idx] = obj
+
+ for i in range(num_scn):
+ off, scn = read_rec(off)
+ self.scenes.append(scn)
+ self.scn_idx[scn.idx] = scn
+
+ data = self.fman.read_data(self.curr_path + "backgrnd.bg")
+ num_rec = struct.unpack_from("<I", data[:4])[0]
+ off = 4
+ for i in range(num_rec):
+ scn_ref, num_ref = struct.unpack_from("<HI", data[off:off + 6])
+ off += 6
+ if scn_ref in self.scn_idx:
+ scn = self.scn_idx[scn_ref]
+ scn.refs = []
+ else:
+ print("DEBUG: Scene ID = 0x{:x} not found".format(scn_ref))
+ scn = None
+ for j in range(num_ref):
+ ref = struct.unpack_from("<H5I", data[off:off + 22])
+ off += 22
+ if scn:
+ if ref[0] in self.obj_idx:
+ obj = self.obj_idx[ref[0]]
+ scn.refs.append([obj] + list(ref[1:]))
+ else:
+ print("DEBUG: Object ID = 0x{:x} not found".\
+ format(obj[0]))
+
+
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index ade282255..0a59ca398 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -17,6 +17,7 @@ class FileManager:
# search case insensive from root
dpath = []
npath = self.root
+ path = path.replace("\\", "/")
for item in path.split("/"):
if not item: continue
ok = False
@@ -30,7 +31,7 @@ class FileManager:
- def load_store(self, name):
+ def load_store(self, name, tag = 0):
path = self.find_path(name)
if path is None:
print("DEBUG: Store \"{}\" not found".format(name))
@@ -56,15 +57,34 @@ class FileManager:
index_table.append((data[1], data[2]))
data = f.read().decode("ascii")
for idx, fname in enumerate(data.split("\x00")):
- if idx < index_len and fname not in self.strtable:
- self.strtable[fname] = (len(self.strfd), ) + \
- tuple(index_table[idx])
+ if idx < index_len and fname.lower() not in self.strtable:
+ self.strtable[fname.lower()] = (len(self.strfd),) + index_table[idx]
# add file descriptor
- self.strfd.append((f, name))
+ self.strfd.append((f, name, tag))
+ def read_data(self, fname):
+ sf = fname.lower()
+ if sf in self.strtable:
+ fnum, st, ln = self.strtable[sf]
+ self.strfd[fnum][0].seek(st)
+ return self.strfd[fnum][0].read(ln)
+ else:
+ pf = self.find_path(fname)
+ if not pf:
+ print("DEBUG: Can't open file \"{}\"".format(fname))
+ # file in filesystem
+ f = open(pf, "rb")
+ try:
+ data = f.read()
+ finally:
+ f.close()
+ return data
+
- def unload_stores(self):
- for fd, name in self.strfd:
+ def unload_stores(self, flt = None):
+ for fd, name, tag in self.strfd:
+ if flt is not None:
+ if tag != flt: continue
try:
if fd: fd.close()
except Exception as e:
Commit: 9c043f222a4067d1a299b4534848a8b6e5bbfdae
https://github.com/scummvm/scummvm-tools/commit/9c043f222a4067d1a299b4534848a8b6e5bbfdae
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Fix from loading DEMO
Changed paths:
engines/petka/petka/engine.py
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index ac7196309..c7930e35d 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -50,38 +50,45 @@ class Engine:
self.enc = enc
# load PARTS.INI
pf = self.fman.find_path("parts.ini")
- f = open(pf, "rb")
- try:
- self.parts_ini = self.parse_ini(f)
- finally:
- f.close()
- if "All" in self.parts_ini:
- if "Part" in self.parts_ini["All"]:
- self.start_part = int(self.parts_ini["All"]["Part"])
- if "Chapter" in self.parts_ini["All"]:
- self.start_chap = int(self.parts_ini["All"]["Chapter"])
- for sect, data in self.parts_ini.items():
- if sect == "All":
- if "Part" in data:
- self.start_part = int(data["Part"]) - 1
- if "Chapter" in data:
- self.start_chap = int(data["Chapter"]) - 1
- elif sect[:5] == "Part ":
- self.parts.append(data)
+ if pf:
+ f = open(pf, "rb")
+ try:
+ self.parts_ini = self.parse_ini(f)
+ finally:
+ f.close()
+ for sect, data in self.parts_ini.items():
+ if sect == "All":
+ if "Part" in data:
+ self.start_part = int(data["Part"]) - 1
+ if "Chapter" in data:
+ self.start_chap = int(data["Chapter"]) - 1
+ elif sect[:5] == "Part ":
+ self.parts.append(data)
+ else:
+ # load BGS.INI only (e.g. DEMO)
+ self.parts_ini = None
+
# std stores
self.fman.load_store("patch.str")
self.fman.load_store("main.str")
def open_part(self, part, chap):
self.fman.unload_stores(1)
- pname = "Part {}".format(part)
- pcname = pname
- if chap:
- pcname += " Chapter {}".format(chap)
- ini = self.parts_ini[pname]
- self.curr_path = ini["CurrentPath"]
- self.curr_speech = ini["PathSpeech"]
- self.curr_diskid = ini["DiskID"]
+ if self.parts_ini:
+ pname = "Part {}".format(part)
+ pcname = pname
+ if chap:
+ pcname += " Chapter {}".format(chap)
+ ini = self.parts_ini[pname]
+ self.curr_path = ini["CurrentPath"]
+ self.curr_speech = ini["PathSpeech"]
+ self.curr_diskid = ini["DiskID"]
+ else:
+ ini = {}
+ self.curr_path = ""
+ self.curr_speech = ""
+ self.curr_diskid = None
+
# load BGS.INI
self.bgs_ini = {}
@@ -171,4 +178,3 @@ class Engine:
print("DEBUG: Object ID = 0x{:x} not found".\
format(obj[0]))
-
Commit: 8f3e8e5d64de2e8c7d6a71147be534b841d1d491
https://github.com/scummvm/scummvm-tools/commit/8f3e8e5d64de2e8c7d6a71147be534b841d1d491
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Canvas rendering, BMP loading
Changed paths:
A engines/petka/petka/imgbmp.py
engines/petka/p12explore.py
engines/petka/petka/__init__.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 720fe9876..4fa371dd8 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -5,7 +5,7 @@
import sys, os
import tkinter
-from tkinter import ttk
+from tkinter import ttk, font
import petka
@@ -16,42 +16,211 @@ class App(tkinter.Frame):
tkinter.Frame.__init__(self, master)
master.title(APPNAME)
self.pack(fill = tkinter.BOTH, expand = 1)
- self.createWidgets()
- self.createMenu()
-
+ #self.createWidgets()
+ #self.createMenu()
+ self.pad = None
self.sim = None
+ self.curr_mode = 0
+ self.curr_width = 0
+ self.curr_height = 0
+ self.last_width = 1
+ self.last_height = 1
+ self.need_update = False
+ self.main_image = tkinter.PhotoImage(width = 1, height = 1)
+ self.after_idle(self.on_first_display)
- def createWidgets(self):
+ def create_widgets(self):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
- #ttk.Style().configure("TLabel", padding = PADDING)
+ ttk.Style().configure("TLabel", padding = self.pad)
+
+ # canvas
+ self.frm_view = ttk.Frame(self)
+ self.frm_view.pack(side = tkinter.TOP, expand = 1, fill = tkinter.BOTH)
+ self.frm_view.grid_rowconfigure(0, weight = 1)
+ self.frm_view.grid_columnconfigure(0, weight = 1)
+ self.scr_view_x = ttk.Scrollbar(self.frm_view,
+ orient = tkinter.HORIZONTAL)
+ self.scr_view_x.grid(row = 1, column = 0, \
+ sticky = tkinter.E + tkinter.W)
+ self.scr_view_y = ttk.Scrollbar(self.frm_view)
+ self.scr_view_y.grid(row = 0, column = 1, sticky = \
+ tkinter.N + tkinter.S)
+ self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
+ scrollregion = (0, 0, 50, 50),
+ xscrollcommand = self.scr_view_x.set,
+ yscrollcommand = self.scr_view_y.set)
+ self.canv_view_w = 0
+ self.canv_view_h = 0
+ self.canv_view_fact = 1
+ self.canv_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ self.scr_view_x.config(command = self.canv_view.xview)
+ self.scr_view_y.config(command = self.canv_view.yview)
+ # don't forget
+ # canvas.config(scrollregion=(left, top, right, bottom))
+ self.canv_view.bind('<Configure>', self.on_resize_view)
+ self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
+ self.update_after()
+ self.update_gui(None)
- def createMenu(self):
+ def create_menu(self):
self.menubar = tkinter.Menu(self.master)
self.master.configure(menu = self.menubar)
self.menufile = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menufile,
- label="File")
+ label = "File")
self.menufile.add_command(
command = self.on_open_data,
- label="Open data...")
+ label = "Open data...")
self.menufile.add_separator()
self.menufile.add_command(
command = self.on_exit,
- label="Quit")
+ label = "Quit")
self.menuedit = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuedit,
- label="Edit")
+ label = "Edit")
self.menuedit.add_command(
command = self.on_select_chapter,
- label="Select chapter")
+ label = "Select chapter")
+
+ def update_after(self):
+ if not self.need_update:
+ self.after_idle(self.on_idle)
+ self.need_update = True
+
+ def on_idle(self):
+ self.need_update = False
+ self.update_canvas()
+
+ def on_first_display(self):
+ fnt = font.Font()
+ try:
+ self.pad = fnt.measure(":")
+ except:
+ self.pad = 5
+ self.create_widgets()
+ self.create_menu()
def on_exit(self):
self.master.destroy()
+ def on_mouse_view(self, event):
+ #self.currMode += 1
+ #if self.currMode > 1:
+ # self.currMode = 0
+ self.last_width = -1
+ self.last_height = -1
+ self.update_after()
+
+ def on_resize_view(self, event):
+ self.canv_view_w = event.width
+ self.canv_view_h = event.height
+ self.update_after()
+
+ def update_canvas(self):
+ # rebuild image
+ c = self.canv_view
+ c.delete(tkinter.ALL)
+
+ if self.sim is None: return
+
+ #if (self.last_width != self.curr_width) or \
+ # (self.last_height != self.curr_height):
+ # self.build_image()
+
+ # Preview image
+ #print("Update %d x %d" % (self.currWidth, self.currHeight))
+ self.canv_image = self.main_image.copy()
+ w = self.canv_view_w
+ h = self.canv_view_h
+ if (w == 0) and (h == 0):
+ return
+
+ scale = 0 #self.RadioGroupScale.get()
+ if scale == 0: # Fit
+ try:
+ psc = w / h
+ isc = self.curr_width / self.curr_height
+ if psc < isc:
+ if w > self.curr_width:
+ fact = w // self.curr_width
+ else:
+ fact = -self.curr_width // w
+ else:
+ if h > self.curr_height:
+ fact = h // self.curr_height
+ else:
+ fact = -self.curr_height // h
+ except:
+ fact = 1
+ else:
+ fact = scale
+
+ # place on canvas
+ if fact > 0:
+ pw = self.curr_width * fact
+ ph = self.curr_height * fact
+ else:
+ pw = self.curr_width // -fact
+ ph = self.curr_height // -fact
+
+ cw = max(pw, w)
+ ch = max(ph, h)
+
+ c.config(scrollregion = (0, 0, cw - 2, ch - 2))
+
+ if fact > 0:
+ self.canv_image = self.canv_image.zoom(fact)
+ else:
+ self.canv_image = self.canv_image.subsample(-fact)
+ self.canv_image_fact = fact
+ #print("Place c %d %d, p %d %d" % (cw, ch, w, h))
+ c.create_image(cw // 2, ch // 2, image = self.canv_image)
+
+ def build_image(self):
+ # rebuild main_image
+ width = self.curr_width
+ height = self.curr_height
+ self.last_width = width
+ self.last_height = height
+
+ return
+
+ def make_image(self, width, height, data):
+ # create P6
+ phdr = ("P6\n{} {}\n255\n".format(width, height))
+ rawlen = width * height * 3 # RGB
+ #phdr = ("P5\n{} {}\n255\n".format(width, height))
+ #rawlen = width * height
+ phdr = phdr.encode("UTF-8")
+
+ if len(data) > rawlen:
+ # truncate
+ pdata = data[:rawlen]
+ if len(data) < rawlen:
+ # fill gap
+ gap = bytearray()
+ data += b"\xff" * (rawlen - len(data))
+ p = bytearray(phdr)
+ # fix UTF-8 issue
+ for ch in data:
+ if ch > 0x7f:
+ p += bytes((0b11000000 |\
+ ch >> 6, 0b10000000 |\
+ (ch & 0b00111111)))
+ else:
+ p += bytes((ch,))
+ image = tkinter.PhotoImage(width = width, height = height, \
+ data = bytes(p))
+ return image
+
+ def update_gui(self, fn):
+ pass
+
def on_open_data(self):
# open data - select TODO
pass
@@ -64,6 +233,15 @@ class App(tkinter.Frame):
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
self.sim.open_part(0, 0)
+ # load static image
+ #for item in self.sim.fman.strtable:
+ # print(item)
+ bmpdata = self.sim.fman.read_file("MAIN/INTRFACE.BG/INSTHERO.BMP")
+ bmp = petka.BMPLoader()
+ bmp.load_data(bmpdata)
+ self.main_image = self.make_image(640, 480, bmp.rgb)
+ self.curr_width = 640
+ self.curr_height = 480
#self.sim.open_part(1, 0)
#self.sim.open_part(2, 0)
#self.sim.open_part(3, 0)
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index 5bcfed3b5..ecf231162 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -1,4 +1,6 @@
-# pass
-from .fman import FileManager
+class EngineError(Exception): pass
+
from .engine import Engine
+from .fman import FileManager
+from .imgbmp import BMPLoader
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index c7930e35d..10a095408 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -5,7 +5,7 @@
import os
import struct
-from . import FileManager
+from .fman import FileManager
class ScrObject:
def __init__(self, idx, name):
@@ -120,7 +120,7 @@ class Engine:
self.obj_idx = {}
self.scn_idx = {}
- data = self.fman.read_data(self.curr_path + "script.dat")
+ data = self.fman.read_file(self.curr_path + "script.dat")
num_obj, num_scn = struct.unpack_from("<II", data[:8])
off = 8
def read_rec(off):
@@ -155,7 +155,7 @@ class Engine:
self.scenes.append(scn)
self.scn_idx[scn.idx] = scn
- data = self.fman.read_data(self.curr_path + "backgrnd.bg")
+ data = self.fman.read_file(self.curr_path + "backgrnd.bg")
num_rec = struct.unpack_from("<I", data[:4])[0]
off = 4
for i in range(num_rec):
@@ -165,16 +165,16 @@ class Engine:
scn = self.scn_idx[scn_ref]
scn.refs = []
else:
- print("DEBUG: Scene ID = 0x{:x} not found".format(scn_ref))
- scn = None
+ raise EngineError("DEBUG: Scene ID = 0x{:x} not found".\
+ format(scn_ref))
+
for j in range(num_ref):
ref = struct.unpack_from("<H5I", data[off:off + 22])
off += 22
- if scn:
- if ref[0] in self.obj_idx:
- obj = self.obj_idx[ref[0]]
- scn.refs.append([obj] + list(ref[1:]))
- else:
- print("DEBUG: Object ID = 0x{:x} not found".\
- format(obj[0]))
+ if ref[0] in self.obj_idx:
+ obj = self.obj_idx[ref[0]]
+ scn.refs.append([obj] + list(ref[1:]))
+ else:
+ raise EngineError("DEBUG: Object ID = 0x{:x} not found".\
+ format(obj[0]))
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index 0a59ca398..400cf1a78 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -5,6 +5,8 @@
import os
import struct
+from . import EngineError
+
# manage files data
class FileManager:
def __init__(self, root):
@@ -41,7 +43,7 @@ class FileManager:
# check magic string "StOR"
magic = f.read(4)
if magic != b"StOR":
- print("DEBUG: Bad magic in \"{}\"".format(name))
+ raise EngineError("Bad magic in store \"{}\"".format(name))
return
# read index table ref
temp = f.read(4)
@@ -55,20 +57,29 @@ class FileManager:
temp = f.read(12)
data = struct.unpack_from("<III", temp)
index_table.append((data[1], data[2]))
- data = f.read().decode("ascii")
+ data = f.read().decode("latin-1")
for idx, fname in enumerate(data.split("\x00")):
- if idx < index_len and fname.lower() not in self.strtable:
- self.strtable[fname.lower()] = (len(self.strfd),) + index_table[idx]
+ fname = fname.lower().replace("\\", "/")
+ if idx < index_len and fname not in self.strtable:
+ self.strtable[fname] = (len(self.strfd),) + \
+ index_table[idx]
+ else:
+ if len(fname) > 0:
+ raise EngineError("Extra file record \"{}\" in \"{}\"".\
+ format(fname, name))
# add file descriptor
self.strfd.append((f, name, tag))
- def read_data(self, fname):
- sf = fname.lower()
+ def read_file(self, fname):
+ sf = fname.lower().replace("\\", "/")
if sf in self.strtable:
fnum, st, ln = self.strtable[sf]
+ print("Load file \"{}\" from store \"{}\"".\
+ format(fname, self.strfd[fnum][1]))
self.strfd[fnum][0].seek(st)
return self.strfd[fnum][0].read(ln)
else:
+ print("Load file \"{}\" from filesystem".format(fname))
pf = self.find_path(fname)
if not pf:
print("DEBUG: Can't open file \"{}\"".format(fname))
@@ -82,9 +93,10 @@ class FileManager:
def unload_stores(self, flt = None):
- for fd, name, tag in self.strfd:
+ for idx, (fd, name, tag) in enumerate(self.strfd):
if flt is not None:
if tag != flt: continue
+ print("DEBIG: Unload store \"{}\"".format(name))
try:
if fd: fd.close()
except Exception as e:
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
new file mode 100644
index 000000000..4c5b36296
--- /dev/null
+++ b/engines/petka/petka/imgbmp.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import array, struct
+
+from . import EngineError
+
+class BMPLoader:
+ def __init__(self):
+ self.raw = None
+
+ def load_data(self, data):
+ # TODO: normal BMP, rle BMP
+ # check magic string "BM"
+ if data[:2] != b"BM":
+ raise EngineError("Bad magic string")
+ off = 2
+
+ f_sz, res1, res2, data_offset = struct.unpack_from("<IHHI", \
+ data[off:off + 12])
+ off += 12
+
+ # read next 40 bytes, BITMAPINFOHEADER
+ pict = struct.unpack_from("<IiiHHIIiiII", data[off:off + 40])
+ off += 40
+ if pict[0] != 40:
+ raise EngineError("Unsupported InfoHeader")
+ pictw = pict[1]
+ picth = pict[2]
+
+ # read data_offset - 40 - 6 bytes
+ delta = data_offset - 40 - 6
+ if delta < 0:
+ raise EngineError("To small bitmap data offset")
+ if delta != 8:
+ raise EngineError("Unsupported Header at 0x36")
+ hdr36 = struct.unpack_from("<II", data[off:off + delta])
+ off += delta
+
+ bsz = pictw * picth * 2
+ picture_data = data[off:off + bsz]
+ off += bsz
+ if len(picture_data) != bsz:
+ raise EngineError("Bitmap truncated, need {}, got {}".format(bsz, \
+ len(picture_data)))
+
+ # read 2 zero bytes
+ if data[off:off + 2] != b"\x00\x00":
+ raise EngineError("Magic zero bytes absent [{:02x},{:02x}]".\
+ format(data[off], data[off + 1]))
+ off += 2
+
+ if len(data) - off > 0:
+ raise EngineError("BMP read error, some data unparsed")
+
+ # convert 16 bit to 24
+ b16arr = array.array("H") # unsigned short
+ b16arr.frombytes(picture_data)
+ rgb = array.array("B")
+ for b16 in b16arr:
+ rgb.append((b16 >> 5) & 0b11111000)
+ rgb.append((b16 << 5) & 0b11100000 | (b16 >> 11) & 0b00011100)
+ rgb.append((b16 << 0) &0b11111000)
+ # Y-mirror
+ self.rgb = array.array("B")
+ for i in range(picth):
+ off = (picth - i - 1) * pictw * 3
+ self.rgb += rgb[off:off + pictw * 3]
+
Commit: 37c26c9520b773b0d8c882ee5760e5344d8baa74
https://github.com/scummvm/scummvm-tools/commit/37c26c9520b773b0d8c882ee5760e5344d8baa74
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Resource list
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 4fa371dd8..f3aee0468 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -26,6 +26,7 @@ class App(tkinter.Frame):
self.last_width = 1
self.last_height = 1
self.need_update = False
+ self.curr_gui = []
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
self.after_idle(self.on_first_display)
@@ -33,6 +34,10 @@ class App(tkinter.Frame):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
+
+ # leftpanel
+ self.frm_left = ttk.Frame(self)
+ self.frm_left.pack(side = tkinter.LEFT, expand = 0, fill = tkinter.BOTH)
# canvas
self.frm_view = ttk.Frame(self)
@@ -219,7 +224,17 @@ class App(tkinter.Frame):
return image
def update_gui(self, fn):
- pass
+ # TODO: remove unused gui items
+
+ if self.curr_mode == 100:
+ # list resources
+ lst = tkinter.Listbox(self.frm_left)
+ lst.pack(expand = 1, fill = tkinter.BOTH)
+ self.curr_gui.append(lst)
+ # fill
+ for res_id in self.sim.resord:
+ lst.insert(tkinter.END, "{} [{}]".format(self.sim.res[res_id],
+ res_id))
def on_open_data(self):
# open data - select TODO
@@ -236,12 +251,13 @@ class App(tkinter.Frame):
# load static image
#for item in self.sim.fman.strtable:
# print(item)
- bmpdata = self.sim.fman.read_file("MAIN/INTRFACE.BG/INSTHERO.BMP")
- bmp = petka.BMPLoader()
- bmp.load_data(bmpdata)
- self.main_image = self.make_image(640, 480, bmp.rgb)
- self.curr_width = 640
- self.curr_height = 480
+ #bmpdata = self.sim.fman.read_file("MAIN/INTRFACE.BG/INSTHERO.BMP")
+ #bmp = petka.BMPLoader()
+ #bmp.load_data(bmpdata)
+ #self.main_image = self.make_image(640, 480, bmp.rgb)
+ #self.curr_width = 640
+ #self.curr_height = 480
+ self.curr_mode = 100
#self.sim.open_part(1, 0)
#self.sim.open_part(2, 0)
#self.sim.open_part(3, 0)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 10a095408..5dc459d8a 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -4,6 +4,7 @@
import os
import struct
+import io
from .fman import FileManager
@@ -45,6 +46,24 @@ class Engine:
ini[curr_sect][kv[0].strip()] = kv[1].strip()
return ini
+ def parse_res(self, f):
+ res = {}
+ resord = []
+ for line in f.readlines():
+ line = line.decode(self.enc).strip()
+ if len(line) == 0:
+ continue
+ pair = line.split("=", 1)
+ if len(pair) < 2:
+ continue
+ value = pair[1].strip()
+ if value[:1] == "=":
+ value = value[1:].strip()
+ res_id = int(pair[0].strip(), 10)
+ res[res_id] = value
+ resord.append(res_id)
+ return res, resord
+
def load_data(self, folder, enc):
self.fman = FileManager(folder)
self.enc = enc
@@ -177,4 +196,12 @@ class Engine:
else:
raise EngineError("DEBUG: Object ID = 0x{:x} not found".\
format(obj[0]))
+
+ data = self.fman.read_file(self.curr_path + "resource.qrc")
+ mems = io.BytesIO()
+ mems.write(data)
+ mems.seek(0)
+ self.res, self.resord = self.parse_res(mems)
+
+
Commit: 7d64e0d2b5148b2dfd7c0b6869d8718d1b075a13
https://github.com/scummvm/scummvm-tools/commit/7d64e0d2b5148b2dfd7c0b6869d8718d1b075a13
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Select part, select resource
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index f3aee0468..f20876482 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -16,8 +16,6 @@ class App(tkinter.Frame):
tkinter.Frame.__init__(self, master)
master.title(APPNAME)
self.pack(fill = tkinter.BOTH, expand = 1)
- #self.createWidgets()
- #self.createMenu()
self.pad = None
self.sim = None
self.curr_mode = 0
@@ -26,6 +24,9 @@ class App(tkinter.Frame):
self.last_width = 1
self.last_height = 1
self.need_update = False
+ self.canv_view_w = 0
+ self.canv_view_h = 0
+ self.canv_view_fact = 1
self.curr_gui = []
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
self.after_idle(self.on_first_display)
@@ -35,13 +36,17 @@ class App(tkinter.Frame):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
+ # main paned
+ self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
+ self.pan_main.pack(fill = tkinter.BOTH, expand = 1)
+
# leftpanel
- self.frm_left = ttk.Frame(self)
- self.frm_left.pack(side = tkinter.LEFT, expand = 0, fill = tkinter.BOTH)
+ self.frm_left = ttk.Frame(self.pan_main)
+ self.pan_main.add(self.frm_left)
# canvas
- self.frm_view = ttk.Frame(self)
- self.frm_view.pack(side = tkinter.TOP, expand = 1, fill = tkinter.BOTH)
+ self.frm_view = ttk.Frame(self.pan_main)
+ self.pan_main.add(self.frm_view)
self.frm_view.grid_rowconfigure(0, weight = 1)
self.frm_view.grid_columnconfigure(0, weight = 1)
self.scr_view_x = ttk.Scrollbar(self.frm_view,
@@ -55,9 +60,6 @@ class App(tkinter.Frame):
scrollregion = (0, 0, 50, 50),
xscrollcommand = self.scr_view_x.set,
yscrollcommand = self.scr_view_y.set)
- self.canv_view_w = 0
- self.canv_view_h = 0
- self.canv_view_fact = 1
self.canv_view.grid(row = 0, column = 0, \
sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
self.scr_view_x.config(command = self.canv_view.xview)
@@ -68,7 +70,7 @@ class App(tkinter.Frame):
self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
self.update_after()
- self.update_gui(None)
+ self.update_gui()
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -89,8 +91,12 @@ class App(tkinter.Frame):
self.menubar.add_cascade(menu = self.menuedit,
label = "Edit")
self.menuedit.add_command(
- command = self.on_select_chapter,
- label = "Select chapter")
+ command = self.on_list_parts,
+ label = "Select part")
+ self.menuedit.add_separator()
+ self.menuedit.add_command(
+ command = self.on_list_res,
+ label = "Resources")
def update_after(self):
if not self.need_update:
@@ -223,41 +229,106 @@ class App(tkinter.Frame):
data = bytes(p))
return image
- def update_gui(self, fn):
+ def update_gui_add_left_listbox(self, text):
+ lab = tkinter.Label(self.frm_left, text = text)
+ lab.pack()
+
+ frm_lb = ttk.Frame(self.frm_left)
+ frm_lb.pack(fill = tkinter.BOTH, expand = 1)
+ frm_lb.grid_rowconfigure(0, weight = 1)
+ frm_lb.grid_columnconfigure(0, weight = 1)
+ scr_lb_x = ttk.Scrollbar(frm_lb, orient = tkinter.HORIZONTAL)
+ scr_lb_x.grid(row = 1, column = 0, sticky = tkinter.E + tkinter.W)
+ scr_lb_y = ttk.Scrollbar(frm_lb)
+ scr_lb_y.grid(row = 0, column = 1, sticky = tkinter.N + tkinter.S)
+ lb = tkinter.Listbox(frm_lb,
+ xscrollcommand = scr_lb_x.set,
+ yscrollcommand = scr_lb_y.set)
+ lb.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ scr_lb_x.config(command = lb.xview)
+ scr_lb_y.config(command = lb.yview)
+ self.curr_gui.append(lambda:lb.grid_remove())
+ self.curr_gui.append(lambda:lab.pack_forget())
+ self.curr_gui.append(lambda:frm_lb.pack_forget())
+ lb.bind("<Double-Button-1>", self.on_left_listbox)
+ lb.bind("<Return>", self.on_left_listbox)
+ return lb
+
+ def update_gui(self):
# TODO: remove unused gui items
+ for item in self.curr_gui:
+ item()
- if self.curr_mode == 100:
+ if self.curr_mode == 90:
+ # list parts
+ lb = self.update_gui_add_left_listbox("Parts")
+ for part in self.sim.parts:
+ lb.insert(tkinter.END, part)
+ self.curr_lb = lb
+ elif self.curr_mode == 100:
# list resources
- lst = tkinter.Listbox(self.frm_left)
- lst.pack(expand = 1, fill = tkinter.BOTH)
- self.curr_gui.append(lst)
- # fill
+ lb = self.update_gui_add_left_listbox("Resources")
for res_id in self.sim.resord:
- lst.insert(tkinter.END, "{} [{}]".format(self.sim.res[res_id],
- res_id))
+ lb.insert(tkinter.END, "{} - {}".format(res_id, \
+ self.sim.res[res_id]))
+ self.curr_lb = lb
+
+ def on_left_listbox(self, event):
+ if self.curr_mode == 90:
+ # parts
+ try:
+ part_id = self.curr_lb.curselection()[0]
+ part_id = int(part_id)
+ except:
+ pass
+ part_id = self.sim.parts[part_id]
+ # parse
+ pnum = part_id[5:]
+ cnum = pnum.split("Chapter", 1)
+ if len(cnum) > 1:
+ pnum = int(cnum[0].strip(), 10)
+ cnum = int(cnum[0].strip(), 10)
+ else:
+ cnum = 0
+ self.sim.open_part(pnum, cnum)
+ self.update_after()
+ elif self.curr_mode == 100:
+ # resources
+ try:
+ res_id = self.curr_lb.curselection()[0]
+ res_id = int(res_id)
+ except:
+ pass
+ res_id = self.sim.resord[res_id]
+ fn = self.sim.res[res_id]
+ if fn[-4:].lower() == ".bmp":
+ bmpdata = self.sim.fman.read_file(fn)
+ bmp = petka.BMPLoader()
+ bmp.load_data(bmpdata)
+ self.main_image = self.make_image(bmp.width, bmp.height, bmp.rgb)
+ self.curr_width = bmp.width
+ self.curr_height = bmp.height
+ self.update_after()
+ print(fn)
def on_open_data(self):
# open data - select TODO
pass
- def on_select_chapter(self):
- # TODO
- pass
+ def on_list_parts(self):
+ self.curr_mode = 90
+ self.update_gui()
+
+ def on_list_res(self):
+ self.curr_mode = 100
+ self.update_gui()
def open_data_from(self, folder):
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
self.sim.open_part(0, 0)
- # load static image
- #for item in self.sim.fman.strtable:
- # print(item)
- #bmpdata = self.sim.fman.read_file("MAIN/INTRFACE.BG/INSTHERO.BMP")
- #bmp = petka.BMPLoader()
- #bmp.load_data(bmpdata)
- #self.main_image = self.make_image(640, 480, bmp.rgb)
- #self.curr_width = 640
- #self.curr_height = 480
- self.curr_mode = 100
+ self.curr_mode = 90
#self.sim.open_part(1, 0)
#self.sim.open_part(2, 0)
#self.sim.open_part(3, 0)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 5dc459d8a..48955e95b 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -33,6 +33,7 @@ class Engine:
# parse ini settings
curr_sect = None
ini = {}
+ ordersect = []
for line in f.readlines():
line = line.decode(self.enc).strip()
if len(line) == 0: continue
@@ -40,10 +41,12 @@ class Engine:
if line[:1] == "[" and line[-1:] == "]":
curr_sect = line[1:-1].strip()
ini[curr_sect] = {}
+ ordersect.append(curr_sect)
continue
kv = line.split("=", 1)
if len(kv) != 2: continue
ini[curr_sect][kv[0].strip()] = kv[1].strip()
+ ini["__order__"] = ordersect
return ini
def parse_res(self, f):
@@ -75,14 +78,15 @@ class Engine:
self.parts_ini = self.parse_ini(f)
finally:
f.close()
- for sect, data in self.parts_ini.items():
+ for sect in self.parts_ini["__order__"]:
+ data = self.parts_ini[sect]
if sect == "All":
if "Part" in data:
self.start_part = int(data["Part"]) - 1
if "Chapter" in data:
self.start_chap = int(data["Chapter"]) - 1
elif sect[:5] == "Part ":
- self.parts.append(data)
+ self.parts.append(sect)
else:
# load BGS.INI only (e.g. DEMO)
self.parts_ini = None
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 4c5b36296..8cfb95aca 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -9,6 +9,8 @@ from . import EngineError
class BMPLoader:
def __init__(self):
self.raw = None
+ self.width = 0
+ self.height = 0
def load_data(self, data):
# TODO: normal BMP, rle BMP
@@ -27,7 +29,9 @@ class BMPLoader:
if pict[0] != 40:
raise EngineError("Unsupported InfoHeader")
pictw = pict[1]
+ self.width = pictw
picth = pict[2]
+ self.height = picth
# read data_offset - 40 - 6 bytes
delta = data_offset - 40 - 6
Commit: 9405a96b3a4a7fd21ae2550663a34ed58913b1ca
https://github.com/scummvm/scummvm-tools/commit/9405a96b3a4a7fd21ae2550663a34ed58913b1ca
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Fix unloading stores
Changed paths:
engines/petka/petka/fman.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index 400cf1a78..f61d5ed7c 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -93,12 +93,21 @@ class FileManager:
def unload_stores(self, flt = None):
+ strfd = []
+ strtable = {}
for idx, (fd, name, tag) in enumerate(self.strfd):
if flt is not None:
- if tag != flt: continue
- print("DEBIG: Unload store \"{}\"".format(name))
+ if tag != flt:
+ for k, v in self.strtable:
+ if v == idx:
+ strtable[k] = len(strfd)
+ strfd.append((fd, name, tag))
+ continue
+ print("DEBUG: Unload store \"{}\"".format(name))
try:
if fd: fd.close()
except Exception as e:
print("DEBUG: Can't unload \"{}\":".format(name) + str(e))
-
+ self.strff = strfd
+ self.strtable = strtable
+
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 8cfb95aca..eaf849fc3 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -51,8 +51,7 @@ class BMPLoader:
# read 2 zero bytes
if data[off:off + 2] != b"\x00\x00":
- raise EngineError("Magic zero bytes absent [{:02x},{:02x}]".\
- format(data[off], data[off + 1]))
+ raise EngineError("Magic zero bytes absent or mismatch")
off += 2
if len(data) - off > 0:
Commit: b2342c929b27c0add6dbc4d1ddf2a1a15a47c651
https://github.com/scummvm/scummvm-tools/commit/b2342c929b27c0add6dbc4d1ddf2a1a15a47c651
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Switchable canvas and frame
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index f20876482..60c04df9e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -18,7 +18,12 @@ class App(tkinter.Frame):
self.pack(fill = tkinter.BOTH, expand = 1)
self.pad = None
self.sim = None
- self.curr_mode = 0
+ # gui
+ self.curr_mode = 0
+ self.curr_gui = []
+ self.curr_main = 0 # 0 - frame, 1 - canvas
+ self.last_main = -1
+ # canvas
self.curr_width = 0
self.curr_height = 0
self.last_width = 1
@@ -27,7 +32,6 @@ class App(tkinter.Frame):
self.canv_view_w = 0
self.canv_view_h = 0
self.canv_view_fact = 1
- self.curr_gui = []
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
self.after_idle(self.on_first_display)
@@ -60,14 +64,14 @@ class App(tkinter.Frame):
scrollregion = (0, 0, 50, 50),
xscrollcommand = self.scr_view_x.set,
yscrollcommand = self.scr_view_y.set)
- self.canv_view.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
self.scr_view_x.config(command = self.canv_view.xview)
self.scr_view_y.config(command = self.canv_view.yview)
# don't forget
# canvas.config(scrollregion=(left, top, right, bottom))
self.canv_view.bind('<Configure>', self.on_resize_view)
self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
+ # info panel
+ self.frm_info = ttk.Frame(self.frm_view)
self.update_after()
self.update_gui()
@@ -134,15 +138,12 @@ class App(tkinter.Frame):
def update_canvas(self):
# rebuild image
+ if self.curr_main != 1:
+ return
c = self.canv_view
c.delete(tkinter.ALL)
-
if self.sim is None: return
-
- #if (self.last_width != self.curr_width) or \
- # (self.last_height != self.curr_height):
- # self.build_image()
-
+
# Preview image
#print("Update %d x %d" % (self.currWidth, self.currHeight))
self.canv_image = self.main_image.copy()
@@ -256,7 +257,21 @@ class App(tkinter.Frame):
return lb
def update_gui(self):
- # TODO: remove unused gui items
+ if self.last_main != self.curr_main:
+ if self.last_main == 0:
+ self.frm_info.grid_forget()
+ elif self.curr_main == 1:
+ self.canv_view.grid_forget()
+ self.last_main = self.curr_main
+ if self.curr_main == 0:
+ self.frm_info.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ pass
+ elif self.curr_main == 1:
+ self.canv_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+
+
for item in self.curr_gui:
item()
@@ -266,6 +281,11 @@ class App(tkinter.Frame):
for part in self.sim.parts:
lb.insert(tkinter.END, part)
self.curr_lb = lb
+
+ lab = ttk.Label(self.frm_info, text = "Select parts")
+ lab.pack()
+
+
elif self.curr_mode == 100:
# list resources
lb = self.update_gui_add_left_listbox("Resources")
@@ -318,10 +338,12 @@ class App(tkinter.Frame):
def on_list_parts(self):
self.curr_mode = 90
+ self.curr_main = 0
self.update_gui()
def on_list_res(self):
self.curr_mode = 100
+ self.curr_main = 1
self.update_gui()
def open_data_from(self, folder):
Commit: acea4a19eb16db4977547cbbe42843504aa414da
https://github.com/scummvm/scummvm-tools/commit/acea4a19eb16db4977547cbbe42843504aa414da
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Siwtchable interface works, outline mode
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 60c04df9e..683682846 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -23,14 +23,11 @@ class App(tkinter.Frame):
self.curr_gui = []
self.curr_main = 0 # 0 - frame, 1 - canvas
self.last_main = -1
+ self.curr_lb_acts = None
# canvas
self.curr_width = 0
self.curr_height = 0
- self.last_width = 1
- self.last_height = 1
self.need_update = False
- self.canv_view_w = 0
- self.canv_view_h = 0
self.canv_view_fact = 1
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
self.after_idle(self.on_first_display)
@@ -64,15 +61,15 @@ class App(tkinter.Frame):
scrollregion = (0, 0, 50, 50),
xscrollcommand = self.scr_view_x.set,
yscrollcommand = self.scr_view_y.set)
+ self.canv_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
self.scr_view_x.config(command = self.canv_view.xview)
self.scr_view_y.config(command = self.canv_view.yview)
# don't forget
# canvas.config(scrollregion=(left, top, right, bottom))
self.canv_view.bind('<Configure>', self.on_resize_view)
self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
- # info panel
- self.frm_info = ttk.Frame(self.frm_view)
-
+
self.update_after()
self.update_gui()
@@ -94,6 +91,10 @@ class App(tkinter.Frame):
self.menuedit = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuedit,
label = "Edit")
+ self.menuedit.add_command(
+ command = self.on_outline,
+ label = "Outline")
+ self.menuedit.add_separator()
self.menuedit.add_command(
command = self.on_list_parts,
label = "Select part")
@@ -127,29 +128,39 @@ class App(tkinter.Frame):
#self.currMode += 1
#if self.currMode > 1:
# self.currMode = 0
- self.last_width = -1
- self.last_height = -1
self.update_after()
def on_resize_view(self, event):
- self.canv_view_w = event.width
- self.canv_view_h = event.height
+ if self.curr_main != 1:
+ w = self.frm_info.winfo_reqwidth()
+ h = self.frm_info.winfo_reqheight()
+ if w != self.canv_view.winfo_width() or \
+ h != self.canv_view.winfo_height():
+ self.canv_view.itemconfigure(self.frm_info_id,
+ width = w, height = h)
+ return
self.update_after()
+ def on_resize_info(self, event):
+ w = self.frm_info.winfo_reqwidth()
+ h = self.frm_info.winfo_reqheight()
+ self.canv_view.config(scrollregion = (0, 0, w, h))
+ if w != self.canv_view.winfo_width() or \
+ h != self.canv_view.winfo_height():
+ self.canv_view.config(width = w, height = h)
+
def update_canvas(self):
- # rebuild image
- if self.curr_main != 1:
+ if self.curr_main != 1:
return
+ # draw grahics
c = self.canv_view
c.delete(tkinter.ALL)
if self.sim is None: return
-
# Preview image
- #print("Update %d x %d" % (self.currWidth, self.currHeight))
self.canv_image = self.main_image.copy()
- w = self.canv_view_w
- h = self.canv_view_h
- if (w == 0) and (h == 0):
+ w = self.canv_view.winfo_width()
+ h = self.canv_view.winfo_height()
+ if (w == 0) or (h == 0):
return
scale = 0 #self.RadioGroupScale.get()
@@ -182,7 +193,6 @@ class App(tkinter.Frame):
cw = max(pw, w)
ch = max(ph, h)
-
c.config(scrollregion = (0, 0, cw - 2, ch - 2))
if fact > 0:
@@ -192,16 +202,7 @@ class App(tkinter.Frame):
self.canv_image_fact = fact
#print("Place c %d %d, p %d %d" % (cw, ch, w, h))
c.create_image(cw // 2, ch // 2, image = self.canv_image)
-
- def build_image(self):
- # rebuild main_image
- width = self.curr_width
- height = self.curr_height
- self.last_width = width
- self.last_height = height
-
- return
-
+
def make_image(self, width, height, data):
# create P6
phdr = ("P6\n{} {}\n255\n".format(width, height))
@@ -230,7 +231,7 @@ class App(tkinter.Frame):
data = bytes(p))
return image
- def update_gui_add_left_listbox(self, text):
+ def update_gui_add_left_listbox(self, text, acts = None):
lab = tkinter.Label(self.frm_left, text = text)
lab.pack()
@@ -254,28 +255,52 @@ class App(tkinter.Frame):
self.curr_gui.append(lambda:frm_lb.pack_forget())
lb.bind("<Double-Button-1>", self.on_left_listbox)
lb.bind("<Return>", self.on_left_listbox)
+
+ self.curr_lb_acts = acts
+ if acts:
+ for name, cb in acts:
+ lb.insert(tkinter.END, name)
+ self.curr_lb = lb
return lb
def update_gui(self):
if self.last_main != self.curr_main:
- if self.last_main == 0:
- self.frm_info.grid_forget()
- elif self.curr_main == 1:
- self.canv_view.grid_forget()
self.last_main = self.curr_main
+ self.canv_view.delete(tkinter.ALL)
if self.curr_main == 0:
- self.frm_info.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
- pass
- elif self.curr_main == 1:
- self.canv_view.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
-
+ # info panel
+ self.frm_info = ttk.Frame(self.canv_view)
+ self.frm_info_id = self.canv_view.create_window(0, 0,
+ window = self.frm_info, anchor = tkinter.NW)
+ self.frm_info.bind('<Configure>', self.on_resize_info)
+ self.update_canvas()
for item in self.curr_gui:
item()
+
+ if self.curr_mode == 0:
+ if self.sim is None:
+ # open some data
+ acts = [
+ ("Open data", self.on_open_data)
+ ]
+ lb = self.update_gui_add_left_listbox("Outline", acts)
+ lab = ttk.Label(self.frm_info, \
+ text = "Open data")
+ lab.pack()
+ self.curr_gui.append(lambda:lab.pack_forget())
+ else:
+ acts = [
+ ("Parts", self.on_list_parts),
+ ("Resources", self.on_list_res),
+ ]
+ lb = self.update_gui_add_left_listbox("Outline", acts)
+ lab = ttk.Label(self.frm_info, \
+ text = "Select data type from outline")
+ lab.pack()
+ self.curr_gui.append(lambda:lab.pack_forget())
- if self.curr_mode == 90:
+ elif self.curr_mode == 90:
# list parts
lb = self.update_gui_add_left_listbox("Parts")
for part in self.sim.parts:
@@ -284,8 +309,8 @@ class App(tkinter.Frame):
lab = ttk.Label(self.frm_info, text = "Select parts")
lab.pack()
-
-
+ self.curr_gui.append(lambda:lab.pack_forget())
+
elif self.curr_mode == 100:
# list resources
lb = self.update_gui_add_left_listbox("Resources")
@@ -295,7 +320,16 @@ class App(tkinter.Frame):
self.curr_lb = lb
def on_left_listbox(self, event):
- if self.curr_mode == 90:
+ if self.curr_lb_acts:
+ try:
+ num = self.curr_lb.curselection()[0]
+ num = int(num)
+ except:
+ pass
+ act = self.curr_lb_acts[num]
+ if act[1]:
+ act[1]()
+ elif self.curr_mode == 90:
# parts
try:
part_id = self.curr_lb.curselection()[0]
@@ -336,6 +370,11 @@ class App(tkinter.Frame):
# open data - select TODO
pass
+ def on_outline(self):
+ self.curr_mode = 0
+ self.curr_main = 0
+ self.update_gui()
+
def on_list_parts(self):
self.curr_mode = 90
self.curr_main = 0
@@ -350,10 +389,6 @@ class App(tkinter.Frame):
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
self.sim.open_part(0, 0)
- self.curr_mode = 90
- #self.sim.open_part(1, 0)
- #self.sim.open_part(2, 0)
- #self.sim.open_part(3, 0)
def main():
root = tkinter.Tk()
@@ -363,15 +398,8 @@ def main():
else:
fn = "."
app.open_data_from(fn)
-
app.mainloop()
- #fman = petka.FileManager(".")
- #fman.load_store("patch.str")
- #fman.load_store("main.str")
- #for k, v in fman.strtable.items():
- # print(k, "=", v)
- # cleanup
- #fman.unload_stores()
+
if __name__ == "__main__":
main()
Commit: cdb9edbb3632b6cfcc9dabd2ff701d4b1bdfd688
https://github.com/scummvm/scummvm-tools/commit/cdb9edbb3632b6cfcc9dabd2ff701d4b1bdfd688
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Info panel fixes (not yet finished)
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 683682846..55f391013 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -102,6 +102,12 @@ class App(tkinter.Frame):
self.menuedit.add_command(
command = self.on_list_res,
label = "Resources")
+ self.menuedit.add_command(
+ command = self.on_list_objs,
+ label = "Objects")
+ self.menuedit.add_command(
+ command = self.on_list_scenes,
+ label = "Scenes")
def update_after(self):
if not self.need_update:
@@ -290,22 +296,46 @@ class App(tkinter.Frame):
lab.pack()
self.curr_gui.append(lambda:lab.pack_forget())
else:
+ def tst_img():
+ self.curr_main = 1
+ self.main_image = tkinter.PhotoImage(\
+ file = "img/splash.gif")
+ self.curr_width = self.main_image.width()
+ self.curr_height = self.main_image.height()
+ self.update_gui()
+ def tst_info():
+ self.curr_mode = 99
+ self.curr_main = 0
+ self.update_gui()
acts = [
("Parts", self.on_list_parts),
("Resources", self.on_list_res),
+ ("Objects", self.on_list_objs),
+ ("Scenes", self.on_list_scenes),
+ ("-", None),
+ ("Test image", tst_img),
+ ("Test info", tst_info),
]
lb = self.update_gui_add_left_listbox("Outline", acts)
lab = ttk.Label(self.frm_info, \
text = "Select data type from outline")
lab.pack()
self.curr_gui.append(lambda:lab.pack_forget())
-
+ elif self.curr_mode == 99:
+ acts = [
+ ("<- Back", self.on_outline)
+
+ ]
+ lb = self.update_gui_add_left_listbox("Test info", acts)
+ lab = ttk.Label(self.frm_info, \
+ text = "Text placed into looooooooooong string")
+ lab.pack()
+ self.curr_gui.append(lambda:lab.pack_forget())
elif self.curr_mode == 90:
# list parts
lb = self.update_gui_add_left_listbox("Parts")
for part in self.sim.parts:
lb.insert(tkinter.END, part)
- self.curr_lb = lb
lab = ttk.Label(self.frm_info, text = "Select parts")
lab.pack()
@@ -317,7 +347,16 @@ class App(tkinter.Frame):
for res_id in self.sim.resord:
lb.insert(tkinter.END, "{} - {}".format(res_id, \
self.sim.res[res_id]))
- self.curr_lb = lb
+ elif self.curr_mode == 101:
+ # list objects
+ lb = self.update_gui_add_left_listbox("Objects")
+ for obj in self.sim.objects:
+ lb.insert(tkinter.END, "{} - {}".format(obj.idx, obj.name))
+ elif self.curr_mode == 102:
+ # list scenes
+ lb = self.update_gui_add_left_listbox("Scenes")
+ for scn in self.sim.scenes:
+ lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
def on_left_listbox(self, event):
if self.curr_lb_acts:
@@ -384,6 +423,16 @@ class App(tkinter.Frame):
self.curr_mode = 100
self.curr_main = 1
self.update_gui()
+
+ def on_list_objs(self):
+ self.curr_mode = 101
+ self.curr_main = 0
+ self.update_gui()
+
+ def on_list_scenes(self):
+ self.curr_mode = 102
+ self.curr_main = 0
+ self.update_gui()
def open_data_from(self, folder):
self.sim = petka.Engine()
Commit: 42806a53667fef6b0c4d47cc47d3dcfe3e7a2d0d
https://github.com/scummvm/scummvm-tools/commit/42806a53667fef6b0c4d47cc47d3dcfe3e7a2d0d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Switchable interface works
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 55f391013..b5ff3553a 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -22,7 +22,6 @@ class App(tkinter.Frame):
self.curr_mode = 0
self.curr_gui = []
self.curr_main = 0 # 0 - frame, 1 - canvas
- self.last_main = -1
self.curr_lb_acts = None
# canvas
self.curr_width = 0
@@ -36,6 +35,7 @@ class App(tkinter.Frame):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
+ ttk.Style().configure('Info.TFrame', background = 'white')
# main paned
self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
@@ -58,6 +58,7 @@ class App(tkinter.Frame):
self.scr_view_y.grid(row = 0, column = 1, sticky = \
tkinter.N + tkinter.S)
self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
+ bd = 0, highlightthickness = 0, bg = "white",
scrollregion = (0, 0, 50, 50),
xscrollcommand = self.scr_view_x.set,
yscrollcommand = self.scr_view_y.set)
@@ -137,14 +138,13 @@ class App(tkinter.Frame):
self.update_after()
def on_resize_view(self, event):
- if self.curr_main != 1:
+ if self.curr_main == 0:
w = self.frm_info.winfo_reqwidth()
h = self.frm_info.winfo_reqheight()
if w != self.canv_view.winfo_width() or \
h != self.canv_view.winfo_height():
self.canv_view.itemconfigure(self.frm_info_id,
width = w, height = h)
- return
self.update_after()
def on_resize_info(self, event):
@@ -154,9 +154,10 @@ class App(tkinter.Frame):
if w != self.canv_view.winfo_width() or \
h != self.canv_view.winfo_height():
self.canv_view.config(width = w, height = h)
+ self.update_after()
def update_canvas(self):
- if self.curr_main != 1:
+ if self.curr_main == 0:
return
# draw grahics
c = self.canv_view
@@ -268,21 +269,27 @@ class App(tkinter.Frame):
lb.insert(tkinter.END, name)
self.curr_lb = lb
return lb
+
+ def update_gui_add_label(self, text):
+ lab = ttk.Label(self.frm_info, text = text)
+ lab.pack()
+ self.curr_gui.append(lambda:lab.pack_forget())
def update_gui(self):
- if self.last_main != self.curr_main:
- self.last_main = self.curr_main
- self.canv_view.delete(tkinter.ALL)
- if self.curr_main == 0:
- # info panel
- self.frm_info = ttk.Frame(self.canv_view)
- self.frm_info_id = self.canv_view.create_window(0, 0,
- window = self.frm_info, anchor = tkinter.NW)
- self.frm_info.bind('<Configure>', self.on_resize_info)
- self.update_canvas()
+ self.canv_view.delete(tkinter.ALL)
+ if self.curr_main == 0:
+ # info panel
+ self.frm_info = ttk.Frame(self.canv_view)
+ self.frm_info_id = self.canv_view.create_window(0, 0,
+ window = self.frm_info, anchor = tkinter.NW)
+ self.frm_info.bind('<Configure>', self.on_resize_info)
+
+ self.canv_view.xview_moveto(0)
+ self.canv_view.yview_moveto(0)
for item in self.curr_gui:
item()
+ self.curr_gui = []
if self.curr_mode == 0:
if self.sim is None:
@@ -290,11 +297,8 @@ class App(tkinter.Frame):
acts = [
("Open data", self.on_open_data)
]
- lb = self.update_gui_add_left_listbox("Outline", acts)
- lab = ttk.Label(self.frm_info, \
- text = "Open data")
- lab.pack()
- self.curr_gui.append(lambda:lab.pack_forget())
+ self.update_gui_add_left_listbox("Outline", acts)
+ self.update_gui_add_label("Open data")
else:
def tst_img():
self.curr_main = 1
@@ -316,31 +320,20 @@ class App(tkinter.Frame):
("Test image", tst_img),
("Test info", tst_info),
]
- lb = self.update_gui_add_left_listbox("Outline", acts)
- lab = ttk.Label(self.frm_info, \
- text = "Select data type from outline")
- lab.pack()
- self.curr_gui.append(lambda:lab.pack_forget())
+ self.update_gui_add_left_listbox("Outline", acts)
+ self.update_gui_add_label("Select data type from outline")
elif self.curr_mode == 99:
acts = [
("<- Back", self.on_outline)
-
]
- lb = self.update_gui_add_left_listbox("Test info", acts)
- lab = ttk.Label(self.frm_info, \
- text = "Text placed into looooooooooong string")
- lab.pack()
- self.curr_gui.append(lambda:lab.pack_forget())
+ self.update_gui_add_left_listbox("Test info", acts)
+ self.update_gui_add_label("Text placed into looooooooooong string")
elif self.curr_mode == 90:
# list parts
lb = self.update_gui_add_left_listbox("Parts")
for part in self.sim.parts:
lb.insert(tkinter.END, part)
-
- lab = ttk.Label(self.frm_info, text = "Select parts")
- lab.pack()
- self.curr_gui.append(lambda:lab.pack_forget())
-
+ self.update_gui_add_label("Select parts")
elif self.curr_mode == 100:
# list resources
lb = self.update_gui_add_left_listbox("Resources")
@@ -352,11 +345,15 @@ class App(tkinter.Frame):
lb = self.update_gui_add_left_listbox("Objects")
for obj in self.sim.objects:
lb.insert(tkinter.END, "{} - {}".format(obj.idx, obj.name))
+ self.update_gui_add_label("Object info")
elif self.curr_mode == 102:
# list scenes
lb = self.update_gui_add_left_listbox("Scenes")
for scn in self.sim.scenes:
lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
+ self.update_gui_add_label("Scene info")
+
+ self.update_after()
def on_left_listbox(self, event):
if self.curr_lb_acts:
Commit: 86a8ced5ac4fc2d48fc77ae00ea8d92f96f97613
https://github.com/scummvm/scummvm-tools/commit/86a8ced5ac4fc2d48fc77ae00ea8d92f96f97613
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Fix unloading stores
Changed paths:
engines/petka/petka/fman.py
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index f61d5ed7c..3fee9123e 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -30,8 +30,6 @@ class FileManager:
break
if not ok: return None
return npath
-
-
def load_store(self, name, tag = 0):
path = self.find_path(name)
@@ -61,8 +59,8 @@ class FileManager:
for idx, fname in enumerate(data.split("\x00")):
fname = fname.lower().replace("\\", "/")
if idx < index_len and fname not in self.strtable:
- self.strtable[fname] = (len(self.strfd),) + \
- index_table[idx]
+ self.strtable[fname] = (len(self.strfd),) + index_table[idx]
+ print("STORE:", fname)
else:
if len(fname) > 0:
raise EngineError("Extra file record \"{}\" in \"{}\"".\
@@ -97,10 +95,10 @@ class FileManager:
strtable = {}
for idx, (fd, name, tag) in enumerate(self.strfd):
if flt is not None:
- if tag != flt:
- for k, v in self.strtable:
- if v == idx:
- strtable[k] = len(strfd)
+ if tag != flt:
+ for k, v in self.strtable.items():
+ if v[0] == idx:
+ strtable[k] = (len(strfd), v[1], v[2])
strfd.append((fd, name, tag))
continue
print("DEBUG: Unload store \"{}\"".format(name))
@@ -108,6 +106,6 @@ class FileManager:
if fd: fd.close()
except Exception as e:
print("DEBUG: Can't unload \"{}\":".format(name) + str(e))
- self.strff = strfd
+ self.strfd = strfd
self.strtable = strtable
Commit: 8f81a2b9148305cfaf49240583e78c1635aca701
https://github.com/scummvm/scummvm-tools/commit/8f81a2b9148305cfaf49240583e78c1635aca701
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refine outline information
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index b5ff3553a..78be2752c 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -35,7 +35,7 @@ class App(tkinter.Frame):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
- ttk.Style().configure('Info.TFrame', background = 'white')
+ ttk.Style().configure('Info.TFrame', background = 'white', foreground = "black")
# main paned
self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
@@ -58,7 +58,7 @@ class App(tkinter.Frame):
self.scr_view_y.grid(row = 0, column = 1, sticky = \
tkinter.N + tkinter.S)
self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
- bd = 0, highlightthickness = 0, bg = "white",
+ bd = 0, highlightthickness = 0,
scrollregion = (0, 0, 50, 50),
xscrollcommand = self.scr_view_x.set,
yscrollcommand = self.scr_view_y.set)
@@ -313,18 +313,19 @@ class App(tkinter.Frame):
self.update_gui()
acts = [
("Parts", self.on_list_parts),
- ("Resources", self.on_list_res),
- ("Objects", self.on_list_objs),
- ("Scenes", self.on_list_scenes),
+ ("Resources ({})".format(len(self.sim.res)), self.on_list_res),
+ ("Objects ({})".format(len(self.sim.objects)), self.on_list_objs),
+ ("Scenes ({})".format(len(self.sim.scenes)), self.on_list_scenes),
("-", None),
("Test image", tst_img),
("Test info", tst_info),
]
- self.update_gui_add_left_listbox("Outline", acts)
+ self.update_gui_add_left_listbox("Outline: part {} chapter {}".\
+ format(self.sim.curr_part, self.sim.curr_chap), acts)
self.update_gui_add_label("Select data type from outline")
elif self.curr_mode == 99:
acts = [
- ("<- Back", self.on_outline)
+ ("<- outline", self.on_outline)
]
self.update_gui_add_left_listbox("Test info", acts)
self.update_gui_add_label("Text placed into looooooooooong string")
@@ -334,6 +335,8 @@ class App(tkinter.Frame):
for part in self.sim.parts:
lb.insert(tkinter.END, part)
self.update_gui_add_label("Select parts")
+ self.update_gui_add_label("or goto outline")
+
elif self.curr_mode == 100:
# list resources
lb = self.update_gui_add_left_listbox("Resources")
@@ -378,7 +381,7 @@ class App(tkinter.Frame):
cnum = pnum.split("Chapter", 1)
if len(cnum) > 1:
pnum = int(cnum[0].strip(), 10)
- cnum = int(cnum[0].strip(), 10)
+ cnum = int(cnum[1].strip(), 10)
else:
cnum = 0
self.sim.open_part(pnum, cnum)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 48955e95b..b02960844 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -82,9 +82,9 @@ class Engine:
data = self.parts_ini[sect]
if sect == "All":
if "Part" in data:
- self.start_part = int(data["Part"]) - 1
+ self.start_part = int(data["Part"])
if "Chapter" in data:
- self.start_chap = int(data["Chapter"]) - 1
+ self.start_chap = int(data["Chapter"])
elif sect[:5] == "Part ":
self.parts.append(sect)
else:
@@ -97,6 +97,8 @@ class Engine:
def open_part(self, part, chap):
self.fman.unload_stores(1)
+ self.curr_part = part
+ self.curr_chap = chap
if self.parts_ini:
pname = "Part {}".format(part)
pcname = pname
@@ -106,18 +108,19 @@ class Engine:
self.curr_path = ini["CurrentPath"]
self.curr_speech = ini["PathSpeech"]
self.curr_diskid = ini["DiskID"]
+ inic = self.parts_ini[pcname]
+ if "Chapter" in inic:
+ self.fman.load_store(inic["Chapter"], 1)
else:
ini = {}
self.curr_path = ""
self.curr_speech = ""
self.curr_diskid = None
-
# load BGS.INI
self.bgs_ini = {}
self.start_scene = None
pf = self.fman.find_path(self.curr_path + "bgs.ini")
- print(self.curr_path)
if pf:
f = open(pf, "rb")
try:
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index 3fee9123e..12435df8a 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -60,7 +60,6 @@ class FileManager:
fname = fname.lower().replace("\\", "/")
if idx < index_len and fname not in self.strtable:
self.strtable[fname] = (len(self.strfd),) + index_table[idx]
- print("STORE:", fname)
else:
if len(fname) > 0:
raise EngineError("Extra file record \"{}\" in \"{}\"".\
Commit: dd01092a27d2e408a9dabdd760d631a02777dc2c
https://github.com/scummvm/scummvm-tools/commit/dd01092a27d2e408a9dabdd760d631a02777dc2c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refine outline information
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 78be2752c..276c42afc 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -11,6 +11,38 @@ import petka
APPNAME = "P1&2 Explorer"
+# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
+class HyperlinkManager:
+ def __init__(self, text):
+ self.text = text
+ self.text.tag_config("hyper", foreground = "blue", underline = 1)
+ self.text.tag_bind("hyper", "<Enter>", self._enter)
+ self.text.tag_bind("hyper", "<Leave>", self._leave)
+ self.text.tag_bind("hyper", "<Button-1>", self._click)
+ self.reset()
+
+ def reset(self):
+ self.links = {}
+
+ def add(self, action):
+ # add an action to the manager. returns tags to use in
+ # associated text widget
+ tag = "hyper-{}".format(len(self.links))
+ self.links[tag] = action
+ return "hyper", tag
+
+ def _enter(self, event):
+ self.text.config(cursor = "hand2")
+
+ def _leave(self, event):
+ self.text.config(cursor = "")
+
+ def _click(self, event):
+ for tag in self.text.tag_names(CURRENT):
+ if tag[:6] == "hyper-":
+ self.links[tag]()
+ return
+
class App(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
Commit: f7dfc9c6f1dab6be930eded0445e15f9b2b3abbf
https://github.com/scummvm/scummvm-tools/commit/f7dfc9c6f1dab6be930eded0445e15f9b2b3abbf
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Hyperlinks in info panel
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 276c42afc..dd3f22dba 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -14,34 +14,33 @@ APPNAME = "P1&2 Explorer"
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
def __init__(self, text):
- self.text = text
- self.text.tag_config("hyper", foreground = "blue", underline = 1)
- self.text.tag_bind("hyper", "<Enter>", self._enter)
- self.text.tag_bind("hyper", "<Leave>", self._leave)
- self.text.tag_bind("hyper", "<Button-1>", self._click)
- self.reset()
-
+ self.text = text
+ self.text.tag_config("hyper", foreground = "blue", underline = 1)
+ self.text.tag_bind("hyper", "<Enter>", self._enter)
+ self.text.tag_bind("hyper", "<Leave>", self._leave)
+ self.text.tag_bind("hyper", "<Button-1>", self._click)
+ self.reset()
def reset(self):
self.links = {}
def add(self, action):
# add an action to the manager. returns tags to use in
# associated text widget
- tag = "hyper-{}".format(len(self.links))
- self.links[tag] = action
- return "hyper", tag
+ tag = "hyper-{}".format(len(self.links))
+ self.links[tag] = action
+ return "hyper", tag
def _enter(self, event):
- self.text.config(cursor = "hand2")
+ self.text.config(cursor = "hand2")
def _leave(self, event):
- self.text.config(cursor = "")
+ self.text.config(cursor = "")
def _click(self, event):
- for tag in self.text.tag_names(CURRENT):
- if tag[:6] == "hyper-":
- self.links[tag]()
- return
+ for tag in self.text.tag_names(tkinter.CURRENT):
+ if tag[:6] == "hyper-":
+ self.links[tag]()
+ return
class App(tkinter.Frame):
def __init__(self, master):
@@ -309,19 +308,23 @@ class App(tkinter.Frame):
def update_gui(self):
self.canv_view.delete(tkinter.ALL)
+ for item in self.curr_gui:
+ item()
+ self.curr_gui = []
+
if self.curr_main == 0:
# info panel
self.frm_info = ttk.Frame(self.canv_view)
self.frm_info_id = self.canv_view.create_window(0, 0,
window = self.frm_info, anchor = tkinter.NW)
self.frm_info.bind('<Configure>', self.on_resize_info)
-
self.canv_view.xview_moveto(0)
self.canv_view.yview_moveto(0)
-
- for item in self.curr_gui:
- item()
- self.curr_gui = []
+ # info data
+ self.frm_info_text = tkinter.Text(self.frm_info)
+ self.frm_info_hl = HyperlinkManager(self.frm_info_text)
+ self.frm_info_text.pack(expand = 1, fill = tkinter.BOTH)
+ self.curr_gui.append(lambda:self.frm_info_text.pack_forget())
if self.curr_mode == 0:
if self.sim is None:
@@ -366,9 +369,6 @@ class App(tkinter.Frame):
lb = self.update_gui_add_left_listbox("Parts")
for part in self.sim.parts:
lb.insert(tkinter.END, part)
- self.update_gui_add_label("Select parts")
- self.update_gui_add_label("or goto outline")
-
elif self.curr_mode == 100:
# list resources
lb = self.update_gui_add_left_listbox("Resources")
@@ -387,9 +387,40 @@ class App(tkinter.Frame):
for scn in self.sim.scenes:
lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
self.update_gui_add_label("Scene info")
-
+ self.update_info()
self.update_after()
+ def update_info(self):
+ def stdinfo():
+ self.frm_info_text.delete(0.0, tkinter.END)
+ self.frm_info_text.insert(tkinter.INSERT, "<- Outline", \
+ self.frm_info_hl.add(self.on_outline))
+ self.frm_info_text.insert(tkinter.INSERT, "\n\n")
+ if self.curr_mode == 99:
+ stdinfo()
+ for i in range(100):
+ self.frm_info_text.insert(tkinter.INSERT, "Item {}\n".format(i))
+ elif self.curr_mode == 90:
+ stdinfo()
+ self.frm_info_text.insert(tkinter.INSERT, \
+ "Current: part {} chapter {}\n\n Resources: ".\
+ format(self.sim.curr_part, self.sim.curr_chap))
+ self.frm_info_text.insert(tkinter.INSERT, "{}".\
+ format(len(self.sim.res)), \
+ self.frm_info_hl.add(self.on_list_res))
+ self.frm_info_text.insert(tkinter.INSERT, "\n Objects: ")
+ self.frm_info_text.insert(tkinter.INSERT, "{}".\
+ format(len(self.sim.objects)), \
+ self.frm_info_hl.add(self.on_list_objs))
+ self.frm_info_text.insert(tkinter.INSERT, "\n Scenes: ")
+ self.frm_info_text.insert(tkinter.INSERT, "{}".\
+ format(len(self.sim.scenes)), \
+ self.frm_info_hl.add(self.on_list_scenes))
+ elif self.curr_mode == 101:
+ stdinfo()
+ elif self.curr_mode == 102:
+ stdinfo()
+
def on_left_listbox(self, event):
if self.curr_lb_acts:
try:
@@ -417,6 +448,7 @@ class App(tkinter.Frame):
else:
cnum = 0
self.sim.open_part(pnum, cnum)
+ self.update_info()
self.update_after()
elif self.curr_mode == 100:
# resources
Commit: 8ed83d8ed40adb2f4587ce74afe58795bb4edcf9
https://github.com/scummvm/scummvm-tools/commit/8ed83d8ed40adb2f4587ce74afe58795bb4edcf9
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Info panel works, refactor
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index dd3f22dba..20e8f95e7 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -75,8 +75,7 @@ class App(tkinter.Frame):
# leftpanel
self.frm_left = ttk.Frame(self.pan_main)
self.pan_main.add(self.frm_left)
-
- # canvas
+ # main view
self.frm_view = ttk.Frame(self.pan_main)
self.pan_main.add(self.frm_view)
self.frm_view.grid_rowconfigure(0, weight = 1)
@@ -88,20 +87,24 @@ class App(tkinter.Frame):
self.scr_view_y = ttk.Scrollbar(self.frm_view)
self.scr_view_y.grid(row = 0, column = 1, sticky = \
tkinter.N + tkinter.S)
+ # canvas
self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
bd = 0, highlightthickness = 0,
scrollregion = (0, 0, 50, 50),
- xscrollcommand = self.scr_view_x.set,
- yscrollcommand = self.scr_view_y.set)
- self.canv_view.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
- self.scr_view_x.config(command = self.canv_view.xview)
- self.scr_view_y.config(command = self.canv_view.yview)
+ )
# don't forget
# canvas.config(scrollregion=(left, top, right, bottom))
self.canv_view.bind('<Configure>', self.on_resize_view)
self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
+ # text
+ self.text_view = tkinter.Text(self.frm_view,
+ highlightthickness = 0,
+ )
+ self.text_hl = HyperlinkManager(self.text_view)
+ self.text_view.bind('<Configure>', self.on_resize_view)
+
+
self.update_after()
self.update_gui()
@@ -169,22 +172,6 @@ class App(tkinter.Frame):
self.update_after()
def on_resize_view(self, event):
- if self.curr_main == 0:
- w = self.frm_info.winfo_reqwidth()
- h = self.frm_info.winfo_reqheight()
- if w != self.canv_view.winfo_width() or \
- h != self.canv_view.winfo_height():
- self.canv_view.itemconfigure(self.frm_info_id,
- width = w, height = h)
- self.update_after()
-
- def on_resize_info(self, event):
- w = self.frm_info.winfo_reqwidth()
- h = self.frm_info.winfo_reqheight()
- self.canv_view.config(scrollregion = (0, 0, w, h))
- if w != self.canv_view.winfo_width() or \
- h != self.canv_view.winfo_height():
- self.canv_view.config(width = w, height = h)
self.update_after()
def update_canvas(self):
@@ -301,11 +288,6 @@ class App(tkinter.Frame):
self.curr_lb = lb
return lb
- def update_gui_add_label(self, text):
- lab = ttk.Label(self.frm_info, text = text)
- lab.pack()
- self.curr_gui.append(lambda:lab.pack_forget())
-
def update_gui(self):
self.canv_view.delete(tkinter.ALL)
for item in self.curr_gui:
@@ -313,18 +295,25 @@ class App(tkinter.Frame):
self.curr_gui = []
if self.curr_main == 0:
- # info panel
- self.frm_info = ttk.Frame(self.canv_view)
- self.frm_info_id = self.canv_view.create_window(0, 0,
- window = self.frm_info, anchor = tkinter.NW)
- self.frm_info.bind('<Configure>', self.on_resize_info)
- self.canv_view.xview_moveto(0)
- self.canv_view.yview_moveto(0)
- # info data
- self.frm_info_text = tkinter.Text(self.frm_info)
- self.frm_info_hl = HyperlinkManager(self.frm_info_text)
- self.frm_info_text.pack(expand = 1, fill = tkinter.BOTH)
- self.curr_gui.append(lambda:self.frm_info_text.pack_forget())
+ self.canv_view.grid_forget()
+ self.text_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ self.text_view.configure(
+ xscrollcommand = self.scr_view_x.set,
+ yscrollcommand = self.scr_view_y.set
+ )
+ self.scr_view_x.config(command = self.text_view.xview)
+ self.scr_view_y.config(command = self.text_view.yview)
+ else:
+ self.text_view.grid_forget()
+ self.canv_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ self.canv_view.configure(
+ xscrollcommand = self.scr_view_x.set,
+ yscrollcommand = self.scr_view_y.set
+ )
+ self.scr_view_x.config(command = self.canv_view.xview)
+ self.scr_view_y.config(command = self.canv_view.yview)
if self.curr_mode == 0:
if self.sim is None:
@@ -333,7 +322,6 @@ class App(tkinter.Frame):
("Open data", self.on_open_data)
]
self.update_gui_add_left_listbox("Outline", acts)
- self.update_gui_add_label("Open data")
else:
def tst_img():
self.curr_main = 1
@@ -357,13 +345,11 @@ class App(tkinter.Frame):
]
self.update_gui_add_left_listbox("Outline: part {} chapter {}".\
format(self.sim.curr_part, self.sim.curr_chap), acts)
- self.update_gui_add_label("Select data type from outline")
elif self.curr_mode == 99:
acts = [
("<- outline", self.on_outline)
]
self.update_gui_add_left_listbox("Test info", acts)
- self.update_gui_add_label("Text placed into looooooooooong string")
elif self.curr_mode == 90:
# list parts
lb = self.update_gui_add_left_listbox("Parts")
@@ -380,55 +366,74 @@ class App(tkinter.Frame):
lb = self.update_gui_add_left_listbox("Objects")
for obj in self.sim.objects:
lb.insert(tkinter.END, "{} - {}".format(obj.idx, obj.name))
- self.update_gui_add_label("Object info")
elif self.curr_mode == 102:
# list scenes
lb = self.update_gui_add_left_listbox("Scenes")
for scn in self.sim.scenes:
lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
- self.update_gui_add_label("Scene info")
self.update_info()
self.update_after()
def update_info(self):
def stdinfo():
- self.frm_info_text.delete(0.0, tkinter.END)
- self.frm_info_text.insert(tkinter.INSERT, "<- Outline", \
- self.frm_info_hl.add(self.on_outline))
- self.frm_info_text.insert(tkinter.INSERT, "\n\n")
- if self.curr_mode == 99:
+ self.text_view.delete(0.0, tkinter.END)
+ self.text_view.insert(tkinter.INSERT, "<- Outline", \
+ self.text_hl.add(self.on_outline))
+ self.text_view.insert(tkinter.INSERT, "\n\n")
+
+ if self.curr_mode == 0:
+ self.text_view.delete(0.0, tkinter.END)
+ if self.sim is None:
+ self.text_view.insert(tkinter.INSERT, "No data loaded")
+ self.text_view.insert(tkinter.INSERT, "Open data", \
+ self.text_hl.add(self.on_open_data))
+ else:
+ self.text_view.insert(tkinter.INSERT, \
+ "Select type from outline")
+ elif self.curr_mode == 99:
stdinfo()
for i in range(100):
- self.frm_info_text.insert(tkinter.INSERT, "Item {}\n".format(i))
+ self.text_view.insert(tkinter.INSERT, \
+ "Item {}\n".format(i))
elif self.curr_mode == 90:
stdinfo()
- self.frm_info_text.insert(tkinter.INSERT, \
+ self.text_view.insert(tkinter.INSERT, \
"Current: part {} chapter {}\n\n Resources: ".\
format(self.sim.curr_part, self.sim.curr_chap))
- self.frm_info_text.insert(tkinter.INSERT, "{}".\
+ self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.res)), \
- self.frm_info_hl.add(self.on_list_res))
- self.frm_info_text.insert(tkinter.INSERT, "\n Objects: ")
- self.frm_info_text.insert(tkinter.INSERT, "{}".\
+ self.text_hl.add(self.on_list_res))
+ self.text_view.insert(tkinter.INSERT, "\n Objects: ")
+ self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.objects)), \
- self.frm_info_hl.add(self.on_list_objs))
- self.frm_info_text.insert(tkinter.INSERT, "\n Scenes: ")
- self.frm_info_text.insert(tkinter.INSERT, "{}".\
+ self.text_hl.add(self.on_list_objs))
+ self.text_view.insert(tkinter.INSERT, "\n Scenes: ")
+ self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.scenes)), \
- self.frm_info_hl.add(self.on_list_scenes))
+ self.text_hl.add(self.on_list_scenes))
elif self.curr_mode == 101:
stdinfo()
elif self.curr_mode == 102:
stdinfo()
+ else:
+ stdinfo()
def on_left_listbox(self, event):
- if self.curr_lb_acts:
+ def currsel():
try:
num = self.curr_lb.curselection()[0]
num = int(num)
except:
pass
- act = self.curr_lb_acts[num]
+ return num
+
+ def objinfo(tp, rec):
+ self.text_view.insert(tkinter.INSERT, tp + "\n\n")
+ self.text_view.insert(tkinter.INSERT, \
+ " Index: {}\n Name: {}".format(rec.idx, rec.name))
+
+ if self.curr_lb_acts:
+ act = self.curr_lb_acts[currsel()]
if act[1]:
act[1]()
elif self.curr_mode == 90:
@@ -468,6 +473,14 @@ class App(tkinter.Frame):
self.curr_height = bmp.height
self.update_after()
print(fn)
+ elif self.curr_mode == 101:
+ # objects
+ self.update_info()
+ objinfo("Object:", self.sim.objects[currsel()])
+ elif self.curr_mode == 102:
+ # scenes
+ self.update_info()
+ objinfo("Scene:", self.sim.scenes[currsel()])
def on_open_data(self):
# open data - select TODO
Commit: 56e1eaa0971d454ce3bf4189e1b48ab9e9854406
https://github.com/scummvm/scummvm-tools/commit/56e1eaa0971d454ce3bf4189e1b48ab9e9854406
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Names and invntr information
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 20e8f95e7..0120f61b5 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -143,6 +143,12 @@ class App(tkinter.Frame):
self.menuedit.add_command(
command = self.on_list_scenes,
label = "Scenes")
+ self.menuedit.add_command(
+ command = self.on_list_names,
+ label = "Names")
+ self.menuedit.add_command(
+ command = self.on_list_invntr,
+ label = "Invntr")
def update_after(self):
if not self.need_update:
@@ -336,9 +342,16 @@ class App(tkinter.Frame):
self.update_gui()
acts = [
("Parts", self.on_list_parts),
- ("Resources ({})".format(len(self.sim.res)), self.on_list_res),
- ("Objects ({})".format(len(self.sim.objects)), self.on_list_objs),
- ("Scenes ({})".format(len(self.sim.scenes)), self.on_list_scenes),
+ ("Resources ({})".format(len(self.sim.res)), \
+ self.on_list_res),
+ ("Objects ({})".format(len(self.sim.objects)), \
+ self.on_list_objs),
+ ("Scenes ({})".format(len(self.sim.scenes)), \
+ self.on_list_scenes),
+ ("Names ({})".format(len(self.sim.names)), \
+ self.on_list_names),
+ ("Invntr ({})".format(len(self.sim.invntr)), \
+ self.on_list_invntr),
("-", None),
("Test image", tst_img),
("Test info", tst_info),
@@ -371,6 +384,16 @@ class App(tkinter.Frame):
lb = self.update_gui_add_left_listbox("Scenes")
for scn in self.sim.scenes:
lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
+ elif self.curr_mode == 103:
+ # list names
+ lb = self.update_gui_add_left_listbox("Names")
+ for name in self.sim.names.keys():
+ lb.insert(tkinter.END, "{}".format(name))
+ elif self.curr_mode == 104:
+ # list invntr
+ lb = self.update_gui_add_left_listbox("Invntr")
+ for name in self.sim.invntr.keys():
+ lb.insert(tkinter.END, "{}".format(name))
self.update_info()
self.update_after()
@@ -403,14 +426,22 @@ class App(tkinter.Frame):
self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.res)), \
self.text_hl.add(self.on_list_res))
- self.text_view.insert(tkinter.INSERT, "\n Objects: ")
+ self.text_view.insert(tkinter.INSERT, "\n Objects: ")
self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.objects)), \
self.text_hl.add(self.on_list_objs))
- self.text_view.insert(tkinter.INSERT, "\n Scenes: ")
+ self.text_view.insert(tkinter.INSERT, "\n Scenes: ")
self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.scenes)), \
self.text_hl.add(self.on_list_scenes))
+ self.text_view.insert(tkinter.INSERT, "\n Names: ")
+ self.text_view.insert(tkinter.INSERT, "{}".\
+ format(len(self.sim.names)), \
+ self.text_hl.add(self.on_list_names))
+ self.text_view.insert(tkinter.INSERT, "\n Invntr: ")
+ self.text_view.insert(tkinter.INSERT, "{}".\
+ format(len(self.sim.invntr)), \
+ self.text_hl.add(self.on_list_invntr))
elif self.curr_mode == 101:
stdinfo()
elif self.curr_mode == 102:
@@ -428,10 +459,17 @@ class App(tkinter.Frame):
return num
def objinfo(tp, rec):
- self.text_view.insert(tkinter.INSERT, tp + "\n\n")
self.text_view.insert(tkinter.INSERT, \
- " Index: {}\n Name: {}".format(rec.idx, rec.name))
-
+ ("Object" if tp else "Scene") + ":\n")
+ self.text_view.insert(tkinter.INSERT, \
+ " Index: {}\n Name: {}\n".format(rec.idx, rec.name))
+ if rec.name in self.sim.names:
+ self.text_view.insert(tkinter.INSERT, \
+ " Alias: {}\n".format(self.sim.names[rec.name]))
+ if rec.name in self.sim.invntr:
+ self.text_view.insert(tkinter.INSERT, \
+ " Invntr: {}\n".format(self.sim.invntr[rec.name]))
+
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
if act[1]:
@@ -476,11 +514,57 @@ class App(tkinter.Frame):
elif self.curr_mode == 101:
# objects
self.update_info()
- objinfo("Object:", self.sim.objects[currsel()])
+ objinfo(True, self.sim.objects[currsel()])
elif self.curr_mode == 102:
# scenes
self.update_info()
- objinfo("Scene:", self.sim.scenes[currsel()])
+ objinfo(False, self.sim.scenes[currsel()])
+ elif self.curr_mode == 103:
+ # names
+ self.update_info()
+ key = list(self.sim.names.keys())[currsel()]
+ self.text_view.insert(tkinter.INSERT, \
+ "Object: {}\n".format(key))
+ self.text_view.insert(tkinter.INSERT, \
+ "Alias: {}\n\n".format(self.sim.names[key]))
+ # search for objects
+ self.text_view.insert(tkinter.INSERT, \
+ "Applied for:")
+ for obj in self.sim.objects:
+ if obj.name == key:
+ self.text_view.insert(tkinter.INSERT, \
+ "\n ")
+ def make_cb(idx):
+ def cb():
+ print("TODO: names obj", idx)
+ return cb
+ self.text_view.insert(tkinter.INSERT, \
+ "{} - {}".format(obj.idx, obj.name), \
+ self.text_hl.add(make_cb(obj.idx)))
+ elif self.curr_mode == 104:
+ # invntr
+ self.update_info()
+ key = list(self.sim.invntr.keys())[currsel()]
+ self.text_view.insert(tkinter.INSERT, \
+ "Object: {}\n".format(key))
+ self.text_view.insert(tkinter.INSERT, \
+ "{}\n\n".format(self.sim.invntr[key]))
+ # search for objects
+ self.text_view.insert(tkinter.INSERT, \
+ "Applied for:")
+ for obj in self.sim.objects:
+ if obj.name == key:
+ self.text_view.insert(tkinter.INSERT, \
+ "\n ")
+ def make_cb(idx):
+ def cb():
+ print("TODO: invntr obj", idx)
+ return cb
+ self.text_view.insert(tkinter.INSERT, \
+ "{} - {}".format(obj.idx, obj.name), \
+ self.text_hl.add(make_cb(obj.idx)))
+
+
def on_open_data(self):
# open data - select TODO
@@ -510,6 +594,16 @@ class App(tkinter.Frame):
self.curr_mode = 102
self.curr_main = 0
self.update_gui()
+
+ def on_list_names(self):
+ self.curr_mode = 103
+ self.curr_main = 0
+ self.update_gui()
+
+ def on_list_invntr(self):
+ self.curr_mode = 104
+ self.curr_main = 0
+ self.update_gui()
def open_data_from(self, folder):
self.sim = petka.Engine()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index b02960844..a6e33cc3e 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -204,11 +204,22 @@ class Engine:
raise EngineError("DEBUG: Object ID = 0x{:x} not found".\
format(obj[0]))
- data = self.fman.read_file(self.curr_path + "resource.qrc")
- mems = io.BytesIO()
- mems.write(data)
- mems.seek(0)
- self.res, self.resord = self.parse_res(mems)
+ f = self.fman.read_file_stream(self.curr_path + "resource.qrc")
+ self.res, self.resord = self.parse_res(f)
+ f.close()
+ self.names = {}
+ fp = self.curr_path + "names.ini"
+ if self.fman.exists(fp):
+ f = self.fman.read_file_stream(fp)
+ self.names = self.parse_ini(f)["all"]
+ f.close()
+
+ self.invntr = {}
+ fp = self.curr_path + "invntr.txt"
+ if self.fman.exists(fp):
+ f = self.fman.read_file_stream(fp)
+ self.invntr = self.parse_ini(f)["ALL"]
+ f.close()
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index 12435df8a..acb5c362b 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -4,6 +4,7 @@
import os
import struct
+import io
from . import EngineError
@@ -88,6 +89,19 @@ class FileManager:
f.close()
return data
+ def read_file_stream(self, fname):
+ data = self.read_file(fname)
+ mems = io.BytesIO()
+ mems.write(data)
+ mems.seek(0)
+ return mems
+
+ def exists(self, fname):
+ sf = fname.lower().replace("\\", "/")
+ if sf in self.strtable:
+ return True
+ else:
+ return self.find_path(fname) is not None
def unload_stores(self, flt = None):
strfd = []
Commit: 0600e6948cd65dc812ba3987b5ff24639f5e0223
https://github.com/scummvm/scummvm-tools/commit/0600e6948cd65dc812ba3987b5ff24639f5e0223
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Names anr invntr order as in file
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 0120f61b5..9eb94a535 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -387,12 +387,12 @@ class App(tkinter.Frame):
elif self.curr_mode == 103:
# list names
lb = self.update_gui_add_left_listbox("Names")
- for name in self.sim.names.keys():
+ for name in self.sim.namesord:
lb.insert(tkinter.END, "{}".format(name))
elif self.curr_mode == 104:
# list invntr
lb = self.update_gui_add_left_listbox("Invntr")
- for name in self.sim.invntr.keys():
+ for name in self.sim.invntrord:
lb.insert(tkinter.END, "{}".format(name))
self.update_info()
self.update_after()
@@ -522,7 +522,7 @@ class App(tkinter.Frame):
elif self.curr_mode == 103:
# names
self.update_info()
- key = list(self.sim.names.keys())[currsel()]
+ key = self.sim.namesord[currsel()]
self.text_view.insert(tkinter.INSERT, \
"Object: {}\n".format(key))
self.text_view.insert(tkinter.INSERT, \
@@ -544,7 +544,7 @@ class App(tkinter.Frame):
elif self.curr_mode == 104:
# invntr
self.update_info()
- key = list(self.sim.invntr.keys())[currsel()]
+ key = self.sim.invntrord[currsel()]
self.text_view.insert(tkinter.INSERT, \
"Object: {}\n".format(key))
self.text_view.insert(tkinter.INSERT, \
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index a6e33cc3e..64a5bb77c 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -33,20 +33,27 @@ class Engine:
# parse ini settings
curr_sect = None
ini = {}
- ordersect = []
+ order_sect = []
+ orders = {}
for line in f.readlines():
line = line.decode(self.enc).strip()
if len(line) == 0: continue
if line[:1] == ";": continue
if line[:1] == "[" and line[-1:] == "]":
+ if curr_sect is not None:
+ orders[curr_sect] = order
curr_sect = line[1:-1].strip()
+ order_sect.append(curr_sect)
+ order = []
ini[curr_sect] = {}
- ordersect.append(curr_sect)
continue
kv = line.split("=", 1)
if len(kv) != 2: continue
ini[curr_sect][kv[0].strip()] = kv[1].strip()
- ini["__order__"] = ordersect
+ order.append(kv[0].strip())
+ orders[curr_sect] = order
+ ini["__ordersect__"] = order_sect
+ ini["__order__"] = orders
return ini
def parse_res(self, f):
@@ -78,7 +85,7 @@ class Engine:
self.parts_ini = self.parse_ini(f)
finally:
f.close()
- for sect in self.parts_ini["__order__"]:
+ for sect in self.parts_ini["__ordersect__"]:
data = self.parts_ini[sect]
if sect == "All":
if "Part" in data:
@@ -212,14 +219,18 @@ class Engine:
fp = self.curr_path + "names.ini"
if self.fman.exists(fp):
f = self.fman.read_file_stream(fp)
- self.names = self.parse_ini(f)["all"]
+ ini = self.parse_ini(f)
+ self.names = ini["all"]
+ self.namesord = ini["__order__"]["all"]
f.close()
self.invntr = {}
fp = self.curr_path + "invntr.txt"
if self.fman.exists(fp):
f = self.fman.read_file_stream(fp)
- self.invntr = self.parse_ini(f)["ALL"]
+ ini = self.parse_ini(f)
+ self.invntr = ini["ALL"]
+ self.invntrord = ini["__order__"]["ALL"]
f.close()
Commit: 82c8104b1435726260c72f9ca7ec741aab4227fa
https://github.com/scummvm/scummvm-tools/commit/82c8104b1435726260c72f9ca7ec741aab4227fa
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Open aliases and invntr from objects, refactor
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9eb94a535..2ffd1a3ff 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -6,6 +6,7 @@
import sys, os
import tkinter
from tkinter import ttk, font
+from idlelib.WidgetRedirector import WidgetRedirector
import petka
@@ -42,6 +43,17 @@ class HyperlinkManager:
self.links[tag]()
return
+
+# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
+class ReadOnlyText(tkinter.Text):
+ def __init__(self, *args, **kwargs):
+ tkinter.Text.__init__(self, *args, **kwargs)
+ self.redirector = WidgetRedirector(self)
+ self.insert = \
+ self.redirector.register("insert", lambda *args, **kw: "break")
+ self.delete = \
+ self.redirector.register("delete", lambda *args, **kw: "break")
+
class App(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
@@ -50,9 +62,9 @@ class App(tkinter.Frame):
self.pad = None
self.sim = None
# gui
+ self.curr_main = 0 # 0 - frame, 1 - canvas
self.curr_mode = 0
self.curr_gui = []
- self.curr_main = 0 # 0 - frame, 1 - canvas
self.curr_lb_acts = None
# canvas
self.curr_width = 0
@@ -98,13 +110,12 @@ class App(tkinter.Frame):
self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
# text
- self.text_view = tkinter.Text(self.frm_view,
+ self.text_view = ReadOnlyText(self.frm_view,
highlightthickness = 0,
)
self.text_hl = HyperlinkManager(self.text_view)
self.text_view.bind('<Configure>', self.on_resize_view)
-
self.update_after()
self.update_gui()
@@ -337,9 +348,7 @@ class App(tkinter.Frame):
self.curr_height = self.main_image.height()
self.update_gui()
def tst_info():
- self.curr_mode = 99
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 99)
acts = [
("Parts", self.on_list_parts),
("Resources ({})".format(len(self.sim.res)), \
@@ -448,6 +457,42 @@ class App(tkinter.Frame):
stdinfo()
else:
stdinfo()
+
+ def open_gui_elem(self, main, mode, idx):
+ if self.curr_mode != mode:
+ self.change_gui(main, mode)
+ self.curr_lb.selection_set(idx)
+ self.curr_lb.see(idx)
+ self.on_left_listbox(None)
+
+ def open_object(self, obj_id):
+ for idx, obj in enumerate(self.sim.objects):
+ if obj.idx == obj_id:
+ self.open_gui_elem(0, 101, idx)
+ break
+
+ def open_scene(self, scn_id):
+ for idx, obj in enumerate(self.sim.scenes):
+ if obj.idx == scn_id:
+ self.open_gui_elem(0, 102, idx)
+ break
+
+ def open_name(self, name_key):
+ for idx, key in enumerate(self.sim.namesord):
+ if key == name_key:
+ self.open_gui_elem(0, 103, idx)
+ break
+
+ def open_invntr(self, inv_key):
+ for idx, key in enumerate(self.sim.invntrord):
+ if key == inv_key:
+ self.open_gui_elem(0, 104, idx)
+ break
+
+ def change_gui(self, main, mode):
+ self.curr_main = main
+ self.curr_mode = mode
+ self.update_gui()
def on_left_listbox(self, event):
def currsel():
@@ -464,12 +509,25 @@ class App(tkinter.Frame):
self.text_view.insert(tkinter.INSERT, \
" Index: {}\n Name: {}\n".format(rec.idx, rec.name))
if rec.name in self.sim.names:
+ self.text_view.insert(tkinter.INSERT, " ")
+ def make_cb(key):
+ def cb():
+ self.open_name(key)
+ return cb
+ self.text_view.insert(tkinter.INSERT, "Alias", \
+ self.text_hl.add(make_cb(rec.name)))
self.text_view.insert(tkinter.INSERT, \
- " Alias: {}\n".format(self.sim.names[rec.name]))
+ ": {}\n".format(self.sim.names[rec.name]))
if rec.name in self.sim.invntr:
+ self.text_view.insert(tkinter.INSERT, " ")
+ def make_cb(key):
+ def cb():
+ self.open_invntr(key)
+ return cb
+ self.text_view.insert(tkinter.INSERT, "Invntr", \
+ self.text_hl.add(make_cb(rec.name)))
self.text_view.insert(tkinter.INSERT, \
- " Invntr: {}\n".format(self.sim.invntr[rec.name]))
-
+ ": {}\n".format(self.sim.invntr[rec.name]))
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
if act[1]:
@@ -524,9 +582,9 @@ class App(tkinter.Frame):
self.update_info()
key = self.sim.namesord[currsel()]
self.text_view.insert(tkinter.INSERT, \
- "Object: {}\n".format(key))
+ "Alias: {}\n".format(key))
self.text_view.insert(tkinter.INSERT, \
- "Alias: {}\n\n".format(self.sim.names[key]))
+ "Value: {}\n\n".format(self.sim.names[key]))
# search for objects
self.text_view.insert(tkinter.INSERT, \
"Applied for:")
@@ -536,7 +594,7 @@ class App(tkinter.Frame):
"\n ")
def make_cb(idx):
def cb():
- print("TODO: names obj", idx)
+ self.open_object(idx)
return cb
self.text_view.insert(tkinter.INSERT, \
"{} - {}".format(obj.idx, obj.name), \
@@ -546,7 +604,7 @@ class App(tkinter.Frame):
self.update_info()
key = self.sim.invntrord[currsel()]
self.text_view.insert(tkinter.INSERT, \
- "Object: {}\n".format(key))
+ "Invntr: {}\n".format(key))
self.text_view.insert(tkinter.INSERT, \
"{}\n\n".format(self.sim.invntr[key]))
# search for objects
@@ -558,52 +616,36 @@ class App(tkinter.Frame):
"\n ")
def make_cb(idx):
def cb():
- print("TODO: invntr obj", idx)
+ self.open_object(idx)
return cb
self.text_view.insert(tkinter.INSERT, \
"{} - {}".format(obj.idx, obj.name), \
self.text_hl.add(make_cb(obj.idx)))
-
-
def on_open_data(self):
# open data - select TODO
pass
def on_outline(self):
- self.curr_mode = 0
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 0)
def on_list_parts(self):
- self.curr_mode = 90
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 90)
def on_list_res(self):
- self.curr_mode = 100
- self.curr_main = 1
- self.update_gui()
+ self.change_gui(1, 100)
def on_list_objs(self):
- self.curr_mode = 101
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 101)
def on_list_scenes(self):
- self.curr_mode = 102
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 102)
def on_list_names(self):
- self.curr_mode = 103
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 103)
def on_list_invntr(self):
- self.curr_mode = 104
- self.curr_main = 0
- self.update_gui()
+ self.change_gui(0, 104)
def open_data_from(self, folder):
self.sim = petka.Engine()
Commit: b62ea77dc2cfe68d532e65fde66d3b22e98f1092
https://github.com/scummvm/scummvm-tools/commit/b62ea77dc2cfe68d532e65fde66d3b22e98f1092
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Cleanup removed links
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 2ffd1a3ff..a4c20d92f 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,6 +21,7 @@ class HyperlinkManager:
self.text.tag_bind("hyper", "<Leave>", self._leave)
self.text.tag_bind("hyper", "<Button-1>", self._click)
self.reset()
+
def reset(self):
self.links = {}
@@ -374,33 +375,33 @@ class App(tkinter.Frame):
self.update_gui_add_left_listbox("Test info", acts)
elif self.curr_mode == 90:
# list parts
- lb = self.update_gui_add_left_listbox("Parts")
+ lb = self.update_gui_add_left_listbox("Parts")
for part in self.sim.parts:
lb.insert(tkinter.END, part)
elif self.curr_mode == 100:
# list resources
- lb = self.update_gui_add_left_listbox("Resources")
+ lb = self.update_gui_add_left_listbox("Resources")
for res_id in self.sim.resord:
lb.insert(tkinter.END, "{} - {}".format(res_id, \
self.sim.res[res_id]))
elif self.curr_mode == 101:
# list objects
- lb = self.update_gui_add_left_listbox("Objects")
+ lb = self.update_gui_add_left_listbox("Objects")
for obj in self.sim.objects:
lb.insert(tkinter.END, "{} - {}".format(obj.idx, obj.name))
elif self.curr_mode == 102:
# list scenes
- lb = self.update_gui_add_left_listbox("Scenes")
+ lb = self.update_gui_add_left_listbox("Scenes")
for scn in self.sim.scenes:
lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
elif self.curr_mode == 103:
# list names
- lb = self.update_gui_add_left_listbox("Names")
+ lb = self.update_gui_add_left_listbox("Names")
for name in self.sim.namesord:
lb.insert(tkinter.END, "{}".format(name))
elif self.curr_mode == 104:
# list invntr
- lb = self.update_gui_add_left_listbox("Invntr")
+ lb = self.update_gui_add_left_listbox("Invntr")
for name in self.sim.invntrord:
lb.insert(tkinter.END, "{}".format(name))
self.update_info()
@@ -412,7 +413,8 @@ class App(tkinter.Frame):
self.text_view.insert(tkinter.INSERT, "<- Outline", \
self.text_hl.add(self.on_outline))
self.text_view.insert(tkinter.INSERT, "\n\n")
-
+
+ self.text_hl.reset()
if self.curr_mode == 0:
self.text_view.delete(0.0, tkinter.END)
if self.sim is None:
Commit: 4d17a6243e53f9fd6facb90803d3c0dcab6c06d7
https://github.com/scummvm/scummvm-tools/commit/4d17a6243e53f9fd6facb90803d3c0dcab6c06d7
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Cleanup removed links
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index a4c20d92f..3140ec69e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -632,10 +632,10 @@ class App(tkinter.Frame):
self.change_gui(0, 0)
def on_list_parts(self):
- self.change_gui(0, 90)
+ self.change_gui(0, 90)
def on_list_res(self):
- self.change_gui(1, 100)
+ self.change_gui(0, 100)
def on_list_objs(self):
self.change_gui(0, 101)
Commit: 715ed6ef51631ed145a2d7a92ce901030aa1b7cc
https://github.com/scummvm/scummvm-tools/commit/715ed6ef51631ed145a2d7a92ce901030aa1b7cc
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Resource filters
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3140ec69e..9de1f23b4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -65,6 +65,7 @@ class App(tkinter.Frame):
# gui
self.curr_main = 0 # 0 - frame, 1 - canvas
self.curr_mode = 0
+ self.curr_mode_sub = None
self.curr_gui = []
self.curr_lb_acts = None
# canvas
@@ -380,10 +381,19 @@ class App(tkinter.Frame):
lb.insert(tkinter.END, part)
elif self.curr_mode == 100:
# list resources
- lb = self.update_gui_add_left_listbox("Resources")
- for res_id in self.sim.resord:
- lb.insert(tkinter.END, "{} - {}".format(res_id, \
- self.sim.res[res_id]))
+ if self.curr_mode_sub is None:
+ lb = self.update_gui_add_left_listbox("Resources")
+ for res_id in self.sim.resord:
+ lb.insert(tkinter.END, "{} - {}".format(res_id, \
+ self.sim.res[res_id]))
+ else:
+ lb = self.update_gui_add_left_listbox("Resources: {}".\
+ format(self.curr_mode_sub))
+ for res_id in self.sim.resord:
+ if self.sim.res[res_id].upper().endswith\
+ ("." + self.curr_mode_sub):
+ lb.insert(tkinter.END, "{} - {}".format(res_id, \
+ self.sim.res[res_id]))
elif self.curr_mode == 101:
# list objects
lb = self.update_gui_add_left_listbox("Objects")
@@ -453,6 +463,31 @@ class App(tkinter.Frame):
self.text_view.insert(tkinter.INSERT, "{}".\
format(len(self.sim.invntr)), \
self.text_hl.add(self.on_list_invntr))
+ elif self.curr_mode == 100:
+ stdinfo()
+ self.text_view.insert(tkinter.INSERT, "Total: ")
+ self.text_view.insert(tkinter.INSERT, "{}".\
+ format(len(self.sim.res)), \
+ self.text_hl.add(lambda: self.change_gui(0, 100)))
+ self.text_view.insert(tkinter.INSERT, "\nFiletypes:\n")
+ fts = {}
+ for res in self.sim.res.values():
+ fp = res.rfind(".")
+ if fp >= 0:
+ ft = res[fp + 1:].upper()
+ fts[ft] = fts.get(ft, 0) + 1
+ ftk = list(fts.keys())
+ ftk.sort()
+ for ft in ftk:
+ self.text_view.insert(tkinter.INSERT, " ")
+ def make_cb(key):
+ def cb():
+ self.change_gui(0, 100, key)
+ return cb
+ self.text_view.insert(tkinter.INSERT, ft, \
+ self.text_hl.add(make_cb(ft)))
+ self.text_view.insert(tkinter.INSERT, ": {}\n".format(fts[ft]))
+
elif self.curr_mode == 101:
stdinfo()
elif self.curr_mode == 102:
@@ -491,9 +526,10 @@ class App(tkinter.Frame):
self.open_gui_elem(0, 104, idx)
break
- def change_gui(self, main, mode):
+ def change_gui(self, main, mode, sub = None):
self.curr_main = main
self.curr_mode = mode
+ self.curr_mode_sub = sub
self.update_gui()
def on_left_listbox(self, event):
@@ -557,19 +593,21 @@ class App(tkinter.Frame):
# resources
try:
res_id = self.curr_lb.curselection()[0]
+ res_id = self.curr_lb.get(res_id).split("-", 1)[0].strip()
res_id = int(res_id)
except:
pass
- res_id = self.sim.resord[res_id]
fn = self.sim.res[res_id]
if fn[-4:].lower() == ".bmp":
bmpdata = self.sim.fman.read_file(fn)
bmp = petka.BMPLoader()
bmp.load_data(bmpdata)
- self.main_image = self.make_image(bmp.width, bmp.height, bmp.rgb)
+ self.main_image = \
+ self.make_image(bmp.width, bmp.height, bmp.rgb)
self.curr_width = bmp.width
self.curr_height = bmp.height
- self.update_after()
+ self.curr_main = 1
+ self.update_gui()
print(fn)
elif self.curr_mode == 101:
# objects
Commit: 47a787d10e37435e878e8d447ccc164bfe8f651f
https://github.com/scummvm/scummvm-tools/commit/47a787d10e37435e878e8d447ccc164bfe8f651f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor, scene referenced objects
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9de1f23b4..6e5df0a41 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -307,6 +307,11 @@ class App(tkinter.Frame):
self.curr_lb = lb
return lb
+ def make_obj_cb(self, idx):
+ def cb():
+ self.open_object(idx)
+ return cb
+
def update_gui(self):
self.canv_view.delete(tkinter.ALL)
for item in self.curr_gui:
@@ -352,7 +357,8 @@ class App(tkinter.Frame):
def tst_info():
self.change_gui(0, 99)
acts = [
- ("Parts", self.on_list_parts),
+ ("Parts ({})".format(len(self.sim.parts)), \
+ self.on_list_parts),
("Resources ({})".format(len(self.sim.res)), \
self.on_list_res),
("Objects ({})".format(len(self.sim.objects)), \
@@ -417,59 +423,53 @@ class App(tkinter.Frame):
self.update_info()
self.update_after()
+ def insert_text(self, text, link = None):
+ if link:
+ self.text_view.insert(tkinter.INSERT, text, self.text_hl.add(link))
+ else:
+ self.text_view.insert(tkinter.INSERT, text)
+
def update_info(self):
def stdinfo():
self.text_view.delete(0.0, tkinter.END)
- self.text_view.insert(tkinter.INSERT, "<- Outline", \
- self.text_hl.add(self.on_outline))
- self.text_view.insert(tkinter.INSERT, "\n\n")
+ self.insert_text("<- Outline", self.on_outline)
+ self.insert_text("\n\n")
self.text_hl.reset()
if self.curr_mode == 0:
self.text_view.delete(0.0, tkinter.END)
if self.sim is None:
- self.text_view.insert(tkinter.INSERT, "No data loaded")
- self.text_view.insert(tkinter.INSERT, "Open data", \
- self.text_hl.add(self.on_open_data))
+ self.insert_text("No data loaded")
+ self.insert_text("Open data",self.on_open_data)
else:
- self.text_view.insert(tkinter.INSERT, \
- "Select type from outline")
+ self.insert_text("Select type from outline")
elif self.curr_mode == 99:
stdinfo()
for i in range(100):
- self.text_view.insert(tkinter.INSERT, \
- "Item {}\n".format(i))
+ self.insert_text("Item {}\n".format(i))
elif self.curr_mode == 90:
stdinfo()
- self.text_view.insert(tkinter.INSERT, \
- "Current: part {} chapter {}\n\n Resources: ".\
+ self.insert_text("Current: part {} chapter {}\n\n Resources: ".\
format(self.sim.curr_part, self.sim.curr_chap))
- self.text_view.insert(tkinter.INSERT, "{}".\
- format(len(self.sim.res)), \
- self.text_hl.add(self.on_list_res))
- self.text_view.insert(tkinter.INSERT, "\n Objects: ")
- self.text_view.insert(tkinter.INSERT, "{}".\
- format(len(self.sim.objects)), \
- self.text_hl.add(self.on_list_objs))
- self.text_view.insert(tkinter.INSERT, "\n Scenes: ")
- self.text_view.insert(tkinter.INSERT, "{}".\
- format(len(self.sim.scenes)), \
- self.text_hl.add(self.on_list_scenes))
- self.text_view.insert(tkinter.INSERT, "\n Names: ")
- self.text_view.insert(tkinter.INSERT, "{}".\
- format(len(self.sim.names)), \
- self.text_hl.add(self.on_list_names))
- self.text_view.insert(tkinter.INSERT, "\n Invntr: ")
- self.text_view.insert(tkinter.INSERT, "{}".\
- format(len(self.sim.invntr)), \
- self.text_hl.add(self.on_list_invntr))
+ self.insert_text("{}".format(len(self.sim.res)), self.on_list_res)
+ self.insert_text("\n Objects: ")
+ self.insert_text("{}".format(len(self.sim.objects)), \
+ self.on_list_objs)
+ self.insert_text("\n Scenes: ")
+ self.insert_text("{}".format(len(self.sim.scenes)), \
+ self.on_list_scenes)
+ self.insert_text("\n Names: ")
+ self.insert_text("{}".format(len(self.sim.names)), \
+ self.on_list_names)
+ self.insert_text("\n Invntr: ")
+ self.insert_text("{}".format(len(self.sim.invntr)), \
+ self.on_list_invntr)
elif self.curr_mode == 100:
stdinfo()
- self.text_view.insert(tkinter.INSERT, "Total: ")
- self.text_view.insert(tkinter.INSERT, "{}".\
- format(len(self.sim.res)), \
- self.text_hl.add(lambda: self.change_gui(0, 100)))
- self.text_view.insert(tkinter.INSERT, "\nFiletypes:\n")
+ self.insert_text("Total: ")
+ self.insert_text("{}".format(len(self.sim.res)), \
+ lambda: self.change_gui(0, 100))
+ self.insert_text("\nFiletypes:\n")
fts = {}
for res in self.sim.res.values():
fp = res.rfind(".")
@@ -479,14 +479,13 @@ class App(tkinter.Frame):
ftk = list(fts.keys())
ftk.sort()
for ft in ftk:
- self.text_view.insert(tkinter.INSERT, " ")
+ self.insert_text(" ")
def make_cb(key):
def cb():
self.change_gui(0, 100, key)
return cb
- self.text_view.insert(tkinter.INSERT, ft, \
- self.text_hl.add(make_cb(ft)))
- self.text_view.insert(tkinter.INSERT, ": {}\n".format(fts[ft]))
+ self.insert_text(ft, make_cb(ft))
+ self.insert_text(": {}\n".format(fts[ft]))
elif self.curr_mode == 101:
stdinfo()
@@ -542,30 +541,37 @@ class App(tkinter.Frame):
return num
def objinfo(tp, rec):
- self.text_view.insert(tkinter.INSERT, \
- ("Object" if tp else "Scene") + ":\n")
- self.text_view.insert(tkinter.INSERT, \
- " Index: {}\n Name: {}\n".format(rec.idx, rec.name))
+ self.insert_text(("Object" if tp else "Scene") + ":\n")
+ self.insert_text(" Index: {}\n Name: {}\n".\
+ format(rec.idx, rec.name))
if rec.name in self.sim.names:
- self.text_view.insert(tkinter.INSERT, " ")
+ self.insert_text(" ")
def make_cb(key):
def cb():
self.open_name(key)
return cb
- self.text_view.insert(tkinter.INSERT, "Alias", \
- self.text_hl.add(make_cb(rec.name)))
- self.text_view.insert(tkinter.INSERT, \
- ": {}\n".format(self.sim.names[rec.name]))
+ self.insert_text("Alias", make_cb(rec.name))
+ self.insert_text(": {}\n".format(self.sim.names[rec.name]))
if rec.name in self.sim.invntr:
- self.text_view.insert(tkinter.INSERT, " ")
+ self.insert_text(" ")
def make_cb(key):
def cb():
self.open_invntr(key)
return cb
- self.text_view.insert(tkinter.INSERT, "Invntr", \
- self.text_hl.add(make_cb(rec.name)))
- self.text_view.insert(tkinter.INSERT, \
- ": {}\n".format(self.sim.invntr[rec.name]))
+ self.insert_text("Invntr", make_cb(rec.name))
+ self.insert_text(": {}\n".format(self.sim.invntr[rec.name]))
+
+ if not tp:
+ if len(rec.refs) == 0:
+ self.insert_text("\nNo references\n")
+ else:
+ self.insert_text("\nReferences: {}\n".format(len(rec.refs)))
+ for idx, ref in enumerate(rec.refs):
+ self.insert_text(" {}) ".format(idx))
+ self.insert_text("obj_{}".format(ref[0].idx), \
+ self.make_obj_cb(ref[0].idx))
+ self.insert_text("\n".format(idx))
+
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
if act[1]:
@@ -621,46 +627,36 @@ class App(tkinter.Frame):
# names
self.update_info()
key = self.sim.namesord[currsel()]
- self.text_view.insert(tkinter.INSERT, \
- "Alias: {}\n".format(key))
- self.text_view.insert(tkinter.INSERT, \
- "Value: {}\n\n".format(self.sim.names[key]))
+ self.insert_text("Alias: {}\n".format(key))
+ self.insert_text("Value: {}\n\n".format(self.sim.names[key]))
# search for objects
- self.text_view.insert(tkinter.INSERT, \
- "Applied for:")
+ self.insert_text("Applied for:")
for obj in self.sim.objects:
if obj.name == key:
- self.text_view.insert(tkinter.INSERT, \
- "\n ")
+ self.insert_text("\n ")
def make_cb(idx):
def cb():
self.open_object(idx)
return cb
- self.text_view.insert(tkinter.INSERT, \
- "{} - {}".format(obj.idx, obj.name), \
- self.text_hl.add(make_cb(obj.idx)))
+ self.insert_text("{} - {}".format(obj.idx, obj.name), \
+ make_cb(obj.idx))
elif self.curr_mode == 104:
# invntr
self.update_info()
key = self.sim.invntrord[currsel()]
- self.text_view.insert(tkinter.INSERT, \
- "Invntr: {}\n".format(key))
- self.text_view.insert(tkinter.INSERT, \
- "{}\n\n".format(self.sim.invntr[key]))
+ self.insert_text("Invntr: {}\n".format(key))
+ self.insert_text("{}\n\n".format(self.sim.invntr[key]))
# search for objects
- self.text_view.insert(tkinter.INSERT, \
- "Applied for:")
+ self.insert_text("Applied for:")
for obj in self.sim.objects:
if obj.name == key:
- self.text_view.insert(tkinter.INSERT, \
- "\n ")
+ self.insert_text("\n ")
def make_cb(idx):
def cb():
self.open_object(idx)
return cb
- self.text_view.insert(tkinter.INSERT, \
- "{} - {}".format(obj.idx, obj.name), \
- self.text_hl.add(make_cb(obj.idx)))
+ self.insert_text("{} - {}".format(obj.idx, obj.name), \
+ make_cb(obj.idx))
def on_open_data(self):
# open data - select TODO
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 64a5bb77c..9c4a34335 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -216,6 +216,7 @@ class Engine:
f.close()
self.names = {}
+ self.namesord = []
fp = self.curr_path + "names.ini"
if self.fman.exists(fp):
f = self.fman.read_file_stream(fp)
@@ -225,6 +226,7 @@ class Engine:
f.close()
self.invntr = {}
+ self.invntrord = []
fp = self.curr_path + "invntr.txt"
if self.fman.exists(fp):
f = self.fman.read_file_stream(fp)
Commit: 26b39b9aa3d62c348527bf34d5fcc0c54236bab2
https://github.com/scummvm/scummvm-tools/commit/26b39b9aa3d62c348527bf34d5fcc0c54236bab2
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor navigation
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 6e5df0a41..000fb611d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -63,7 +63,10 @@ class App(tkinter.Frame):
self.pad = None
self.sim = None
# gui
+ self.path_handler = {}
self.curr_main = 0 # 0 - frame, 1 - canvas
+ self.curr_path = []
+ self.last_path = None
self.curr_mode = 0
self.curr_mode_sub = None
self.curr_gui = []
@@ -118,8 +121,11 @@ class App(tkinter.Frame):
self.text_hl = HyperlinkManager(self.text_view)
self.text_view.bind('<Configure>', self.on_resize_view)
+ # bind path handlers
+ self.path_handler["parts"] = self.path_parts
+
self.update_after()
- self.update_gui()
+ self.open_path([])
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -140,27 +146,27 @@ class App(tkinter.Frame):
self.menubar.add_cascade(menu = self.menuedit,
label = "Edit")
self.menuedit.add_command(
- command = self.on_outline,
+ command = lambda: self.open_path([]),
label = "Outline")
self.menuedit.add_separator()
self.menuedit.add_command(
- command = self.on_list_parts,
+ command = lambda: self.open_path(["parts"]),
label = "Select part")
self.menuedit.add_separator()
self.menuedit.add_command(
- command = self.on_list_res,
+ command = lambda: self.open_path(["res"]),
label = "Resources")
self.menuedit.add_command(
- command = self.on_list_objs,
+ command = lambda: self.open_path(["objs"]),
label = "Objects")
self.menuedit.add_command(
- command = self.on_list_scenes,
+ command = lambda: self.open_path(["scenes"]),
label = "Scenes")
self.menuedit.add_command(
- command = self.on_list_names,
+ command = lambda: self.open_path(["names"]),
label = "Names")
self.menuedit.add_command(
- command = self.on_list_invntr,
+ command = lambda: self.open_path(["invntr"]),
label = "Invntr")
def update_after(self):
@@ -185,13 +191,19 @@ class App(tkinter.Frame):
self.master.destroy()
def on_mouse_view(self, event):
- #self.currMode += 1
- #if self.currMode > 1:
- # self.currMode = 0
self.update_after()
def on_resize_view(self, event):
self.update_after()
+
+ def open_path(self, path):
+ path = tuple(path)
+ print("DEBUG: Open", path)
+ self.curr_path = path
+ if len(path) > 0:
+ if path[0] in self.path_handler:
+ return self.path_handler[path[0]](path)
+ return self.path_default(path)
def update_canvas(self):
if self.curr_main == 0:
@@ -275,10 +287,21 @@ class App(tkinter.Frame):
data = bytes(p))
return image
- def update_gui_add_left_listbox(self, text, acts = None):
+ def make_obj_cb(self, idx):
+ def cb():
+ self.open_object(idx)
+ return cb
+
+ def update_gui(self, text = "<Undefined>"):
+ self.last_path = self.curr_path
+ self.canv_view.delete(tkinter.ALL)
+ # cleanup
+ for item in self.curr_gui:
+ item()
+ self.curr_gui = []
+ # left listbox
lab = tkinter.Label(self.frm_left, text = text)
lab.pack()
-
frm_lb = ttk.Frame(self.frm_left)
frm_lb.pack(fill = tkinter.BOTH, expand = 1)
frm_lb.grid_rowconfigure(0, weight = 1)
@@ -299,25 +322,10 @@ class App(tkinter.Frame):
self.curr_gui.append(lambda:frm_lb.pack_forget())
lb.bind("<Double-Button-1>", self.on_left_listbox)
lb.bind("<Return>", self.on_left_listbox)
-
- self.curr_lb_acts = acts
- if acts:
- for name, cb in acts:
- lb.insert(tkinter.END, name)
+ # actions on listbox
self.curr_lb = lb
- return lb
-
- def make_obj_cb(self, idx):
- def cb():
- self.open_object(idx)
- return cb
-
- def update_gui(self):
- self.canv_view.delete(tkinter.ALL)
- for item in self.curr_gui:
- item()
- self.curr_gui = []
-
+ self.curr_lb_acts = []
+ # main view
if self.curr_main == 0:
self.canv_view.grid_forget()
self.text_view.grid(row = 0, column = 0, \
@@ -338,43 +346,11 @@ class App(tkinter.Frame):
)
self.scr_view_x.config(command = self.canv_view.xview)
self.scr_view_y.config(command = self.canv_view.yview)
-
+ return
+
+
if self.curr_mode == 0:
- if self.sim is None:
- # open some data
- acts = [
- ("Open data", self.on_open_data)
- ]
- self.update_gui_add_left_listbox("Outline", acts)
- else:
- def tst_img():
- self.curr_main = 1
- self.main_image = tkinter.PhotoImage(\
- file = "img/splash.gif")
- self.curr_width = self.main_image.width()
- self.curr_height = self.main_image.height()
- self.update_gui()
- def tst_info():
- self.change_gui(0, 99)
- acts = [
- ("Parts ({})".format(len(self.sim.parts)), \
- self.on_list_parts),
- ("Resources ({})".format(len(self.sim.res)), \
- self.on_list_res),
- ("Objects ({})".format(len(self.sim.objects)), \
- self.on_list_objs),
- ("Scenes ({})".format(len(self.sim.scenes)), \
- self.on_list_scenes),
- ("Names ({})".format(len(self.sim.names)), \
- self.on_list_names),
- ("Invntr ({})".format(len(self.sim.invntr)), \
- self.on_list_invntr),
- ("-", None),
- ("Test image", tst_img),
- ("Test info", tst_info),
- ]
- self.update_gui_add_left_listbox("Outline: part {} chapter {}".\
- format(self.sim.curr_part, self.sim.curr_chap), acts)
+ pass
elif self.curr_mode == 99:
acts = [
("<- outline", self.on_outline)
@@ -423,12 +399,27 @@ class App(tkinter.Frame):
self.update_info()
self.update_after()
+ def clear_text(self):
+ self.text_view.delete(0.0, tkinter.END)
+
def insert_text(self, text, link = None):
if link:
- self.text_view.insert(tkinter.INSERT, text, self.text_hl.add(link))
+ if callable(link):
+ cb = link
+ else:
+ def make_cb(path):
+ def cb():
+ return self.open_path(path)
+ return cb
+ cb = make_cb(tuple(link))
+ self.text_view.insert(tkinter.INSERT, text, self.text_hl.add(cb))
else:
self.text_view.insert(tkinter.INSERT, text)
+ def insert_lb_act(self, name, act):
+ self.curr_lb_acts.append((name, act))
+ self.curr_lb.insert(tkinter.END, name)
+
def update_info(self):
def stdinfo():
self.text_view.delete(0.0, tkinter.END)
@@ -449,21 +440,6 @@ class App(tkinter.Frame):
self.insert_text("Item {}\n".format(i))
elif self.curr_mode == 90:
stdinfo()
- self.insert_text("Current: part {} chapter {}\n\n Resources: ".\
- format(self.sim.curr_part, self.sim.curr_chap))
- self.insert_text("{}".format(len(self.sim.res)), self.on_list_res)
- self.insert_text("\n Objects: ")
- self.insert_text("{}".format(len(self.sim.objects)), \
- self.on_list_objs)
- self.insert_text("\n Scenes: ")
- self.insert_text("{}".format(len(self.sim.scenes)), \
- self.on_list_scenes)
- self.insert_text("\n Names: ")
- self.insert_text("{}".format(len(self.sim.names)), \
- self.on_list_names)
- self.insert_text("\n Invntr: ")
- self.insert_text("{}".format(len(self.sim.invntr)), \
- self.on_list_invntr)
elif self.curr_mode == 100:
stdinfo()
self.insert_text("Total: ")
@@ -575,26 +551,11 @@ class App(tkinter.Frame):
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
if act[1]:
- act[1]()
- elif self.curr_mode == 90:
- # parts
- try:
- part_id = self.curr_lb.curselection()[0]
- part_id = int(part_id)
- except:
- pass
- part_id = self.sim.parts[part_id]
- # parse
- pnum = part_id[5:]
- cnum = pnum.split("Chapter", 1)
- if len(cnum) > 1:
- pnum = int(cnum[0].strip(), 10)
- cnum = int(cnum[1].strip(), 10)
- else:
- cnum = 0
- self.sim.open_part(pnum, cnum)
- self.update_info()
- self.update_after()
+ self.open_path(act[1])
+ return
+
+ if self.curr_mode == 90:
+ pass
elif self.curr_mode == 100:
# resources
try:
@@ -658,31 +619,83 @@ class App(tkinter.Frame):
self.insert_text("{} - {}".format(obj.idx, obj.name), \
make_cb(obj.idx))
+ def path_default(self, path):
+ self.curr_main = 0
+ self.update_gui("Outline")
+ self.clear_text()
+ if len(path) != 0:
+ spath = ""
+ for item in path:
+ spath += "/" + str(item)
+ self.insert_text("Path {} not found\n\n".format(spath))
+ self.insert_text("Select from outline\n")
+ if self.sim is not None:
+ def tst_img():
+ self.curr_main = 1
+ self.main_image = tkinter.PhotoImage(\
+ file = "img/splash.gif")
+ self.curr_width = self.main_image.width()
+ self.curr_height = self.main_image.height()
+ self.update_gui()
+ def tst_info():
+ self.change_gui(0, 99)
+ acts = [
+ ("Parts ({})".format(len(self.sim.parts)), ["parts"]),
+ ("Resources ({})".format(len(self.sim.res)), ["res"]),
+ ("Objects ({})".format(len(self.sim.objects)), ["objs"]),
+ ("Scenes ({})".format(len(self.sim.scenes)), ["scenes"]),
+ ("Names ({})".format(len(self.sim.names)), ["names"]),
+ ("Invntr ({})".format(len(self.sim.invntr)), ["invntr"]),
+ ("-", None),
+ ("Test image", ["tst_image"]),
+ ("Test info", ["tst_info"]),
+ ]
+ for name, act in acts:
+ self.insert_lb_act(name, act)
+
+ def path_parts(self, path):
+ self.curr_main = 0
+ if len(self.last_path) == 0 or self.last_path[0] != "parts":
+ self.update_gui("Parts ({})".format(len(self.sim.parts)))
+ for idx, name in enumerate(self.sim.parts):
+ self.insert_lb_act(name, ["parts", idx])
+ # change
+ if len(path) > 1:
+ # parts
+ try:
+ part_id = self.curr_lb.curselection()[0]
+ part_id = int(part_id)
+ except:
+ pass
+ part_id = self.sim.parts[part_id]
+ # parse
+ pnum = part_id[5:]
+ cnum = pnum.split("Chapter", 1)
+ if len(cnum) > 1:
+ pnum = int(cnum[0].strip(), 10)
+ cnum = int(cnum[1].strip(), 10)
+ else:
+ cnum = 0
+ self.sim.open_part(pnum, cnum)
+ # display
+ self.clear_text()
+ self.insert_text("Current: part {} chapter {}\n\n Resources: ".\
+ format(self.sim.curr_part, self.sim.curr_chap))
+ self.insert_text("{}".format(len(self.sim.res)), ["res"])
+ self.insert_text("\n Objects: ")
+ self.insert_text("{}".format(len(self.sim.objects)), ["objs"])
+ self.insert_text("\n Scenes: ")
+ self.insert_text("{}".format(len(self.sim.scenes)), ["scenes"])
+ self.insert_text("\n Names: ")
+ self.insert_text("{}".format(len(self.sim.names)), ["names"])
+ self.insert_text("\n Invntr: ")
+ self.insert_text("{}".format(len(self.sim.invntr)), ["invntr"])
+ #
+
def on_open_data(self):
# open data - select TODO
pass
- def on_outline(self):
- self.change_gui(0, 0)
-
- def on_list_parts(self):
- self.change_gui(0, 90)
-
- def on_list_res(self):
- self.change_gui(0, 100)
-
- def on_list_objs(self):
- self.change_gui(0, 101)
-
- def on_list_scenes(self):
- self.change_gui(0, 102)
-
- def on_list_names(self):
- self.change_gui(0, 103)
-
- def on_list_invntr(self):
- self.change_gui(0, 104)
-
def open_data_from(self, folder):
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
Commit: 9b4d47482c734a6ef77f9470dde18cd081888059
https://github.com/scummvm/scummvm-tools/commit/9b4d47482c734a6ef77f9470dde18cd081888059
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor: objects, scenes, parts workss again
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 000fb611d..ef56d013e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -123,6 +123,8 @@ class App(tkinter.Frame):
# bind path handlers
self.path_handler["parts"] = self.path_parts
+ self.path_handler["objs"] = self.path_objs_scenes
+ self.path_handler["scenes"] = self.path_objs_scenes
self.update_after()
self.open_path([])
@@ -469,43 +471,16 @@ class App(tkinter.Frame):
stdinfo()
else:
stdinfo()
-
- def open_gui_elem(self, main, mode, idx):
- if self.curr_mode != mode:
- self.change_gui(main, mode)
- self.curr_lb.selection_set(idx)
- self.curr_lb.see(idx)
- self.on_left_listbox(None)
-
- def open_object(self, obj_id):
- for idx, obj in enumerate(self.sim.objects):
- if obj.idx == obj_id:
- self.open_gui_elem(0, 101, idx)
- break
-
- def open_scene(self, scn_id):
- for idx, obj in enumerate(self.sim.scenes):
- if obj.idx == scn_id:
- self.open_gui_elem(0, 102, idx)
- break
-
- def open_name(self, name_key):
- for idx, key in enumerate(self.sim.namesord):
- if key == name_key:
- self.open_gui_elem(0, 103, idx)
- break
-
- def open_invntr(self, inv_key):
- for idx, key in enumerate(self.sim.invntrord):
- if key == inv_key:
- self.open_gui_elem(0, 104, idx)
- break
-
- def change_gui(self, main, mode, sub = None):
- self.curr_main = main
- self.curr_mode = mode
- self.curr_mode_sub = sub
- self.update_gui()
+
+ def select_lb_item(self, idx):
+ try:
+ num = self.curr_lb.curselection()[0]
+ num = int(num)
+ except:
+ num = -1
+ if idx != num:
+ self.curr_lb.selection_set(idx)
+ self.curr_lb.see(idx)
def on_left_listbox(self, event):
def currsel():
@@ -517,37 +492,7 @@ class App(tkinter.Frame):
return num
def objinfo(tp, rec):
- self.insert_text(("Object" if tp else "Scene") + ":\n")
- self.insert_text(" Index: {}\n Name: {}\n".\
- format(rec.idx, rec.name))
- if rec.name in self.sim.names:
- self.insert_text(" ")
- def make_cb(key):
- def cb():
- self.open_name(key)
- return cb
- self.insert_text("Alias", make_cb(rec.name))
- self.insert_text(": {}\n".format(self.sim.names[rec.name]))
- if rec.name in self.sim.invntr:
- self.insert_text(" ")
- def make_cb(key):
- def cb():
- self.open_invntr(key)
- return cb
- self.insert_text("Invntr", make_cb(rec.name))
- self.insert_text(": {}\n".format(self.sim.invntr[rec.name]))
-
- if not tp:
- if len(rec.refs) == 0:
- self.insert_text("\nNo references\n")
- else:
- self.insert_text("\nReferences: {}\n".format(len(rec.refs)))
- for idx, ref in enumerate(rec.refs):
- self.insert_text(" {}) ".format(idx))
- self.insert_text("obj_{}".format(ref[0].idx), \
- self.make_obj_cb(ref[0].idx))
- self.insert_text("\n".format(idx))
-
+ pass
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
if act[1]:
@@ -619,6 +564,30 @@ class App(tkinter.Frame):
self.insert_text("{} - {}".format(obj.idx, obj.name), \
make_cb(obj.idx))
+ def find_path_obj(self, obj_idx):
+ for idx, rec in enumerate(self.sim.objects):
+ if rec.idx == obj_idx:
+ return ["objs", idx]
+ return ["no_obj", obj_idx]
+
+ def find_path_scene(self, scn_idx):
+ for idx, rec in enumerate(self.sim.scenes):
+ if rec.idx == scn_idx:
+ return ["scenes", idx]
+ return ["no_scene", scn_idx]
+
+ def find_path_name(self, key):
+ for idx, name in enumerate(self.sim.names):
+ if name == key:
+ return ["names", idx]
+ return ["no_name", key]
+
+ def find_path_invntr(self, key):
+ for idx, name in enumerate(self.sim.invntr):
+ if name == key:
+ return ["invntr", idx]
+ return ["no_invntr", key]
+
def path_default(self, path):
self.curr_main = 0
self.update_gui("Outline")
@@ -662,12 +631,8 @@ class App(tkinter.Frame):
# change
if len(path) > 1:
# parts
- try:
- part_id = self.curr_lb.curselection()[0]
- part_id = int(part_id)
- except:
- pass
- part_id = self.sim.parts[part_id]
+ self.select_lb_item(path[1])
+ part_id = self.sim.parts[path[1]]
# parse
pnum = part_id[5:]
cnum = pnum.split("Chapter", 1)
@@ -690,7 +655,58 @@ class App(tkinter.Frame):
self.insert_text("{}".format(len(self.sim.names)), ["names"])
self.insert_text("\n Invntr: ")
self.insert_text("{}".format(len(self.sim.invntr)), ["invntr"])
- #
+
+ def path_objs_scenes(self, path):
+ self.curr_main = 0
+ isobj = (self.curr_path[0] == "objs")
+ if isobj:
+ lst = self.sim.objects
+ else:
+ lst = self.sim.scenes
+ if len(self.last_path) == 0 or self.last_path[0] != self.curr_path[0]:
+ if isobj:
+ self.update_gui("Objects ({})".format(len(lst)))
+ else:
+ self.update_gui("Scenes ({})".format(len(lst)))
+ for idx, rec in enumerate(lst):
+ self.insert_lb_act("{} - {}".format(rec.idx, rec.name), \
+ [self.curr_path[0], idx])
+ # change
+ rec = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ rec = lst[path[1]]
+ # display
+ self.clear_text()
+ if not rec:
+ self.insert_text("Select item from list\n")
+ else:
+ # record info
+ self.insert_text(("Object" if isobj else "Scene") + ":\n")
+ self.insert_text(" Index: {}\n Name: {}\n".\
+ format(rec.idx, rec.name))
+ if rec.name in self.sim.names:
+ self.insert_text(" ")
+ self.insert_text("Alias", self.find_path_name(rec.name))
+ self.insert_text(": {}\n".format(self.sim.names[rec.name]))
+ if rec.name in self.sim.invntr:
+ self.insert_text(" ")
+ self.insert_text("Invntr", self.find_path_invntr(rec.name))
+ self.insert_text(": {}\n".format(self.sim.invntr[rec.name]))
+
+ if not isobj:
+ if len(rec.refs) == 0:
+ self.insert_text("\nNo references\n")
+ else:
+ self.insert_text("\nReferences: {}\n".format(len(rec.refs)))
+ for idx, ref in enumerate(rec.refs):
+ self.insert_text(" {}) ".format(idx))
+ self.insert_text("obj_{}".format(ref[0].idx), \
+ self.find_path_obj(ref[0].idx))
+ self.insert_text("\n".format(idx))
+
+
def on_open_data(self):
# open data - select TODO
Commit: 4b7bd0f01682e4f2d31bdf9d614a9ea130064714
https://github.com/scummvm/scummvm-tools/commit/4b7bd0f01682e4f2d31bdf9d614a9ea130064714
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor: names and invntr works
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ef56d013e..9c74eddda 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -125,6 +125,8 @@ class App(tkinter.Frame):
self.path_handler["parts"] = self.path_parts
self.path_handler["objs"] = self.path_objs_scenes
self.path_handler["scenes"] = self.path_objs_scenes
+ self.path_handler["names"] = self.path_names
+ self.path_handler["invntr"] = self.path_invntr
self.update_after()
self.open_path([])
@@ -464,11 +466,7 @@ class App(tkinter.Frame):
return cb
self.insert_text(ft, make_cb(ft))
self.insert_text(": {}\n".format(fts[ft]))
-
- elif self.curr_mode == 101:
- stdinfo()
- elif self.curr_mode == 102:
- stdinfo()
+
else:
stdinfo()
@@ -521,48 +519,7 @@ class App(tkinter.Frame):
self.curr_main = 1
self.update_gui()
print(fn)
- elif self.curr_mode == 101:
- # objects
- self.update_info()
- objinfo(True, self.sim.objects[currsel()])
- elif self.curr_mode == 102:
- # scenes
- self.update_info()
- objinfo(False, self.sim.scenes[currsel()])
- elif self.curr_mode == 103:
- # names
- self.update_info()
- key = self.sim.namesord[currsel()]
- self.insert_text("Alias: {}\n".format(key))
- self.insert_text("Value: {}\n\n".format(self.sim.names[key]))
- # search for objects
- self.insert_text("Applied for:")
- for obj in self.sim.objects:
- if obj.name == key:
- self.insert_text("\n ")
- def make_cb(idx):
- def cb():
- self.open_object(idx)
- return cb
- self.insert_text("{} - {}".format(obj.idx, obj.name), \
- make_cb(obj.idx))
- elif self.curr_mode == 104:
- # invntr
- self.update_info()
- key = self.sim.invntrord[currsel()]
- self.insert_text("Invntr: {}\n".format(key))
- self.insert_text("{}\n\n".format(self.sim.invntr[key]))
- # search for objects
- self.insert_text("Applied for:")
- for obj in self.sim.objects:
- if obj.name == key:
- self.insert_text("\n ")
- def make_cb(idx):
- def cb():
- self.open_object(idx)
- return cb
- self.insert_text("{} - {}".format(obj.idx, obj.name), \
- make_cb(obj.idx))
+
def find_path_obj(self, obj_idx):
for idx, rec in enumerate(self.sim.objects):
@@ -577,13 +534,13 @@ class App(tkinter.Frame):
return ["no_scene", scn_idx]
def find_path_name(self, key):
- for idx, name in enumerate(self.sim.names):
+ for idx, name in enumerate(self.sim.namesord):
if name == key:
return ["names", idx]
return ["no_name", key]
def find_path_invntr(self, key):
- for idx, name in enumerate(self.sim.invntr):
+ for idx, name in enumerate(self.sim.invntrord):
if name == key:
return ["invntr", idx]
return ["no_invntr", key]
@@ -695,18 +652,83 @@ class App(tkinter.Frame):
self.insert_text("Invntr", self.find_path_invntr(rec.name))
self.insert_text(": {}\n".format(self.sim.invntr[rec.name]))
- if not isobj:
+ if isobj:
+ # search where object used
+ self.insert_text("\nUsed in:\n")
+ for scn in self.sim.scenes:
+ for ref in scn.refs:
+ if ref[0].idx == rec.idx:
+ self.insert_text(" ")
+ self.insert_text("{}".format(scn.idx), \
+ self.find_path_scene(scn.idx))
+ self.insert_text(" - {}\n".format(scn.name))
+ break
+ else:
if len(rec.refs) == 0:
self.insert_text("\nNo references\n")
else:
self.insert_text("\nReferences: {}\n".format(len(rec.refs)))
for idx, ref in enumerate(rec.refs):
self.insert_text(" {}) ".format(idx))
- self.insert_text("obj_{}".format(ref[0].idx), \
+ self.insert_text("{}".format(ref[0].idx), \
self.find_path_obj(ref[0].idx))
- self.insert_text("\n".format(idx))
-
+ self.insert_text(" - {}\n".format(ref[0].name))
+ def path_names(self, path):
+ self.curr_main = 0
+ if len(self.last_path) == 0 or self.last_path[0] != "names":
+ self.update_gui("Names ({})".format(len(self.sim.names)))
+ for idx, name in enumerate(self.sim.namesord):
+ self.insert_lb_act(name, ["names", idx])
+ # change
+ name = None
+ if len(path) > 1:
+ # parts
+ self.select_lb_item(path[1])
+ name = self.sim.namesord[path[1]]
+ # display
+ self.clear_text()
+ if not name:
+ self.insert_text("Select name from list\n")
+ else:
+ # name info
+ self.insert_text("Alias: {}\n".format(name))
+ self.insert_text("Value: {}\n\n".format(self.sim.names[name]))
+ # search for objects
+ self.insert_text("Applied for:\n")
+ for idx, obj in enumerate(self.sim.objects):
+ if obj.name == name:
+ self.insert_text(" ")
+ self.insert_text("{}".format(obj.idx), ["objs", idx])
+ self.insert_text(" - {}\n".format(obj.name))
+
+ def path_invntr(self, path):
+ self.curr_main = 0
+ if len(self.last_path) == 0 or self.last_path[0] != "invntr":
+ self.update_gui("Invntr ({})".format(len(self.sim.invntr)))
+ for idx, name in enumerate(self.sim.invntrord):
+ self.insert_lb_act(name, ["invntr", idx])
+ # change
+ name = None
+ if len(path) > 1:
+ # parts
+ self.select_lb_item(path[1])
+ name = self.sim.invntrord[path[1]]
+ # display
+ self.clear_text()
+ if not name:
+ self.insert_text("Select invntr from list\n")
+ else:
+ # invntr info
+ self.insert_text("Invntr: {}\n".format(name))
+ self.insert_text("{}\n\n".format(self.sim.invntr[name]))
+ # search for objects
+ self.insert_text("Applied for:\n")
+ for idx, obj in enumerate(self.sim.objects):
+ if obj.name == name:
+ self.insert_text(" ")
+ self.insert_text("{}".format(obj.idx), ["objs", idx])
+ self.insert_text(" - {}\n".format(obj.name))
def on_open_data(self):
# open data - select TODO
Commit: 0c54fa10a25d67c70730e0b1c5e7a51452a2ed8d
https://github.com/scummvm/scummvm-tools/commit/0c54fa10a25d67c70730e0b1c5e7a51452a2ed8d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor: names and invntr works
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9c74eddda..3c2afae8f 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -123,10 +123,12 @@ class App(tkinter.Frame):
# bind path handlers
self.path_handler["parts"] = self.path_parts
+ self.path_handler["res"] = self.path_res
self.path_handler["objs"] = self.path_objs_scenes
self.path_handler["scenes"] = self.path_objs_scenes
self.path_handler["names"] = self.path_names
self.path_handler["invntr"] = self.path_invntr
+ self.path_handler["test"] = self.path_test
self.update_after()
self.open_path([])
@@ -380,28 +382,6 @@ class App(tkinter.Frame):
("." + self.curr_mode_sub):
lb.insert(tkinter.END, "{} - {}".format(res_id, \
self.sim.res[res_id]))
- elif self.curr_mode == 101:
- # list objects
- lb = self.update_gui_add_left_listbox("Objects")
- for obj in self.sim.objects:
- lb.insert(tkinter.END, "{} - {}".format(obj.idx, obj.name))
- elif self.curr_mode == 102:
- # list scenes
- lb = self.update_gui_add_left_listbox("Scenes")
- for scn in self.sim.scenes:
- lb.insert(tkinter.END, "{} - {}".format(scn.idx, scn.name))
- elif self.curr_mode == 103:
- # list names
- lb = self.update_gui_add_left_listbox("Names")
- for name in self.sim.namesord:
- lb.insert(tkinter.END, "{}".format(name))
- elif self.curr_mode == 104:
- # list invntr
- lb = self.update_gui_add_left_listbox("Invntr")
- for name in self.sim.invntrord:
- lb.insert(tkinter.END, "{}".format(name))
- self.update_info()
- self.update_after()
def clear_text(self):
self.text_view.delete(0.0, tkinter.END)
Commit: 6cad232811e7102869c8d81ca824be9400176a39
https://github.com/scummvm/scummvm-tools/commit/6cad232811e7102869c8d81ca824be9400176a39
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor: test image and info panel
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3c2afae8f..28063d81a 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -473,7 +473,7 @@ class App(tkinter.Frame):
pass
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
- if act[1]:
+ if act[1] is not None:
self.open_path(act[1])
return
@@ -536,15 +536,6 @@ class App(tkinter.Frame):
self.insert_text("Path {} not found\n\n".format(spath))
self.insert_text("Select from outline\n")
if self.sim is not None:
- def tst_img():
- self.curr_main = 1
- self.main_image = tkinter.PhotoImage(\
- file = "img/splash.gif")
- self.curr_width = self.main_image.width()
- self.curr_height = self.main_image.height()
- self.update_gui()
- def tst_info():
- self.change_gui(0, 99)
acts = [
("Parts ({})".format(len(self.sim.parts)), ["parts"]),
("Resources ({})".format(len(self.sim.res)), ["res"]),
@@ -553,8 +544,8 @@ class App(tkinter.Frame):
("Names ({})".format(len(self.sim.names)), ["names"]),
("Invntr ({})".format(len(self.sim.invntr)), ["invntr"]),
("-", None),
- ("Test image", ["tst_image"]),
- ("Test info", ["tst_info"]),
+ ("Test image", ["test", "image"]),
+ ("Test info", ["test","info"]),
]
for name, act in acts:
self.insert_lb_act(name, act)
@@ -593,6 +584,9 @@ class App(tkinter.Frame):
self.insert_text("\n Invntr: ")
self.insert_text("{}".format(len(self.sim.invntr)), ["invntr"])
+ def path_res(self, path):
+ pass
+
def path_objs_scenes(self, path):
self.curr_main = 0
isobj = (self.curr_path[0] == "objs")
@@ -710,6 +704,26 @@ class App(tkinter.Frame):
self.insert_text("{}".format(obj.idx), ["objs", idx])
self.insert_text(" - {}\n".format(obj.name))
+ def path_test(self, path):
+ if path[1] == "image":
+ self.curr_main = 1
+ self.main_image = tkinter.PhotoImage(\
+ file = "img/splash.gif")
+ self.curr_width = self.main_image.width()
+ self.curr_height = self.main_image.height()
+ else:
+ self.curr_main = 0
+ self.update_gui("Test {}".format(path[1]))
+ self.insert_lb_act("Outline", [])
+ self.insert_lb_act("-", None)
+ for i in range(15):
+ self.insert_lb_act("{} #{}".format(path[1], i), path[:2] + (i,))
+ if path[1] != "image":
+ self.clear_text()
+ for i in range(100):
+ self.insert_text(" Item {}\n".format(i))
+
+
def on_open_data(self):
# open data - select TODO
pass
Commit: b7adac730204a60eac4ea19e4ede8807260ab3b8
https://github.com/scummvm/scummvm-tools/commit/b7adac730204a60eac4ea19e4ede8807260ab3b8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor: switch info and canvas
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 28063d81a..763c7f66a 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -64,7 +64,7 @@ class App(tkinter.Frame):
self.sim = None
# gui
self.path_handler = {}
- self.curr_main = 0 # 0 - frame, 1 - canvas
+ self.curr_main = -1 # 0 - frame, 1 - canvas
self.curr_path = []
self.last_path = None
self.curr_mode = 0
@@ -300,7 +300,6 @@ class App(tkinter.Frame):
def update_gui(self, text = "<Undefined>"):
self.last_path = self.curr_path
- self.canv_view.delete(tkinter.ALL)
# cleanup
for item in self.curr_gui:
item()
@@ -331,8 +330,13 @@ class App(tkinter.Frame):
# actions on listbox
self.curr_lb = lb
self.curr_lb_acts = []
+
+ def switch_view(self, main):
# main view
- if self.curr_main == 0:
+ if main == self.curr_main: return
+ self.curr_main = main
+ if main == 0:
+ self.canv_view.delete(tkinter.ALL)
self.canv_view.grid_forget()
self.text_view.grid(row = 0, column = 0, \
sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
@@ -343,6 +347,7 @@ class App(tkinter.Frame):
self.scr_view_x.config(command = self.text_view.xview)
self.scr_view_y.config(command = self.text_view.yview)
else:
+ self.canv_view.delete(tkinter.ALL)
self.text_view.grid_forget()
self.canv_view.grid(row = 0, column = 0, \
sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
@@ -352,36 +357,6 @@ class App(tkinter.Frame):
)
self.scr_view_x.config(command = self.canv_view.xview)
self.scr_view_y.config(command = self.canv_view.yview)
- return
-
-
- if self.curr_mode == 0:
- pass
- elif self.curr_mode == 99:
- acts = [
- ("<- outline", self.on_outline)
- ]
- self.update_gui_add_left_listbox("Test info", acts)
- elif self.curr_mode == 90:
- # list parts
- lb = self.update_gui_add_left_listbox("Parts")
- for part in self.sim.parts:
- lb.insert(tkinter.END, part)
- elif self.curr_mode == 100:
- # list resources
- if self.curr_mode_sub is None:
- lb = self.update_gui_add_left_listbox("Resources")
- for res_id in self.sim.resord:
- lb.insert(tkinter.END, "{} - {}".format(res_id, \
- self.sim.res[res_id]))
- else:
- lb = self.update_gui_add_left_listbox("Resources: {}".\
- format(self.curr_mode_sub))
- for res_id in self.sim.resord:
- if self.sim.res[res_id].upper().endswith\
- ("." + self.curr_mode_sub):
- lb.insert(tkinter.END, "{} - {}".format(res_id, \
- self.sim.res[res_id]))
def clear_text(self):
self.text_view.delete(0.0, tkinter.END)
@@ -526,7 +501,7 @@ class App(tkinter.Frame):
return ["no_invntr", key]
def path_default(self, path):
- self.curr_main = 0
+ self.switch_view(0)
self.update_gui("Outline")
self.clear_text()
if len(path) != 0:
@@ -551,7 +526,7 @@ class App(tkinter.Frame):
self.insert_lb_act(name, act)
def path_parts(self, path):
- self.curr_main = 0
+ self.switch_view(0)
if len(self.last_path) == 0 or self.last_path[0] != "parts":
self.update_gui("Parts ({})".format(len(self.sim.parts)))
for idx, name in enumerate(self.sim.parts):
@@ -586,9 +561,23 @@ class App(tkinter.Frame):
def path_res(self, path):
pass
+ # list resources
+ if self.curr_mode_sub is None:
+ lb = self.update_gui_add_left_listbox("Resources")
+ for res_id in self.sim.resord:
+ lb.insert(tkinter.END, "{} - {}".format(res_id, \
+ self.sim.res[res_id]))
+ else:
+ lb = self.update_gui_add_left_listbox("Resources: {}".\
+ format(self.curr_mode_sub))
+ for res_id in self.sim.resord:
+ if self.sim.res[res_id].upper().endswith\
+ ("." + self.curr_mode_sub):
+ lb.insert(tkinter.END, "{} - {}".format(res_id, \
+ self.sim.res[res_id]))
def path_objs_scenes(self, path):
- self.curr_main = 0
+ self.switch_view(0)
isobj = (self.curr_path[0] == "objs")
if isobj:
lst = self.sim.objects
@@ -649,7 +638,7 @@ class App(tkinter.Frame):
self.insert_text(" - {}\n".format(ref[0].name))
def path_names(self, path):
- self.curr_main = 0
+ self.switch_view(0)
if len(self.last_path) == 0 or self.last_path[0] != "names":
self.update_gui("Names ({})".format(len(self.sim.names)))
for idx, name in enumerate(self.sim.namesord):
@@ -677,7 +666,7 @@ class App(tkinter.Frame):
self.insert_text(" - {}\n".format(obj.name))
def path_invntr(self, path):
- self.curr_main = 0
+ self.switch_view(0)
if len(self.last_path) == 0 or self.last_path[0] != "invntr":
self.update_gui("Invntr ({})".format(len(self.sim.invntr)))
for idx, name in enumerate(self.sim.invntrord):
@@ -706,13 +695,13 @@ class App(tkinter.Frame):
def path_test(self, path):
if path[1] == "image":
- self.curr_main = 1
+ self.switch_view(1)
self.main_image = tkinter.PhotoImage(\
file = "img/splash.gif")
self.curr_width = self.main_image.width()
self.curr_height = self.main_image.height()
else:
- self.curr_main = 0
+ self.switch_view(0)
self.update_gui("Test {}".format(path[1]))
self.insert_lb_act("Outline", [])
self.insert_lb_act("-", None)
@@ -723,7 +712,6 @@ class App(tkinter.Frame):
for i in range(100):
self.insert_text(" Item {}\n".format(i))
-
def on_open_data(self):
# open data - select TODO
pass
Commit: 72bf691b391cac206dcdb83f7bfac82c98124158
https://github.com/scummvm/scummvm-tools/commit/72bf691b391cac206dcdb83f7bfac82c98124158
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor: resources works (filter and all list)
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 763c7f66a..9e34673ac 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -7,6 +7,7 @@ import sys, os
import tkinter
from tkinter import ttk, font
from idlelib.WidgetRedirector import WidgetRedirector
+import traceback
import petka
@@ -292,12 +293,7 @@ class App(tkinter.Frame):
image = tkinter.PhotoImage(width = width, height = height, \
data = bytes(p))
return image
-
- def make_obj_cb(self, idx):
- def cb():
- self.open_object(idx)
- return cb
-
+
def update_gui(self, text = "<Undefined>"):
self.last_path = self.curr_path
# cleanup
@@ -379,52 +375,6 @@ class App(tkinter.Frame):
self.curr_lb_acts.append((name, act))
self.curr_lb.insert(tkinter.END, name)
- def update_info(self):
- def stdinfo():
- self.text_view.delete(0.0, tkinter.END)
- self.insert_text("<- Outline", self.on_outline)
- self.insert_text("\n\n")
-
- self.text_hl.reset()
- if self.curr_mode == 0:
- self.text_view.delete(0.0, tkinter.END)
- if self.sim is None:
- self.insert_text("No data loaded")
- self.insert_text("Open data",self.on_open_data)
- else:
- self.insert_text("Select type from outline")
- elif self.curr_mode == 99:
- stdinfo()
- for i in range(100):
- self.insert_text("Item {}\n".format(i))
- elif self.curr_mode == 90:
- stdinfo()
- elif self.curr_mode == 100:
- stdinfo()
- self.insert_text("Total: ")
- self.insert_text("{}".format(len(self.sim.res)), \
- lambda: self.change_gui(0, 100))
- self.insert_text("\nFiletypes:\n")
- fts = {}
- for res in self.sim.res.values():
- fp = res.rfind(".")
- if fp >= 0:
- ft = res[fp + 1:].upper()
- fts[ft] = fts.get(ft, 0) + 1
- ftk = list(fts.keys())
- ftk.sort()
- for ft in ftk:
- self.insert_text(" ")
- def make_cb(key):
- def cb():
- self.change_gui(0, 100, key)
- return cb
- self.insert_text(ft, make_cb(ft))
- self.insert_text(": {}\n".format(fts[ft]))
-
- else:
- stdinfo()
-
def select_lb_item(self, idx):
try:
num = self.curr_lb.curselection()[0]
@@ -444,36 +394,10 @@ class App(tkinter.Frame):
pass
return num
- def objinfo(tp, rec):
- pass
if self.curr_lb_acts:
act = self.curr_lb_acts[currsel()]
if act[1] is not None:
self.open_path(act[1])
- return
-
- if self.curr_mode == 90:
- pass
- elif self.curr_mode == 100:
- # resources
- try:
- res_id = self.curr_lb.curselection()[0]
- res_id = self.curr_lb.get(res_id).split("-", 1)[0].strip()
- res_id = int(res_id)
- except:
- pass
- fn = self.sim.res[res_id]
- if fn[-4:].lower() == ".bmp":
- bmpdata = self.sim.fman.read_file(fn)
- bmp = petka.BMPLoader()
- bmp.load_data(bmpdata)
- self.main_image = \
- self.make_image(bmp.width, bmp.height, bmp.rgb)
- self.curr_width = bmp.width
- self.curr_height = bmp.height
- self.curr_main = 1
- self.update_gui()
- print(fn)
def find_path_obj(self, obj_idx):
@@ -527,7 +451,7 @@ class App(tkinter.Frame):
def path_parts(self, path):
self.switch_view(0)
- if len(self.last_path) == 0 or self.last_path[0] != "parts":
+ if self.last_path[:1] != ("parts",):
self.update_gui("Parts ({})".format(len(self.sim.parts)))
for idx, name in enumerate(self.sim.parts):
self.insert_lb_act(name, ["parts", idx])
@@ -560,6 +484,31 @@ class App(tkinter.Frame):
self.insert_text("{}".format(len(self.sim.invntr)), ["invntr"])
def path_res(self, path):
+ # res - full list
+ # res/flt/<ext> - list by <ext>
+ # res/all/<id> - display res by id
+ if path == ("res",):
+ path = ("res", "all")
+ if path[1] == "flt":
+ return self.path_res_flt(path)
+ elif path[1] == "all":
+ return self.path_res_all(path)
+ else:
+ return self.path_default()
+
+
+ if self.last_path[:2] != path[:2]:
+ #
+ self.switch_view(0)
+ self.update_gui("Resources: {}".format(path[2]))
+ for idx,res_id in self.sim.resord:
+ if self.sim.res[res_id].upper().endswith("." + path[2]):
+ self.insert_lb_act("{} - {}".format(res_id))
+
+ if len(self.last_path) == 0 or self.last_path[0] != "res":
+ for idx, name in enumerate(self.sim.invntrord):
+ self.insert_lb_act(name, ["invntr", idx])
+
pass
# list resources
if self.curr_mode_sub is None:
@@ -576,6 +525,83 @@ class App(tkinter.Frame):
lb.insert(tkinter.END, "{} - {}".format(res_id, \
self.sim.res[res_id]))
+ def path_res_open(self, res_id):
+ fn = self.sim.res[res_id]
+ if fn[-4:].lower() == ".bmp":
+ try:
+ bmpdata = self.sim.fman.read_file(fn)
+ bmp = petka.BMPLoader()
+ bmp.load_data(bmpdata)
+ self.main_image = \
+ self.make_image(bmp.width, bmp.height, bmp.rgb)
+ self.curr_width = bmp.width
+ self.curr_height = bmp.height
+ self.switch_view(1)
+ self.update_canvas()
+ except:
+ self.switch_view(0)
+ self.clear_text()
+ self.insert_text("Error loading {} - \"{}\" \n\n{}".\
+ format(res_id, fn, traceback.format_exc()))
+ else:
+ self.switch_view(0)
+ self.clear_text()
+ self.insert_text("Resource {} - \"{}\" cannot be displayed\n".\
+ format(res_id, fn))
+
+ def path_res_status(self):
+ self.switch_view(0)
+ self.clear_text()
+ self.insert_text("Total: ")
+ self.insert_text("{}".format(len(self.sim.res)), ["res"])
+ self.insert_text("\nFiletypes:\n")
+ fts = {}
+ for res in self.sim.res.values():
+ fp = res.rfind(".")
+ if fp >= 0:
+ ft = res[fp + 1:].upper()
+ fts[ft] = fts.get(ft, 0) + 1
+ ftk = list(fts.keys())
+ ftk.sort()
+ for ft in ftk:
+ self.insert_text(" ")
+ self.insert_text(ft, ["res", "flt", ft])
+ self.insert_text(": {}\n".format(fts[ft]))
+
+ def path_res_all(self, path):
+ if self.last_path[:2] != ("res", "all",):
+ self.update_gui("Resources ({})".format(len(self.sim.res)))
+ for idx, res_id in enumerate(self.sim.resord):
+ self.insert_lb_act("{} - {}".format(\
+ res_id, self.sim.res[res_id]), ["res", "all", idx])
+ # change
+ if len(path) > 2:
+ # parts
+ self.select_lb_item(path[2])
+ res_id = self.sim.resord[path[2]]
+ self.path_res_open(res_id)
+ else:
+ self.path_res_status()
+
+ def path_res_flt(self, path):
+ lst = []
+ for idx, res_id in enumerate(self.sim.resord):
+ if self.sim.res[res_id].upper().endswith("." + path[2]):
+ lst.append(res_id)
+ if self.last_path[:3] != ("res", "flt", path[2]):
+ self.update_gui("Resources {} ({})".format(path[2], len(lst)))
+ for idx, res_id in enumerate(lst):
+ self.insert_lb_act("{} - {}".format(\
+ res_id, self.sim.res[res_id]), ["res", "flt", path[2], idx])
+ # change
+ if len(path) > 3:
+ # parts
+ self.select_lb_item(path[3])
+ res_id = lst[path[3]]
+ self.path_res_open(res_id)
+ else:
+ self.path_res_status()
+
def path_objs_scenes(self, path):
self.switch_view(0)
isobj = (self.curr_path[0] == "objs")
@@ -583,7 +609,7 @@ class App(tkinter.Frame):
lst = self.sim.objects
else:
lst = self.sim.scenes
- if len(self.last_path) == 0 or self.last_path[0] != self.curr_path[0]:
+ if self.last_path[:1] != (self.curr_path[0],):
if isobj:
self.update_gui("Objects ({})".format(len(lst)))
else:
@@ -639,7 +665,7 @@ class App(tkinter.Frame):
def path_names(self, path):
self.switch_view(0)
- if len(self.last_path) == 0 or self.last_path[0] != "names":
+ if self.last_path[:1] != ("names",):
self.update_gui("Names ({})".format(len(self.sim.names)))
for idx, name in enumerate(self.sim.namesord):
self.insert_lb_act(name, ["names", idx])
@@ -667,7 +693,7 @@ class App(tkinter.Frame):
def path_invntr(self, path):
self.switch_view(0)
- if len(self.last_path) == 0 or self.last_path[0] != "invntr":
+ if self.last_path[:1] != ("invntr",):
self.update_gui("Invntr ({})".format(len(self.sim.invntr)))
for idx, name in enumerate(self.sim.invntrord):
self.insert_lb_act(name, ["invntr", idx])
@@ -694,6 +720,11 @@ class App(tkinter.Frame):
self.insert_text(" - {}\n".format(obj.name))
def path_test(self, path):
+ self.update_gui("Test {}".format(path[1]))
+ self.insert_lb_act("Outline", [])
+ self.insert_lb_act("-", None)
+ for i in range(15):
+ self.insert_lb_act("{} #{}".format(path[1], i), path[:2] + (i,))
if path[1] == "image":
self.switch_view(1)
self.main_image = tkinter.PhotoImage(\
@@ -702,13 +733,8 @@ class App(tkinter.Frame):
self.curr_height = self.main_image.height()
else:
self.switch_view(0)
- self.update_gui("Test {}".format(path[1]))
- self.insert_lb_act("Outline", [])
- self.insert_lb_act("-", None)
- for i in range(15):
- self.insert_lb_act("{} #{}".format(path[1], i), path[:2] + (i,))
- if path[1] != "image":
self.clear_text()
+ self.insert_text("Information panel for {}\n".format(path))
for i in range(100):
self.insert_text(" Item {}\n".format(i))
Commit: 4f62901edd222c465d200debb43bb91753405fa0
https://github.com/scummvm/scummvm-tools/commit/4f62901edd222c465d200debb43bb91753405fa0
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor image loading
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/__init__.py
engines/petka/petka/engine.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9e34673ac..82269d835 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -67,7 +67,7 @@ class App(tkinter.Frame):
self.path_handler = {}
self.curr_main = -1 # 0 - frame, 1 - canvas
self.curr_path = []
- self.last_path = None
+ self.last_path = [None]
self.curr_mode = 0
self.curr_mode_sub = None
self.curr_gui = []
@@ -132,7 +132,7 @@ class App(tkinter.Frame):
self.path_handler["test"] = self.path_test
self.update_after()
- self.open_path([])
+ self.open_path(self.find_path_scene(36))
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -399,6 +399,11 @@ class App(tkinter.Frame):
if act[1] is not None:
self.open_path(act[1])
+ def find_path_res(self, res):
+ for idx, res_id in enumerate(self.sim.resord):
+ if res_id == res:
+ return ["res", "all", idx]
+ return ["no_res", res]
def find_path_obj(self, obj_idx):
for idx, rec in enumerate(self.sim.objects):
@@ -529,9 +534,9 @@ class App(tkinter.Frame):
fn = self.sim.res[res_id]
if fn[-4:].lower() == ".bmp":
try:
- bmpdata = self.sim.fman.read_file(fn)
+ bmpf = self.sim.fman.read_file_stream(fn)
bmp = petka.BMPLoader()
- bmp.load_data(bmpdata)
+ bmp.load_data(bmpf)
self.main_image = \
self.make_image(bmp.width, bmp.height, bmp.rgb)
self.curr_width = bmp.width
@@ -543,6 +548,8 @@ class App(tkinter.Frame):
self.clear_text()
self.insert_text("Error loading {} - \"{}\" \n\n{}".\
format(res_id, fn, traceback.format_exc()))
+ finally:
+ bmpf.close()
else:
self.switch_view(0)
self.clear_text()
@@ -640,7 +647,8 @@ class App(tkinter.Frame):
self.insert_text(" ")
self.insert_text("Invntr", self.find_path_invntr(rec.name))
self.insert_text(": {}\n".format(self.sim.invntr[rec.name]))
-
+
+ # references / backreferences
if isobj:
# search where object used
self.insert_text("\nUsed in:\n")
@@ -661,7 +669,57 @@ class App(tkinter.Frame):
self.insert_text(" {}) ".format(idx))
self.insert_text("{}".format(ref[0].idx), \
self.find_path_obj(ref[0].idx))
- self.insert_text(" - {}\n".format(ref[0].name))
+ msg = ""
+ for arg in ref[1:]:
+ msg += " "
+ if arg < 10:
+ msg += "{}".format(arg)
+ elif arg == 0xffffffff:
+ msg += "-1"
+ else:
+ msg += "0x{:X}".format(arg)
+ self.insert_text(msg + " / {}\n".format(ref[0].name))
+
+ resused = []
+ self.insert_text("\nHandlers: {}\n".format(len(rec.acts)))
+ for idx, (act_id, act_cond, act_arg, ops) in enumerate(rec.acts):
+ msg = petka.OPCODES.get(act_id, ["OP_{:X}".format(act_id)])[0]
+ if act_cond != 0xff or act_arg != 0xffff:
+ msg += " 0x{:02X} 0x{:04X}".format(act_cond, act_arg)
+ self.insert_text(" {}) on {}, ops: {}\n".format(\
+ idx, msg, len(ops)))
+ for oidx, op in enumerate(ops):
+ msg = petka.OPCODES.get(op[1], ["OP_{:X}".format(op[1])])[0]
+ self.insert_text(" {}) {} ".format(oidx, msg))
+ if op[0] == rec.idx:
+ self.insert_text("THIS")
+ else:
+ self.insert_text("{}".format(op[0]), \
+ self.find_path_obj(op[0]))
+ msg = ""
+ if op[2] != 0xffff:
+ if op[2] not in resused and op[2] in self.sim.res:
+ resused.append(op[2])
+ for arg in op[2:]:
+ msg += " "
+ if arg < 10:
+ msg += "{}".format(arg)
+ elif arg == 0xffff:
+ msg += "-1"
+ else:
+ msg += "0x{:X}".format(arg)
+ self.insert_text("{}\n".format(msg))
+
+ if len(resused) > 0:
+ self.insert_text("\nUsed resources: {}\n".format(len(resused)))
+ for res_id in resused:
+ self.insert_text(" ")
+ self.insert_text("{}".format(res_id), \
+ self.find_path_res(res_id))
+ self.insert_text(" - {} (0x{:X})\n".\
+ format(self.sim.res[res_id], res_id))
+
+
def path_names(self, path):
self.switch_view(0)
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index ecf231162..712beca4a 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -1,6 +1,6 @@
class EngineError(Exception): pass
-from .engine import Engine
+from .engine import Engine, OPCODES
from .fman import FileManager
from .imgbmp import BMPLoader
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 9c4a34335..d6fc1b189 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -8,6 +8,67 @@ import io
from .fman import FileManager
+OPCODES = {
+ 1: ("USE", 0),
+ 2: ("SETPOS", 2),
+ 3: ("GOTO", 0),
+ 4: ("LOOK", 0),
+ 5: ("SAY", 0),
+ 6: ("TAKE", 0),
+ 9: ("WALK", 2),
+ 10: ("TALK", 0),
+ 11: ("END", 0),
+ 14: ("SET", 1),
+ 15: ("SHOW", 1),
+ 16: ("HIDE", 0),
+ 17: ("DIALOG", 1),
+ 18: ("ZBUFFER", 0),
+ 19: ("TOTALINIT", 1),
+ 20: ("ANIMATE", 1),
+ 21: ("STATUS", 1),
+ 22: ("ADDINV", 0),
+ 23: ("DELINV", 0),
+ 24: ("STOP", 1),
+ 25: ("CURSOR", 1),
+ 26: ("OBJECTUSE", 0),
+ 27: ("ACTIVE", 1),
+ 28: ("SAID", 0),
+ 29: ("SETSEQ", 0),
+ 30: ("ENDSEQ", 0),
+ 31: ("CHECK", 0),
+ 32: ("IF", 0),
+ 33: ("DESCRIPTION", 0),
+ 34: ("HALF", 0),
+ 36: ("WALKTO", 0),
+ 37: ("WALKVICH", 0),
+ 38: ("INITBG", 0),
+ 39: ("USERMSG", 0),
+ 40: ("SYSTEM", 0),
+ 41: ("SETZBUFFER", 0),
+ 42: ("CONTINUE", 0),
+ 43: ("MAP", 1),
+ 44: ("PASSIVE", 1),
+ 45: ("NOMAP", 1),
+ 46: ("SETINV", 1),
+ 47: ("BGSFX", 1),
+ 48: ("MUSIC", 1),
+ 49: ("IMAGE", 1),
+ 50: ("STAND", 1),
+ 51: ("ON", 1),
+ 52: ("OFF", 1),
+ 53: ("PLAY", 1),
+ 54: ("LEAVEBG", 0),
+ 55: ("SHAKE", 1),
+ 56: ("SP", 2),
+ 57: ("RANDOM", 1),
+ 58: ("JUMP", 0),
+ 59: ("JUMPVICH", 0),
+ 60: ("PART", 2),
+ 61: ("CHAPTER", 2),
+ 62: ("AVI", 1),
+ 63: ("TOMAP", 0),
+}
+
class ScrObject:
def __init__(self, idx, name):
self.idx = idx
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index eaf849fc3..12c098b4d 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -12,19 +12,21 @@ class BMPLoader:
self.width = 0
self.height = 0
- def load_data(self, data):
+ def load_data(self, f):
# TODO: normal BMP, rle BMP
# check magic string "BM"
- if data[:2] != b"BM":
+ temp = f.read(2)
+ if temp != b"BM":
raise EngineError("Bad magic string")
off = 2
- f_sz, res1, res2, data_offset = struct.unpack_from("<IHHI", \
- data[off:off + 12])
+ temp = f.read(12)
+ f_sz, res1, res2, data_offset = struct.unpack_from("<IHHI", temp)
off += 12
# read next 40 bytes, BITMAPINFOHEADER
- pict = struct.unpack_from("<IiiHHIIiiII", data[off:off + 40])
+ temp = f.read(40)
+ pict = struct.unpack_from("<IiiHHIIiiII", temp)
off += 40
if pict[0] != 40:
raise EngineError("Unsupported InfoHeader")
@@ -39,22 +41,24 @@ class BMPLoader:
raise EngineError("To small bitmap data offset")
if delta != 8:
raise EngineError("Unsupported Header at 0x36")
- hdr36 = struct.unpack_from("<II", data[off:off + delta])
+ temp = f.read(delta)
+ hdr36 = struct.unpack_from("<II", temp)
off += delta
bsz = pictw * picth * 2
- picture_data = data[off:off + bsz]
+ picture_data = f.read(bsz)
off += bsz
if len(picture_data) != bsz:
raise EngineError("Bitmap truncated, need {}, got {}".format(bsz, \
len(picture_data)))
# read 2 zero bytes
- if data[off:off + 2] != b"\x00\x00":
+ temp = f.read(2)
+ if temp != b"\x00\x00":
raise EngineError("Magic zero bytes absent or mismatch")
off += 2
- if len(data) - off > 0:
+ if len(f.read()) > 0:
raise EngineError("BMP read error, some data unparsed")
# convert 16 bit to 24
Commit: 11850e3b02eac4b4fc7d3f3881449598d48c58a5
https://github.com/scummvm/scummvm-tools/commit/11850e3b02eac4b4fc7d3f3881449598d48c58a5
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Refactor image loading
Changed paths:
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 12c098b4d..da3bd3b8e 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -6,13 +6,20 @@ import array, struct
from . import EngineError
+try:
+ from PIL import Image
+except:
+ Image = None
+
class BMPLoader:
def __init__(self):
- self.raw = None
+ self.rgb = None
+ self.image = None
self.width = 0
self.height = 0
+ self.imginfo = ""
- def load_data(self, f):
+ def load_data_int(self, f):
# TODO: normal BMP, rle BMP
# check magic string "BM"
temp = f.read(2)
@@ -75,3 +82,12 @@ class BMPLoader:
off = (picth - i - 1) * pictw * 3
self.rgb += rgb[off:off + pictw * 3]
+ self.imginfo = "Internal BMP loader"
+
+ def load_data(self, f):
+ try:
+ img = Image.open(f)
+ except:
+ f.seek(0)
+ self.load_data_int(f)
+
Commit: c86264eca669d71ac6e73163681c14a0186eed43
https://github.com/scummvm/scummvm-tools/commit/c86264eca669d71ac6e73163681c14a0186eed43
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Initial Pillow support
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 82269d835..a365e0a4d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -9,6 +9,15 @@ from tkinter import ttk, font
from idlelib.WidgetRedirector import WidgetRedirector
import traceback
+try:
+ from PIL import Image
+except:
+ Image = None
+try:
+ from PIL import ImageTk
+except:
+ ImageTk = None
+
import petka
APPNAME = "P1&2 Explorer"
@@ -73,8 +82,6 @@ class App(tkinter.Frame):
self.curr_gui = []
self.curr_lb_acts = None
# canvas
- self.curr_width = 0
- self.curr_height = 0
self.need_update = False
self.canv_view_fact = 1
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
@@ -219,54 +226,81 @@ class App(tkinter.Frame):
c = self.canv_view
c.delete(tkinter.ALL)
if self.sim is None: return
- # Preview image
- self.canv_image = self.main_image.copy()
+
w = self.canv_view.winfo_width()
h = self.canv_view.winfo_height()
if (w == 0) or (h == 0):
return
- scale = 0 #self.RadioGroupScale.get()
- if scale == 0: # Fit
- try:
- psc = w / h
- isc = self.curr_width / self.curr_height
- if psc < isc:
- if w > self.curr_width:
- fact = w // self.curr_width
- else:
- fact = -self.curr_width // w
- else:
- if h > self.curr_height:
- fact = h // self.curr_height
+ scale = 0
+
+ # Preview image
+ if not isinstance(self.main_image, tkinter.PhotoImage):
+ mw, mh = self.main_image.size
+ if scale == 0: # Fit
+ try:
+ psc = w / h
+ isc = mw / mh
+ if psc < isc:
+ fact = w / mw
else:
- fact = -self.curr_height // h
- except:
- fact = 1
+ fact = h / mh
+ except:
+ fact = 1.0
+ else:
+ fact = scale
+ pw = int(mw * fact)
+ ph = int(mh * fact)
+ img = self.main_image.resize((pw, ph))
+ self.canv_image = ImageTk.PhotoImage(img)
else:
- fact = scale
+ mw = self.main_image.width()
+ mh = self.main_image.height()
+ if scale == 0: # Fit
+ try:
+ psc = w / h
+ isc = mw / mh
+ if psc < isc:
+ if w > mw:
+ fact = w // mw
+ else:
+ fact = -mw // w
+ else:
+ if h > mh:
+ fact = h // mh
+ else:
+ fact = -mh // h
+ except:
+ fact = 1
+ else:
+ fact = scale
+ self.canv_image = self.main_image.copy()
+ if fact > 0:
+ self.canv_image = self.canv_image.zoom(fact)
+ else:
+ self.canv_image = self.canv_image.subsample(-fact)
+ self.canv_image_fact = fact
- # place on canvas
- if fact > 0:
- pw = self.curr_width * fact
- ph = self.curr_height * fact
- else:
- pw = self.curr_width // -fact
- ph = self.curr_height // -fact
+ # place on canvas
+ if fact > 0:
+ pw = mw * fact
+ ph = mh * fact
+ else:
+ pw = mw // -fact
+ ph = mh // -fact
cw = max(pw, w)
ch = max(ph, h)
c.config(scrollregion = (0, 0, cw - 2, ch - 2))
-
- if fact > 0:
- self.canv_image = self.canv_image.zoom(fact)
- else:
- self.canv_image = self.canv_image.subsample(-fact)
- self.canv_image_fact = fact
#print("Place c %d %d, p %d %d" % (cw, ch, w, h))
c.create_image(cw // 2, ch // 2, image = self.canv_image)
- def make_image(self, width, height, data):
+ def make_image(self, imgobj):
+ if imgobj.image is not None:
+ return imgobj.image
+ width = imgobj.width
+ height = imgobj.height
+ data = imgobj.rgb
# create P6
phdr = ("P6\n{} {}\n255\n".format(width, height))
rawlen = width * height * 3 # RGB
@@ -538,9 +572,7 @@ class App(tkinter.Frame):
bmp = petka.BMPLoader()
bmp.load_data(bmpf)
self.main_image = \
- self.make_image(bmp.width, bmp.height, bmp.rgb)
- self.curr_width = bmp.width
- self.curr_height = bmp.height
+ self.make_image(bmp)
self.switch_view(1)
self.update_canvas()
except:
@@ -785,10 +817,7 @@ class App(tkinter.Frame):
self.insert_lb_act("{} #{}".format(path[1], i), path[:2] + (i,))
if path[1] == "image":
self.switch_view(1)
- self.main_image = tkinter.PhotoImage(\
- file = "img/splash.gif")
- self.curr_width = self.main_image.width()
- self.curr_height = self.main_image.height()
+ self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
else:
self.switch_view(0)
self.clear_text()
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index da3bd3b8e..243779bb9 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -86,7 +86,7 @@ class BMPLoader:
def load_data(self, f):
try:
- img = Image.open(f)
+ self.image = Image.open(f)
except:
f.seek(0)
self.load_data_int(f)
Commit: bfabee3932ea4ea04a9c6c41cb364ff036a2488c
https://github.com/scummvm/scummvm-tools/commit/bfabee3932ea4ea04a9c6c41cb364ff036a2488c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Pillow support (not finished)
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index a365e0a4d..9532692ce 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -11,11 +11,11 @@ import traceback
try:
from PIL import Image
-except:
+except ImportError:
Image = None
try:
from PIL import ImageTk
-except:
+except ImportError:
ImageTk = None
import petka
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 243779bb9..3016593fa 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -8,7 +8,7 @@ from . import EngineError
try:
from PIL import Image
-except:
+except ImportError:
Image = None
class BMPLoader:
@@ -17,10 +17,8 @@ class BMPLoader:
self.image = None
self.width = 0
self.height = 0
- self.imginfo = ""
- def load_data_int(self, f):
- # TODO: normal BMP, rle BMP
+ def load_data_int16(self, f):
# check magic string "BM"
temp = f.read(2)
if temp != b"BM":
@@ -38,9 +36,7 @@ class BMPLoader:
if pict[0] != 40:
raise EngineError("Unsupported InfoHeader")
pictw = pict[1]
- self.width = pictw
picth = pict[2]
- self.height = picth
# read data_offset - 40 - 6 bytes
delta = data_offset - 40 - 6
@@ -68,26 +64,38 @@ class BMPLoader:
if len(f.read()) > 0:
raise EngineError("BMP read error, some data unparsed")
+ return pictw, picth, picture_data
+
+ def pixelswap16(self, pw, ph, pd):
# convert 16 bit to 24
b16arr = array.array("H") # unsigned short
- b16arr.frombytes(picture_data)
+ b16arr.frombytes(pd)
rgb = array.array("B")
for b16 in b16arr:
rgb.append((b16 >> 5) & 0b11111000)
rgb.append((b16 << 5) & 0b11100000 | (b16 >> 11) & 0b00011100)
rgb.append((b16 << 0) &0b11111000)
# Y-mirror
- self.rgb = array.array("B")
- for i in range(picth):
- off = (picth - i - 1) * pictw * 3
- self.rgb += rgb[off:off + pictw * 3]
+ newrgb = array.array("B")
+ for i in range(ph):
+ off = (ph - i - 1) * pw * 3
+ newrgb += rgb[off:off + pw * 3]
+ return newrgb
- self.imginfo = "Internal BMP loader"
def load_data(self, f):
try:
- self.image = Image.open(f)
+ pw, ph, pd = self.load_data_int16(f)
+ if Image:
+
+ self.image = Image.frombytes("RGB;16", (pw, ph), pd, "bit", 16, 0, 0)
+ else:
+ self.width = pw
+ self.height = ph
+ self.rgb = self.pixelswap16(pw, ph, pd)
except:
+ import traceback
+ traceback.print_exc()
f.seek(0)
- self.load_data_int(f)
-
+ self.image = Image.open(f)
+
Commit: b9c84877f91fbe19796e28f76fd317a06d693247
https://github.com/scummvm/scummvm-tools/commit/b9c84877f91fbe19796e28f76fd317a06d693247
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Reading BMP with PILLOW (baggy)
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9532692ce..dfbd1f5b1 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -139,7 +139,8 @@ class App(tkinter.Frame):
self.path_handler["test"] = self.path_test
self.update_after()
- self.open_path(self.find_path_scene(36))
+ #self.open_path(self.find_path_scene(36))
+ self.open_path(["res", "flt", "BMP", 7])
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -533,7 +534,7 @@ class App(tkinter.Frame):
elif path[1] == "all":
return self.path_res_all(path)
else:
- return self.path_default()
+ return self.path_default(path)
if self.last_path[:2] != path[:2]:
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 3016593fa..713c33f0b 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -2,7 +2,7 @@
# romiq.kh at gmail.com, 2014
-import array, struct
+import array, struct, io
from . import EngineError
@@ -50,6 +50,7 @@ class BMPLoader:
bsz = pictw * picth * 2
picture_data = f.read(bsz)
+
off += bsz
if len(picture_data) != bsz:
raise EngineError("Bitmap truncated, need {}, got {}".format(bsz, \
@@ -87,8 +88,20 @@ class BMPLoader:
try:
pw, ph, pd = self.load_data_int16(f)
if Image:
-
- self.image = Image.frombytes("RGB;16", (pw, ph), pd, "bit", 16, 0, 0)
+ # reload fixed
+ f.seek(0)
+ d = io.BytesIO()
+ d.write(f.read(10))
+ data_off = struct.unpack("<I", f.read(4))[0]
+ d.write(struct.pack("<I", data_off - 1))
+ d.write(f.read(data_off - 14))
+ #fmt = "{}H".format(pw * ph)
+ #data = struct.unpack(">" + fmt, f.read(pw * ph * 2))
+ #d.write(struct.pack("<" + fmt, *data))
+ d.write(f.read(pw * ph * 2))
+ d.write(b"\xFF" * 10)
+ d.seek(0)
+ self.image = Image.open(d)
else:
self.width = pw
self.height = ph
Commit: 2603ab1f9b7b419c1a1f7797f10cb977d310e633
https://github.com/scummvm/scummvm-tools/commit/2603ab1f9b7b419c1a1f7797f10cb977d310e633
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Reading BMP with PILLOW (baggy)
Changed paths:
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 713c33f0b..90e72a8b2 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -89,19 +89,20 @@ class BMPLoader:
pw, ph, pd = self.load_data_int16(f)
if Image:
# reload fixed
- f.seek(0)
- d = io.BytesIO()
- d.write(f.read(10))
- data_off = struct.unpack("<I", f.read(4))[0]
- d.write(struct.pack("<I", data_off - 1))
- d.write(f.read(data_off - 14))
+ #f.seek(0)
+ #d = io.BytesIO()
+ #d.write(f.read(10))
+ #data_off = struct.unpack("<I", f.read(4))[0]
+ #d.write(struct.pack("<I", data_off - 1))
+ #d.write(f.read(data_off - 14))
#fmt = "{}H".format(pw * ph)
#data = struct.unpack(">" + fmt, f.read(pw * ph * 2))
#d.write(struct.pack("<" + fmt, *data))
- d.write(f.read(pw * ph * 2))
- d.write(b"\xFF" * 10)
- d.seek(0)
- self.image = Image.open(d)
+ #d.write(f.read(pw * ph * 2))
+ #d.write(b"\xFF" * 10)
+ #d.seek(0)
+ #self.image = Image.open(d)
+ self.image = Image.frombytes("RGB", (pw, ph), pd, "BGR;16")
else:
self.width = pw
self.height = ph
Commit: cf98f30a46b10781f38a8f04b791c4ee6040f12c
https://github.com/scummvm/scummvm-tools/commit/cf98f30a46b10781f38a8f04b791c4ee6040f12c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: BMP can be loaded correctly most times
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index dfbd1f5b1..d0623303e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -139,8 +139,8 @@ class App(tkinter.Frame):
self.path_handler["test"] = self.path_test
self.update_after()
- #self.open_path(self.find_path_scene(36))
- self.open_path(["res", "flt", "BMP", 7])
+ self.open_path(self.find_path_scene(36))
+ #self.open_path(["res", "flt", "BMP", 7])
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -451,6 +451,15 @@ class App(tkinter.Frame):
if rec.idx == scn_idx:
return ["scenes", idx]
return ["no_scene", scn_idx]
+
+ def find_path_obj_scene(self, rec_idx):
+ for idx, rec in enumerate(self.sim.objects):
+ if rec.idx == rec_idx:
+ return ["objs", idx]
+ for idx, rec in enumerate(self.sim.scenes):
+ if rec.idx == rec_idx:
+ return ["scenes", idx]
+ return ["no_obj_scene", rec_idx]
def find_path_name(self, key):
for idx, name in enumerate(self.sim.namesord):
@@ -670,8 +679,8 @@ class App(tkinter.Frame):
else:
# record info
self.insert_text(("Object" if isobj else "Scene") + ":\n")
- self.insert_text(" Index: {}\n Name: {}\n".\
- format(rec.idx, rec.name))
+ self.insert_text(" Index: {} (0x{:X})\n Name: {}\n".\
+ format(rec.idx, rec.idx, rec.name))
if rec.name in self.sim.names:
self.insert_text(" ")
self.insert_text("Alias", self.find_path_name(rec.name))
@@ -728,7 +737,7 @@ class App(tkinter.Frame):
self.insert_text("THIS")
else:
self.insert_text("{}".format(op[0]), \
- self.find_path_obj(op[0]))
+ self.find_path_obj_scene(op[0]))
msg = ""
if op[2] != 0xffff:
if op[2] not in resused and op[2] in self.sim.res:
@@ -749,8 +758,8 @@ class App(tkinter.Frame):
self.insert_text(" ")
self.insert_text("{}".format(res_id), \
self.find_path_res(res_id))
- self.insert_text(" - {} (0x{:X})\n".\
- format(self.sim.res[res_id], res_id))
+ self.insert_text(" (0x{:X}) - {}\n".\
+ format(res_id, self.sim.res[res_id]))
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 90e72a8b2..41565ebc3 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -57,13 +57,15 @@ class BMPLoader:
len(picture_data)))
# read 2 zero bytes
- temp = f.read(2)
- if temp != b"\x00\x00":
- raise EngineError("Magic zero bytes absent or mismatch")
- off += 2
+ #temp = f.read(2)
+ #if temp != b"\x00\x00":
+ # raise EngineError("Magic zero bytes absent or mismatch")
+ #off += 2
- if len(f.read()) > 0:
- raise EngineError("BMP read error, some data unparsed")
+ temp = f.read(2)
+ if len(temp) > 0:
+ if temp != b"\x00\x00":
+ raise EngineError("BMP read error, some data unparsed")
return pictw, picth, picture_data
@@ -71,17 +73,32 @@ class BMPLoader:
# convert 16 bit to 24
b16arr = array.array("H") # unsigned short
b16arr.frombytes(pd)
- rgb = array.array("B")
- for b16 in b16arr:
- rgb.append((b16 >> 5) & 0b11111000)
- rgb.append((b16 << 5) & 0b11100000 | (b16 >> 11) & 0b00011100)
- rgb.append((b16 << 0) &0b11111000)
- # Y-mirror
- newrgb = array.array("B")
- for i in range(ph):
- off = (ph - i - 1) * pw * 3
- newrgb += rgb[off:off + pw * 3]
- return newrgb
+ b16arr.byteswap()
+
+ #rgb = array.array("B")
+ #for b16 in b16arr:
+ #rgb.append((b16 >> 5) & 0b11111000)
+ #rgb.append((b16 << 5) & 0b11100000 | (b16 >> 11) & 0b00011100)
+ #rgb.append((b16 << 0) &0b11111000)
+ # rgb.append((b16 << 3) & 0b11111000)
+ # rgb.append((b16 >> 3) & 0b11111100)
+ # rgb.append((b16 >> 8) & 0b11111000)
+ ## Y-mirror
+ #newrgb = array.array("B")
+ #for i in range(ph):
+ # off = (ph - i - 1) * pw * 3
+ # newrgb += rgb[off:off + pw * 3]
+ #return newrgb
+
+ rgb = array.array("B", [0] * pw * ph * 3)
+ for j in range(ph):
+ for i in range(pw):
+ off = (ph - j - 1) * pw * 3 + i * 3
+ b16 = b16arr[j * pw + i]
+ rgb[off] = (b16 << 3) & 0b11111000
+ rgb[off + 1] = (b16 >> 3) & 0b11111100
+ rgb[off + 2] = (b16 >> 8) & 0b11111000
+ return rgb
def load_data(self, f):
@@ -102,7 +119,8 @@ class BMPLoader:
#d.write(b"\xFF" * 10)
#d.seek(0)
#self.image = Image.open(d)
- self.image = Image.frombytes("RGB", (pw, ph), pd, "BGR;16")
+ pd = self.pixelswap16(pw, ph, pd).tobytes()
+ self.image = Image.frombytes("RGB", (pw, ph), pd)
else:
self.width = pw
self.height = ph
Commit: 8afb6d50b00a0cc4972f2714245cc8b8b2ca8c8f
https://github.com/scummvm/scummvm-tools/commit/8afb6d50b00a0cc4972f2714245cc8b8b2ca8c8f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Select only one item in listbox, refine
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index d0623303e..3a52433e6 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -91,7 +91,8 @@ class App(tkinter.Frame):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
- ttk.Style().configure('Info.TFrame', background = 'white', foreground = "black")
+ ttk.Style().configure('Info.TFrame', background = 'white', \
+ foreground = "black")
# main paned
self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
@@ -411,15 +412,17 @@ class App(tkinter.Frame):
self.curr_lb.insert(tkinter.END, name)
def select_lb_item(self, idx):
- try:
- num = self.curr_lb.curselection()[0]
- num = int(num)
- except:
- num = -1
- if idx != num:
+ idx = "{}".format(idx)
+ need = True
+ for sel in self.curr_lb.curselection():
+ if sel == idx:
+ need = False
+ else:
+ self.curr_lb.selection_clear(sel)
+ if need:
self.curr_lb.selection_set(idx)
- self.curr_lb.see(idx)
-
+ self.curr_lb.see(idx)
+
def on_left_listbox(self, event):
def currsel():
try:
@@ -693,7 +696,7 @@ class App(tkinter.Frame):
# references / backreferences
if isobj:
# search where object used
- self.insert_text("\nUsed in:\n")
+ self.insert_text("\nRefered by scenes:\n")
for scn in self.sim.scenes:
for ref in scn.refs:
if ref[0].idx == rec.idx:
Commit: e98266437bcc5536484439070173a8d0b7359f8d
https://github.com/scummvm/scummvm-tools/commit/e98266437bcc5536484439070173a8d0b7359f8d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: REfactor: internal locations and text tagging
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3a52433e6..ce0259371 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -22,6 +22,9 @@ import petka
APPNAME = "P1&2 Explorer"
+def hlesc(value):
+ return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
+
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
def __init__(self, text):
@@ -30,6 +33,15 @@ class HyperlinkManager:
self.text.tag_bind("hyper", "<Enter>", self._enter)
self.text.tag_bind("hyper", "<Leave>", self._leave)
self.text.tag_bind("hyper", "<Button-1>", self._click)
+ bold_font = font.Font(text, self.text.cget("font"))
+ bold_font.configure(weight = "bold")
+ self.text.tag_config("bold", font = bold_font)
+ italic_font = font.Font(text, self.text.cget("font"))
+ italic_font.configure(slant = "italic")
+ self.text.tag_config("italic", font = italic_font)
+ underline_font = font.Font(text, self.text.cget("font"))
+ underline_font.configure(underline = 1)
+ self.text.tag_config("underline", font = underline_font)
self.reset()
def reset(self):
@@ -140,7 +152,8 @@ class App(tkinter.Frame):
self.path_handler["test"] = self.path_test
self.update_after()
- self.open_path(self.find_path_scene(36))
+ self.open_path("")
+ #self.open_path(self.find_path_scene(36))
#self.open_path(["res", "flt", "BMP", 7])
def create_menu(self):
@@ -212,7 +225,19 @@ class App(tkinter.Frame):
def on_resize_view(self, event):
self.update_after()
- def open_path(self, path):
+ def open_path(self, loc):
+ if isinstance(loc, str):
+ path = []
+ if loc[:1] == "/":
+ loc = loc[1:]
+ if loc != "":
+ for item in loc.split("/"):
+ try:
+ path.append(int(item, 10))
+ except:
+ path.append(item)
+ else:
+ path = loc
path = tuple(path)
print("DEBUG: Open", path)
self.curr_path = path
@@ -253,7 +278,7 @@ class App(tkinter.Frame):
fact = scale
pw = int(mw * fact)
ph = int(mh * fact)
- img = self.main_image.resize((pw, ph))
+ img = self.main_image.resize((pw, ph), Image.ANTIALIAS)
self.canv_image = ImageTk.PhotoImage(img)
else:
mw = self.main_image.width()
@@ -390,23 +415,60 @@ class App(tkinter.Frame):
self.scr_view_x.config(command = self.canv_view.xview)
self.scr_view_y.config(command = self.canv_view.yview)
- def clear_text(self):
+ def clear_info(self):
self.text_view.delete(0.0, tkinter.END)
- def insert_text(self, text, link = None):
- if link:
- if callable(link):
- cb = link
- else:
- def make_cb(path):
- def cb():
- return self.open_path(path)
- return cb
- cb = make_cb(tuple(link))
- self.text_view.insert(tkinter.INSERT, text, self.text_hl.add(cb))
- else:
- self.text_view.insert(tkinter.INSERT, text)
-
+ def add_info(self, text):
+ mode = 0 # 0 - normal, 1 - tag
+ curr_tag = None
+ curr_text = ""
+ tags = []
+ esc = False
+ for ch in text:
+ if mode == 0:
+ if esc:
+ curr_text += ch
+ esc = False
+ else:
+ if ch == "\\":
+ esc = True
+ elif ch == "<":
+ mode = 1
+ curr_tag = ""
+ else:
+ curr_text += ch
+ else:
+ if ch == ">":
+ if len(curr_text) > 0:
+ self.text_view.insert(tkinter.INSERT, curr_text, \
+ tuple([x for x in tags for x in x]))
+ if curr_tag[:7] == "a href=":
+ ref = curr_tag[7:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ def make_cb(path):
+ def cb():
+ return self.open_path(path)
+ return cb
+ tags.append(self.text_hl.add(make_cb(ref)))
+ elif curr_tag == "b":
+ tags.append(["bold"])
+ elif curr_tag == "i":
+ tags.append(["italic"])
+ elif curr_tag == "u":
+ tags.append(["underline"])
+ elif curr_tag[:1] == "/":
+ tags = tags[:-1]
+ curr_text = ""
+ mode = 0
+ else:
+ curr_tag += ch
+ if len(curr_text) > 0:
+ self.text_view.insert(tkinter.INSERT, curr_text, \
+ tuple([x for x in tags for x in x]))
+
def insert_lb_act(self, name, act):
self.curr_lb_acts.append((name, act))
self.curr_lb.insert(tkinter.END, name)
@@ -440,52 +502,68 @@ class App(tkinter.Frame):
def find_path_res(self, res):
for idx, res_id in enumerate(self.sim.resord):
if res_id == res:
- return ["res", "all", idx]
- return ["no_res", res]
+ return "/res/all/{}".format(idx)
+ return "/no_res/{}".format(res)
def find_path_obj(self, obj_idx):
for idx, rec in enumerate(self.sim.objects):
if rec.idx == obj_idx:
- return ["objs", idx]
- return ["no_obj", obj_idx]
+ return "/objs/{}".format(idx)
+ return "/no_obj/{}".format(obj_idx)
def find_path_scene(self, scn_idx):
for idx, rec in enumerate(self.sim.scenes):
if rec.idx == scn_idx:
- return ["scenes", idx]
- return ["no_scene", scn_idx]
+ return "/scenes/{}".format(idx)
+ return "/no_scene/{}".format(scn_idx)
def find_path_obj_scene(self, rec_idx):
for idx, rec in enumerate(self.sim.objects):
if rec.idx == rec_idx:
- return ["objs", idx]
+ return "/objs/{}".format(idx)
for idx, rec in enumerate(self.sim.scenes):
if rec.idx == rec_idx:
- return ["scenes", idx]
- return ["no_obj_scene", rec_idx]
+ return "/scenes/{}".format(idx)
+ return "/no_obj_scene/{}".format(rec_idx)
def find_path_name(self, key):
for idx, name in enumerate(self.sim.namesord):
if name == key:
- return ["names", idx]
- return ["no_name", key]
+ return "/names/{}".format(idx)
+ return "/no_name/{}".format(key)
def find_path_invntr(self, key):
for idx, name in enumerate(self.sim.invntrord):
if name == key:
- return ["invntr", idx]
- return ["no_invntr", key]
+ return "/invntr/{}".format(idx)
+ return "/no_invntr/{}".format(key)
+
+ def path_info_outline(self):
+ self.add_info("Current part {} chapter {}\n\n".\
+ format(self.sim.curr_part, self.sim.curr_chap))
+ self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
+ format(len(self.sim.res)))
+ self.add_info(" Objects: <a href=\"/objs\">{}</a>\n".\
+ format(len(self.sim.objects)))
+ self.add_info(" Scenes: <a href=\"/scenes\">{}</a>\n".\
+ format(len(self.sim.scenes)))
+ self.add_info(" Names: <a href=\"/names\">{}</a>\n".\
+ format(len(self.sim.names)))
+ self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
+ format(len(self.sim.invntr)))
+
def path_default(self, path):
self.switch_view(0)
self.update_gui("Outline")
- self.clear_text()
+ self.clear_info()
if len(path) != 0:
spath = ""
for item in path:
spath += "/" + str(item)
- self.insert_text("Path {} not found\n\n".format(spath))
- self.insert_text("Select from outline\n")
+ self.add_info("Path {} not found\n\n".format(spath))
+ self.add_info("Select from <b>outline</b>\n\n")
+ self.path_info_outline()
if self.sim is not None:
acts = [
("Parts ({})".format(len(self.sim.parts)), ["parts"]),
@@ -522,18 +600,9 @@ class App(tkinter.Frame):
cnum = 0
self.sim.open_part(pnum, cnum)
# display
- self.clear_text()
- self.insert_text("Current: part {} chapter {}\n\n Resources: ".\
- format(self.sim.curr_part, self.sim.curr_chap))
- self.insert_text("{}".format(len(self.sim.res)), ["res"])
- self.insert_text("\n Objects: ")
- self.insert_text("{}".format(len(self.sim.objects)), ["objs"])
- self.insert_text("\n Scenes: ")
- self.insert_text("{}".format(len(self.sim.scenes)), ["scenes"])
- self.insert_text("\n Names: ")
- self.insert_text("{}".format(len(self.sim.names)), ["names"])
- self.insert_text("\n Invntr: ")
- self.insert_text("{}".format(len(self.sim.invntr)), ["invntr"])
+ self.clear_info()
+ self.add_info("Select <b>part</b>\n\n")
+ self.path_info_outline()
def path_res(self, path):
# res - full list
@@ -547,8 +616,7 @@ class App(tkinter.Frame):
return self.path_res_all(path)
else:
return self.path_default(path)
-
-
+
if self.last_path[:2] != path[:2]:
#
self.switch_view(0)
@@ -561,7 +629,6 @@ class App(tkinter.Frame):
for idx, name in enumerate(self.sim.invntrord):
self.insert_lb_act(name, ["invntr", idx])
- pass
# list resources
if self.curr_mode_sub is None:
lb = self.update_gui_add_left_listbox("Resources")
@@ -590,23 +657,22 @@ class App(tkinter.Frame):
self.update_canvas()
except:
self.switch_view(0)
- self.clear_text()
- self.insert_text("Error loading {} - \"{}\" \n\n{}".\
+ self.clear_info()
+ self.add_info("Error loading {} - \"{}\" \n\n{}".\
format(res_id, fn, traceback.format_exc()))
finally:
bmpf.close()
else:
self.switch_view(0)
- self.clear_text()
- self.insert_text("Resource {} - \"{}\" cannot be displayed\n".\
+ self.clear_info()
+ self.add_info("Resource {} - \"{}\" cannot be displayed\n".\
format(res_id, fn))
def path_res_status(self):
self.switch_view(0)
- self.clear_text()
- self.insert_text("Total: ")
- self.insert_text("{}".format(len(self.sim.res)), ["res"])
- self.insert_text("\nFiletypes:\n")
+ self.clear_info()
+ self.add_info("<b>Resources</b>: <a href=\"/res\">{}</a>\nFiletypes:\n".format(\
+ len(self.sim.res)))
fts = {}
for res in self.sim.res.values():
fp = res.rfind(".")
@@ -616,9 +682,8 @@ class App(tkinter.Frame):
ftk = list(fts.keys())
ftk.sort()
for ft in ftk:
- self.insert_text(" ")
- self.insert_text(ft, ["res", "flt", ft])
- self.insert_text(": {}\n".format(fts[ft]))
+ self.add_info(" <a href=\"/res/flt/{}\">{}</a>: {}\n".format(\
+ ft, ft, fts[ft]))
def path_res_all(self, path):
if self.last_path[:2] != ("res", "all",):
@@ -676,44 +741,44 @@ class App(tkinter.Frame):
self.select_lb_item(path[1])
rec = lst[path[1]]
# display
- self.clear_text()
+ self.clear_info()
if not rec:
- self.insert_text("Select item from list\n")
+ self.add_info("Select item from list\n")
else:
# record info
- self.insert_text(("Object" if isobj else "Scene") + ":\n")
- self.insert_text(" Index: {} (0x{:X})\n Name: {}\n".\
- format(rec.idx, rec.idx, rec.name))
+ self.add_info(("<b>Object</b>" if isobj \
+ else "<b>Scene</b>") + ":\n")
+ self.add_info(" Index: {} (0x{:X})\n Name: {}\n".\
+ format(rec.idx, rec.idx, hlesc(rec.name)))
if rec.name in self.sim.names:
- self.insert_text(" ")
- self.insert_text("Alias", self.find_path_name(rec.name))
- self.insert_text(": {}\n".format(self.sim.names[rec.name]))
+ self.add_info(" <a href=\"{}\">Alias</a>: {}\n".format(\
+ self.find_path_name(rec.name), \
+ hlesc(self.sim.names[rec.name])))
if rec.name in self.sim.invntr:
- self.insert_text(" ")
- self.insert_text("Invntr", self.find_path_invntr(rec.name))
- self.insert_text(": {}\n".format(self.sim.invntr[rec.name]))
+ self.add_info(" <a href=\"{}\">Invntr</a>: {}\n".format(\
+ self.find_path_invntr(rec.name), \
+ hlesc(self.sim.invntr[rec.name])))
# references / backreferences
if isobj:
# search where object used
- self.insert_text("\nRefered by scenes:\n")
+ self.add_info("\n<b>Refered by scenes</b>:\n")
for scn in self.sim.scenes:
for ref in scn.refs:
if ref[0].idx == rec.idx:
- self.insert_text(" ")
- self.insert_text("{}".format(scn.idx), \
- self.find_path_scene(scn.idx))
- self.insert_text(" - {}\n".format(scn.name))
+ self.add_info(" <a href=\"{}\">{}</a> (0x{:X}) "\
+ "- {}\n".format(self.find_path_scene(scn.idx), \
+ scn.idx, scn.idx, scn.name))
break
else:
if len(rec.refs) == 0:
- self.insert_text("\nNo references\n")
+ self.add_info("\nNo references\n")
else:
- self.insert_text("\nReferences: {}\n".format(len(rec.refs)))
+ self.add_info("\n<b>References</b>: {}\n".\
+ format(len(rec.refs)))
for idx, ref in enumerate(rec.refs):
- self.insert_text(" {}) ".format(idx))
- self.insert_text("{}".format(ref[0].idx), \
- self.find_path_obj(ref[0].idx))
+ self.add_info(" {}) <a href=\"{}\">{}</a>".format(idx,\
+ self.find_path_obj(ref[0].idx), ref[0].idx))
msg = ""
for arg in ref[1:]:
msg += " "
@@ -723,24 +788,24 @@ class App(tkinter.Frame):
msg += "-1"
else:
msg += "0x{:X}".format(arg)
- self.insert_text(msg + " / {}\n".format(ref[0].name))
+ self.add_info(msg + " / {}\n".format(hlesc(ref[0].name)))
resused = []
- self.insert_text("\nHandlers: {}\n".format(len(rec.acts)))
+ self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
for idx, (act_id, act_cond, act_arg, ops) in enumerate(rec.acts):
msg = petka.OPCODES.get(act_id, ["OP_{:X}".format(act_id)])[0]
if act_cond != 0xff or act_arg != 0xffff:
msg += " 0x{:02X} 0x{:04X}".format(act_cond, act_arg)
- self.insert_text(" {}) on {}, ops: {}\n".format(\
+ self.add_info(" {}) <u>on {}</u>, ops: {}\n".format(\
idx, msg, len(ops)))
for oidx, op in enumerate(ops):
msg = petka.OPCODES.get(op[1], ["OP_{:X}".format(op[1])])[0]
- self.insert_text(" {}) {} ".format(oidx, msg))
+ self.add_info(" {}) {} ".format(oidx, msg))
if op[0] == rec.idx:
- self.insert_text("THIS")
+ self.add_info("THIS")
else:
- self.insert_text("{}".format(op[0]), \
- self.find_path_obj_scene(op[0]))
+ self.add_info("<a href=\"{}\">{}</a>".format(\
+ self.find_path_obj_scene(op[0]), op[0]))
msg = ""
if op[2] != 0xffff:
if op[2] not in resused and op[2] in self.sim.res:
@@ -753,17 +818,15 @@ class App(tkinter.Frame):
msg += "-1"
else:
msg += "0x{:X}".format(arg)
- self.insert_text("{}\n".format(msg))
+ self.add_info("{}\n".format(msg))
if len(resused) > 0:
- self.insert_text("\nUsed resources: {}\n".format(len(resused)))
+ self.add_info("\n<b>Used resources</b>: {}\n".\
+ format(len(resused)))
for res_id in resused:
- self.insert_text(" ")
- self.insert_text("{}".format(res_id), \
- self.find_path_res(res_id))
- self.insert_text(" (0x{:X}) - {}\n".\
- format(res_id, self.sim.res[res_id]))
-
+ self.add_info(" <a href=\"{}\">{}</a> (0x{:X}) - {}\n".\
+ format(self.find_path_res(res_id), res_id, res_id, \
+ hlesc(self.sim.res[res_id])))
def path_names(self, path):
@@ -779,20 +842,20 @@ class App(tkinter.Frame):
self.select_lb_item(path[1])
name = self.sim.namesord[path[1]]
# display
- self.clear_text()
+ self.clear_info()
if not name:
- self.insert_text("Select name from list\n")
+ self.add_info("Select <b>name</b>\n")
else:
# name info
- self.insert_text("Alias: {}\n".format(name))
- self.insert_text("Value: {}\n\n".format(self.sim.names[name]))
+ self.add_info("<b>Alias</b>: {}\n".format(hlesc(name)))
+ self.add_info("Value: {}\n\n".format(self.sim.names[name]))
# search for objects
- self.insert_text("Applied for:\n")
+ self.add_info("<b>Applied for</b>:\n")
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
- self.insert_text(" ")
- self.insert_text("{}".format(obj.idx), ["objs", idx])
- self.insert_text(" - {}\n".format(obj.name))
+ self.add_info(" <a href=\"/objs/{}\">{}</a> (0x{:X}) "\
+ "- {}\n".format(idx, obj.idx, obj.idx, \
+ hlesc(obj.name)))
def path_invntr(self, path):
self.switch_view(0)
@@ -807,20 +870,20 @@ class App(tkinter.Frame):
self.select_lb_item(path[1])
name = self.sim.invntrord[path[1]]
# display
- self.clear_text()
+ self.clear_info()
if not name:
- self.insert_text("Select invntr from list\n")
+ self.add_info("Select <b>invntr</b>\n")
else:
# invntr info
- self.insert_text("Invntr: {}\n".format(name))
- self.insert_text("{}\n\n".format(self.sim.invntr[name]))
+ self.add_info("<b>Invntr</b>: {}\n".format(name))
+ self.add_info("{}\n\n".format(hlesc(self.sim.invntr[name])))
# search for objects
- self.insert_text("Applied for:\n")
+ self.add_info("<b>Applied for</b>:\n")
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
- self.insert_text(" ")
- self.insert_text("{}".format(obj.idx), ["objs", idx])
- self.insert_text(" - {}\n".format(obj.name))
+ self.add_info(" <a href=\"/objs/{}\">{}</a> (0x{:X}) "\
+ "- {}\n".format(idx, obj.idx, obj.idx, \
+ hlesc(obj.name)))
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
@@ -833,10 +896,10 @@ class App(tkinter.Frame):
self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
else:
self.switch_view(0)
- self.clear_text()
- self.insert_text("Information panel for {}\n".format(path))
+ self.clear_info()
+ self.add_info("Information panel for {}\n".format(path))
for i in range(100):
- self.insert_text(" Item {}\n".format(i))
+ self.add_info(" Item {}\n".format(i))
def on_open_data(self):
# open data - select TODO
Commit: 8c273ad39744cf27be1bac89fc14bd75d669e8bb
https://github.com/scummvm/scummvm-tools/commit/8c273ad39744cf27be1bac89fc14bd75d669e8bb
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Information for bmp and same
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ce0259371..18a1a4b1e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -644,7 +644,71 @@ class App(tkinter.Frame):
lb.insert(tkinter.END, "{} - {}".format(res_id, \
self.sim.res[res_id]))
- def path_res_open(self, res_id):
+ def path_res_open(self, res_id, mode):
+ if len(mode) == 0:
+ self.switch_view(0)
+ fn = self.sim.res[res_id]
+ self.clear_info()
+ self.add_info("<b>Resource</b>: {} (0x{:X}) - \"{}\"\n\n".\
+ format(res_id, res_id, hlesc(fn)))
+ resref = self.find_path_res(res_id)
+ self.add_info("<a href=\"{}/view\">View</a> "\
+ "<a href=\"{}/used\">Used by</a>\n\n".\
+ format(resref, resref))
+ try:
+ if fn[-4:].lower() == ".bmp":
+ self.add_info("<b>BMP image</b>: ")
+ bmpf = self.sim.fman.read_file_stream(fn)
+ bmp = petka.BMPLoader()
+ bmp.load_info(bmpf)
+ if bmp.image:
+ # PIL
+ self.add_info("Python Imaging\n")
+ self.add_info(" Mode: {}\n Size: {}x{}".\
+ format(bmp.image.mode, \
+ bmp.image.size[0], bmp.image.size[1]))
+ else:
+ self.add_info("internal BMP loader\n "\
+ "Mode: 16-bit\n Size: {}x{}".\
+ format(bmp.width, bmp.height))
+ if fn[-4:].lower() == ".flc":
+ self.add_info("<b>FLC animation</b>: ")
+ else:
+ self.add_info("No information availiable")
+ except:
+ self.add_info("Error loading {} - \"{}\" \n\n{}".\
+ format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
+
+ elif mode[0] == "view":
+ self.path_res_view(res_id)
+ elif mode[0] == "used":
+ self.switch_view(0)
+ fn = self.sim.res[res_id]
+ self.clear_info()
+ resref = self.find_path_res(res_id)
+ self.add_info("<b>Resource</b>: <a href=\"{}\">{}</a> (0x{:X}) "\
+ "- \"{}\"\n\n".format(resref, res_id, res_id, hlesc(fn)))
+
+ def usedby(lst, tp):
+ for idx, rec in enumerate(lst):
+ ru = False
+ for act_id, act_cond, act_arg, ops in rec.acts:
+ if ru: break
+ for op_id, op_code, op_res, op4, op5 in ops:
+ if res_id == op_res:
+ self.add_info(" <a href=\"/{}/{}\">{}</a> "\
+ "(0x{:X}) - {}\n".format(tp, idx, rec.idx, \
+ rec.idx, hlesc(rec.name)))
+ ru = True
+ break
+ #print(op_id, op_code, op_res, op4, op5)
+ self.add_info("<b>Used by objects</b>:\n")
+ usedby(self.sim.objects, "objs")
+ self.add_info("\n<b>Used by scenes</b>:\n")
+ usedby(self.sim.scenes, "scenes")
+
+
+ def path_res_view(self, res_id):
fn = self.sim.res[res_id]
if fn[-4:].lower() == ".bmp":
try:
@@ -659,20 +723,20 @@ class App(tkinter.Frame):
self.switch_view(0)
self.clear_info()
self.add_info("Error loading {} - \"{}\" \n\n{}".\
- format(res_id, fn, traceback.format_exc()))
+ format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
finally:
bmpf.close()
else:
self.switch_view(0)
self.clear_info()
self.add_info("Resource {} - \"{}\" cannot be displayed\n".\
- format(res_id, fn))
+ format(res_id, hlesc(fn)))
def path_res_status(self):
self.switch_view(0)
self.clear_info()
- self.add_info("<b>Resources</b>: <a href=\"/res\">{}</a>\nFiletypes:\n".format(\
- len(self.sim.res)))
+ self.add_info("<b>Resources</b>: <a href=\"/res\">{}</a>\n"\
+ "Filetypes:\n".format(len(self.sim.res)))
fts = {}
for res in self.sim.res.values():
fp = res.rfind(".")
@@ -696,7 +760,7 @@ class App(tkinter.Frame):
# parts
self.select_lb_item(path[2])
res_id = self.sim.resord[path[2]]
- self.path_res_open(res_id)
+ self.path_res_open(res_id, path[3:])
else:
self.path_res_status()
@@ -707,15 +771,17 @@ class App(tkinter.Frame):
lst.append(res_id)
if self.last_path[:3] != ("res", "flt", path[2]):
self.update_gui("Resources {} ({})".format(path[2], len(lst)))
+ self.insert_lb_act("All", "/res")
+ self.insert_lb_act("-", None)
for idx, res_id in enumerate(lst):
self.insert_lb_act("{} - {}".format(\
res_id, self.sim.res[res_id]), ["res", "flt", path[2], idx])
# change
if len(path) > 3:
# parts
- self.select_lb_item(path[3])
+ self.select_lb_item(path[3] + 2)
res_id = lst[path[3]]
- self.path_res_open(res_id)
+ self.path_res_open(res_id, path[4:])
else:
self.path_res_status()
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 41565ebc3..685b4b304 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -99,7 +99,15 @@ class BMPLoader:
rgb[off + 1] = (b16 >> 3) & 0b11111100
rgb[off + 2] = (b16 >> 8) & 0b11111000
return rgb
-
+
+ def load_info(self, f):
+ try:
+ pw, ph, pd = self.load_data_int16(f)
+ self.width = pw
+ self.height = ph
+ except:
+ f.seek(0)
+ self.image = Image.open(f)
def load_data(self, f):
try:
Commit: c6045ebfa0e0c17c9c4c429e995ccdb21615a128
https://github.com/scummvm/scummvm-tools/commit/c6045ebfa0e0c17c9c4c429e995ccdb21615a128
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: fix
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 18a1a4b1e..876697ea6 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -671,7 +671,7 @@ class App(tkinter.Frame):
self.add_info("internal BMP loader\n "\
"Mode: 16-bit\n Size: {}x{}".\
format(bmp.width, bmp.height))
- if fn[-4:].lower() == ".flc":
+ elif fn[-4:].lower() == ".flc":
self.add_info("<b>FLC animation</b>: ")
else:
self.add_info("No information availiable")
Commit: 593103b907bc1b9ac35747fa929fc38a67661d65
https://github.com/scummvm/scummvm-tools/commit/593103b907bc1b9ac35747fa929fc38a67661d65
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Fix switchinf resource filter
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 876697ea6..c7bb87f7b 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -616,42 +616,15 @@ class App(tkinter.Frame):
return self.path_res_all(path)
else:
return self.path_default(path)
-
- if self.last_path[:2] != path[:2]:
- #
- self.switch_view(0)
- self.update_gui("Resources: {}".format(path[2]))
- for idx,res_id in self.sim.resord:
- if self.sim.res[res_id].upper().endswith("." + path[2]):
- self.insert_lb_act("{} - {}".format(res_id))
-
- if len(self.last_path) == 0 or self.last_path[0] != "res":
- for idx, name in enumerate(self.sim.invntrord):
- self.insert_lb_act(name, ["invntr", idx])
- # list resources
- if self.curr_mode_sub is None:
- lb = self.update_gui_add_left_listbox("Resources")
- for res_id in self.sim.resord:
- lb.insert(tkinter.END, "{} - {}".format(res_id, \
- self.sim.res[res_id]))
- else:
- lb = self.update_gui_add_left_listbox("Resources: {}".\
- format(self.curr_mode_sub))
- for res_id in self.sim.resord:
- if self.sim.res[res_id].upper().endswith\
- ("." + self.curr_mode_sub):
- lb.insert(tkinter.END, "{} - {}".format(res_id, \
- self.sim.res[res_id]))
-
- def path_res_open(self, res_id, mode):
+ def path_res_open(self, pref, res_id, mode):
+ resref = "/" + "/".join([str(x) for x in pref])
if len(mode) == 0:
self.switch_view(0)
fn = self.sim.res[res_id]
self.clear_info()
self.add_info("<b>Resource</b>: {} (0x{:X}) - \"{}\"\n\n".\
format(res_id, res_id, hlesc(fn)))
- resref = self.find_path_res(res_id)
self.add_info("<a href=\"{}/view\">View</a> "\
"<a href=\"{}/used\">Used by</a>\n\n".\
format(resref, resref))
@@ -685,10 +658,8 @@ class App(tkinter.Frame):
self.switch_view(0)
fn = self.sim.res[res_id]
self.clear_info()
- resref = self.find_path_res(res_id)
self.add_info("<b>Resource</b>: <a href=\"{}\">{}</a> (0x{:X}) "\
"- \"{}\"\n\n".format(resref, res_id, res_id, hlesc(fn)))
-
def usedby(lst, tp):
for idx, rec in enumerate(lst):
ru = False
@@ -706,8 +677,7 @@ class App(tkinter.Frame):
usedby(self.sim.objects, "objs")
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes, "scenes")
-
-
+
def path_res_view(self, res_id):
fn = self.sim.res[res_id]
if fn[-4:].lower() == ".bmp":
@@ -760,7 +730,7 @@ class App(tkinter.Frame):
# parts
self.select_lb_item(path[2])
res_id = self.sim.resord[path[2]]
- self.path_res_open(res_id, path[3:])
+ self.path_res_open(path[:3], res_id, path[3:])
else:
self.path_res_status()
@@ -781,7 +751,7 @@ class App(tkinter.Frame):
# parts
self.select_lb_item(path[3] + 2)
res_id = lst[path[3]]
- self.path_res_open(res_id, path[4:])
+ self.path_res_open(path[:4], res_id, path[4:])
else:
self.path_res_status()
Commit: c508e1a902b80f1d018ce6642a3a02add1f1610b
https://github.com/scummvm/scummvm-tools/commit/c508e1a902b80f1d018ce6642a3a02add1f1610b
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: View FLC files (pallette not loaded)
Changed paths:
A engines/petka/petka/imgflc.py
engines/petka/p12explore.py
engines/petka/petka/__init__.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c7bb87f7b..17b3bd9b1 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -641,11 +641,28 @@ class App(tkinter.Frame):
format(bmp.image.mode, \
bmp.image.size[0], bmp.image.size[1]))
else:
- self.add_info("internal BMP loader\n "\
- "Mode: 16-bit\n Size: {}x{}".\
+ self.add_info("internal BMP loader\n"\
+ " Mode: 16-bit\n Size: {}x{}".\
format(bmp.width, bmp.height))
elif fn[-4:].lower() == ".flc":
self.add_info("<b>FLC animation</b>: ")
+ flcf = self.sim.fman.read_file_stream(fn)
+ flc = petka.FLCLoader()
+ flc.load_info(flcf)
+ if flc.image:
+ # PIL
+ self.add_info("Python Imaging\n")
+ self.add_info(" Mode: {}\n Size: {}x{}\n"
+ " Frames: {}\n Delay: {}".\
+ format(flc.image.mode, \
+ flc.image.size[0], flc.image.size[1],
+ flc.frame_num, flc.image.info["duration"]))
+ else:
+ self.add_info("internal FLC loader\n "\
+ " Mode: P\n Size: {}x{}\n"\
+ " Frames: {}\nDelay: {}".\
+ format(flc.width, flc.height, \
+ flc.frame_num, flc.delay))
else:
self.add_info("No information availiable")
except:
@@ -680,27 +697,35 @@ class App(tkinter.Frame):
def path_res_view(self, res_id):
fn = self.sim.res[res_id]
- if fn[-4:].lower() == ".bmp":
- try:
- bmpf = self.sim.fman.read_file_stream(fn)
+ try:
+ dataf = self.sim.fman.read_file_stream(fn)
+ if fn[-4:].lower() == ".bmp":
bmp = petka.BMPLoader()
- bmp.load_data(bmpf)
+ bmp.load_data(dataf)
self.main_image = \
self.make_image(bmp)
self.switch_view(1)
self.update_canvas()
- except:
+ elif fn[-4:].lower() == ".flc":
+ flcf = self.sim.fman.read_file_stream(fn)
+ flc = petka.FLCLoader()
+ flc.load_data(dataf)
+ self.main_image = \
+ self.make_image(flc)
+ self.switch_view(1)
+ self.update_canvas()
+ else:
self.switch_view(0)
self.clear_info()
- self.add_info("Error loading {} - \"{}\" \n\n{}".\
- format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
- finally:
- bmpf.close()
- else:
+ self.add_info("Resource {} - \"{}\" cannot be displayed\n".\
+ format(res_id, hlesc(fn)))
+ except:
self.switch_view(0)
self.clear_info()
- self.add_info("Resource {} - \"{}\" cannot be displayed\n".\
- format(res_id, hlesc(fn)))
+ self.add_info("Error loading {} - \"{}\" \n\n{}".\
+ format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
+ finally:
+ dataf.close()
def path_res_status(self):
self.switch_view(0)
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index 712beca4a..42388d6d6 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -4,3 +4,4 @@ class EngineError(Exception): pass
from .engine import Engine, OPCODES
from .fman import FileManager
from .imgbmp import BMPLoader
+from .imgflc import FLCLoader
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 685b4b304..631c367a0 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -74,22 +74,6 @@ class BMPLoader:
b16arr = array.array("H") # unsigned short
b16arr.frombytes(pd)
b16arr.byteswap()
-
- #rgb = array.array("B")
- #for b16 in b16arr:
- #rgb.append((b16 >> 5) & 0b11111000)
- #rgb.append((b16 << 5) & 0b11100000 | (b16 >> 11) & 0b00011100)
- #rgb.append((b16 << 0) &0b11111000)
- # rgb.append((b16 << 3) & 0b11111000)
- # rgb.append((b16 >> 3) & 0b11111100)
- # rgb.append((b16 >> 8) & 0b11111000)
- ## Y-mirror
- #newrgb = array.array("B")
- #for i in range(ph):
- # off = (ph - i - 1) * pw * 3
- # newrgb += rgb[off:off + pw * 3]
- #return newrgb
-
rgb = array.array("B", [0] * pw * ph * 3)
for j in range(ph):
for i in range(pw):
@@ -113,20 +97,6 @@ class BMPLoader:
try:
pw, ph, pd = self.load_data_int16(f)
if Image:
- # reload fixed
- #f.seek(0)
- #d = io.BytesIO()
- #d.write(f.read(10))
- #data_off = struct.unpack("<I", f.read(4))[0]
- #d.write(struct.pack("<I", data_off - 1))
- #d.write(f.read(data_off - 14))
- #fmt = "{}H".format(pw * ph)
- #data = struct.unpack(">" + fmt, f.read(pw * ph * 2))
- #d.write(struct.pack("<" + fmt, *data))
- #d.write(f.read(pw * ph * 2))
- #d.write(b"\xFF" * 10)
- #d.seek(0)
- #self.image = Image.open(d)
pd = self.pixelswap16(pw, ph, pd).tobytes()
self.image = Image.frombytes("RGB", (pw, ph), pd)
else:
diff --git a/engines/petka/petka/imgflc.py b/engines/petka/petka/imgflc.py
new file mode 100644
index 000000000..63040d7a8
--- /dev/null
+++ b/engines/petka/petka/imgflc.py
@@ -0,0 +1,36 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import array, struct, io
+
+from . import EngineError
+
+try:
+ from PIL import Image
+except ImportError:
+ Image = None
+
+class FLCLoader:
+ def __init__(self):
+ self.rgb = None
+ self.image = None
+ self.width = 0
+ self.height = 0
+ self.frame_num = 0
+ self.delay = 0
+
+
+ def load_info(self, f):
+ self.image = Image.open(f)
+ self.frame_num = 1
+ try:
+ while 1:
+ self.image.seek(self.image.tell() + 1)
+ self.frame_num += 1
+ except EOFError:
+ pass # end of sequence
+
+ def load_data(self, f):
+ self.image = Image.open(f)
+
Commit: 73d0812642bafe94831b921d90996171520f7089
https://github.com/scummvm/scummvm-tools/commit/73d0812642bafe94831b921d90996171520f7089
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Messages works
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 17b3bd9b1..e0bf5ab67 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -149,6 +149,8 @@ class App(tkinter.Frame):
self.path_handler["scenes"] = self.path_objs_scenes
self.path_handler["names"] = self.path_names
self.path_handler["invntr"] = self.path_invntr
+ self.path_handler["msgs"] = self.path_msgs
+ self.path_handler["dlgs"] = self.path_dlgs
self.path_handler["test"] = self.path_test
self.update_after()
@@ -179,24 +181,30 @@ class App(tkinter.Frame):
label = "Outline")
self.menuedit.add_separator()
self.menuedit.add_command(
- command = lambda: self.open_path(["parts"]),
+ command = lambda: self.open_path("/parts"),
label = "Select part")
self.menuedit.add_separator()
self.menuedit.add_command(
- command = lambda: self.open_path(["res"]),
+ command = lambda: self.open_path("/res"),
label = "Resources")
self.menuedit.add_command(
- command = lambda: self.open_path(["objs"]),
+ command = lambda: self.open_path("/objs"),
label = "Objects")
self.menuedit.add_command(
- command = lambda: self.open_path(["scenes"]),
+ command = lambda: self.open_path("/scenes"),
label = "Scenes")
self.menuedit.add_command(
- command = lambda: self.open_path(["names"]),
+ command = lambda: self.open_path("/names"),
label = "Names")
self.menuedit.add_command(
- command = lambda: self.open_path(["invntr"]),
+ command = lambda: self.open_path("/invntr"),
label = "Invntr")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/msgs"),
+ label = "Messages")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/dlgs"),
+ label = "Dialog groups")
def update_after(self):
if not self.need_update:
@@ -541,16 +549,20 @@ class App(tkinter.Frame):
def path_info_outline(self):
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
- self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
+ self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
format(len(self.sim.res)))
- self.add_info(" Objects: <a href=\"/objs\">{}</a>\n".\
+ self.add_info(" Objects: <a href=\"/objs\">{}</a>\n".\
format(len(self.sim.objects)))
- self.add_info(" Scenes: <a href=\"/scenes\">{}</a>\n".\
+ self.add_info(" Scenes: <a href=\"/scenes\">{}</a>\n".\
format(len(self.sim.scenes)))
- self.add_info(" Names: <a href=\"/names\">{}</a>\n".\
+ self.add_info(" Names: <a href=\"/names\">{}</a>\n".\
format(len(self.sim.names)))
- self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
+ self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
format(len(self.sim.invntr)))
+ self.add_info(" Messages <a href=\"/msgs\">{}</a>\n".\
+ format(len(self.sim.msgs)))
+ self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
+ format(len(self.sim.dlgs)))
def path_default(self, path):
@@ -566,12 +578,14 @@ class App(tkinter.Frame):
self.path_info_outline()
if self.sim is not None:
acts = [
- ("Parts ({})".format(len(self.sim.parts)), ["parts"]),
- ("Resources ({})".format(len(self.sim.res)), ["res"]),
- ("Objects ({})".format(len(self.sim.objects)), ["objs"]),
- ("Scenes ({})".format(len(self.sim.scenes)), ["scenes"]),
- ("Names ({})".format(len(self.sim.names)), ["names"]),
- ("Invntr ({})".format(len(self.sim.invntr)), ["invntr"]),
+ ("Parts ({})".format(len(self.sim.parts)), "/parts"),
+ ("Resources ({})".format(len(self.sim.res)), "/res"),
+ ("Objects ({})".format(len(self.sim.objects)), "/objs"),
+ ("Scenes ({})".format(len(self.sim.scenes)), "/scenes"),
+ ("Names ({})".format(len(self.sim.names)), "/names"),
+ ("Invntr ({})".format(len(self.sim.invntr)), "/invntr"),
+ ("Messages ({})".format(len(self.sim.msgs)), "/msgs"),
+ ("Dialog groups ({})".format(len(self.sim.dlgs)), "/dlgs"),
("-", None),
("Test image", ["test", "image"]),
("Test info", ["test","info"]),
@@ -889,6 +903,11 @@ class App(tkinter.Frame):
format(self.find_path_res(res_id), res_id, res_id, \
hlesc(self.sim.res[res_id])))
+ self.add_info("\n<b>Messages</b>:\n")
+ for msg in self.sim.msgs:
+ if msg.obj.idx != rec.idx: continue
+ self.add_info(" <a href=\"/msgs/{}\">{}</a> (0x{:X}) - {}\n".\
+ format(msg.idx, msg.idx, msg.idx, hlesc(msg.capt)))
def path_names(self, path):
self.switch_view(0)
@@ -946,6 +965,57 @@ class App(tkinter.Frame):
"- {}\n".format(idx, obj.idx, obj.idx, \
hlesc(obj.name)))
+ def path_msgs(self, path):
+ self.switch_view(0)
+ if self.last_path[:1] != ("msgs",):
+ self.update_gui("Messages ({})".format(len(self.sim.msgs)))
+ for idx, msg in enumerate(self.sim.msgs):
+ capt = msg.capt
+ if len(capt) > 25:
+ capt = capt[:25] + "|"
+ self.insert_lb_act("{} - {}".format(msg.idx, capt), \
+ [self.curr_path[0], idx])
+ # change
+ msg = None
+ if len(path) > 1:
+ # parts
+ self.select_lb_item(path[1])
+ msg = self.sim.msgs[path[1]]
+ # display
+ self.clear_info()
+ if not msg:
+ self.add_info("Select <b>message</b>\n")
+ else:
+ # msg info
+ self.add_info("<b>Message</b>: {}\n".format(path[1]))
+ self.add_info(" wav: {}\n".format(msg.wav))
+ self.add_info(" object: <a href=\"{}\">{}</a> (0x{:X}) - {}\n".\
+ format(self.find_path_obj(msg.arg1), msg.arg1, msg.arg1, \
+ msg.obj.name))
+ self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
+ self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
+ self.add_info("\n{}".format(hlesc(msg.capt)))
+
+ def path_dlgs(self, path):
+ self.switch_view(0)
+ if self.last_path[:1] != ("dlgs",):
+ self.update_gui("Dialog groups ({})".format(len(self.sim.dlgs)))
+ for idx, dlg in enumerate(self.sim.dlgs):
+ self.insert_lb_act(name, ["dlgs", idx])
+ # change
+ name = None
+ if len(path) > 1:
+ # parts
+ self.select_lb_item(path[1])
+ dlg = self.sim.dlgs[path[1]]
+ # display
+ self.clear_info()
+ if not name:
+ self.add_info("Select <b>dialog group</b>\n")
+ else:
+ # dlg info
+ self.add_info("<b>Dialog group</b>: {}\n".format(path[1]))
+
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
self.insert_lb_act("Outline", [])
@@ -969,7 +1039,7 @@ class App(tkinter.Frame):
def open_data_from(self, folder):
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
- self.sim.open_part(0, 0)
+ self.sim.open_part(1, 0)
def main():
root = tkinter.Tk()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index d6fc1b189..0979f2d3f 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -74,6 +74,15 @@ class ScrObject:
self.idx = idx
self.name = name
+class MsgObject:
+ def __init__(self, idx, wav, arg1, arg2, arg3):
+ self.idx = idx
+ self.wav = wav
+ self.arg1 = arg1
+ self.arg2 = arg2
+ self.arg3 = arg3
+ self.capt = None
+
class Engine:
def __init__(self):
self.fman = None
@@ -205,8 +214,12 @@ class Engine:
if not pf: continue
if strf in ini:
self.fman.load_store(ini[strf], 1)
- # load script
+ # load script.dat, backgrnd.bg and resources.qrc
self.load_script()
+ # load names & invntr
+ self.load_names()
+ # load dialogs
+ self.load_dialogs()
def load_script(self):
self.objects = []
@@ -269,13 +282,14 @@ class Engine:
obj = self.obj_idx[ref[0]]
scn.refs.append([obj] + list(ref[1:]))
else:
- raise EngineError("DEBUG: Object ID = 0x{:x} not found".\
+ raise EngineError("DEBUG: Scene ref 0x{:x} not found".\
format(obj[0]))
f = self.fman.read_file_stream(self.curr_path + "resource.qrc")
self.res, self.resord = self.parse_res(f)
f.close()
+ def load_names(self):
self.names = {}
self.namesord = []
fp = self.curr_path + "names.ini"
@@ -296,4 +310,39 @@ class Engine:
self.invntrord = ini["__order__"]["ALL"]
f.close()
+ def load_dialogs(self):
+ self.msgs = []
+ # DIALOGUES.LOD
+ fp = self.curr_path + "dialogue.lod"
+ if self.fman.exists(fp):
+ f = self.fman.read_file_stream(fp)
+ try:
+ temp = f.read(4)
+ num_msg = struct.unpack_from("<I", temp)[0]
+ for i in range(num_msg):
+ temp = f.read(24)
+ arg1, wav, arg2, arg3 = struct.unpack_from("<I12sII", temp)
+ msg = MsgObject(len(self.msgs), \
+ wav.decode(self.enc).strip(), arg1, arg2, arg3)
+ # scan objects
+ msg.obj = None
+ for obj in self.objects:
+ if obj.idx == arg1:
+ msg.obj = obj
+ break
+ if not msg.obj:
+ raise EngineError("DEBUG: Message ref = 0x{:x} not found".\
+ format(obj[0]))
+ self.msgs.append(msg)
+ for i, capt in enumerate(f.read().split(b"\x00")):
+ if i < len(self.msgs):
+ self.msgs[i].capt = capt.decode(self.enc)
+ finally:
+ f.close()
+
+ self.dlgs = []
+ # DIALOGUES.FIX
+ fp = self.curr_path + "dialogue.fix"
+ if self.fman.exists(fp):
+ f = self.fman.read_file_stream(fp)
Commit: f7fa014126386c5736640795821edee08191b9ba
https://github.com/scummvm/scummvm-tools/commit/f7fa014126386c5736640795821edee08191b9ba
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Messages works
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index e0bf5ab67..69bf2e2c9 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -903,11 +903,12 @@ class App(tkinter.Frame):
format(self.find_path_res(res_id), res_id, res_id, \
hlesc(self.sim.res[res_id])))
- self.add_info("\n<b>Messages</b>:\n")
- for msg in self.sim.msgs:
- if msg.obj.idx != rec.idx: continue
- self.add_info(" <a href=\"/msgs/{}\">{}</a> (0x{:X}) - {}\n".\
- format(msg.idx, msg.idx, msg.idx, hlesc(msg.capt)))
+ if isobj:
+ self.add_info("\n<b>Messages</b>:\n")
+ for msg in self.sim.msgs:
+ if msg.obj.idx != rec.idx: continue
+ self.add_info(" <a href=\"/msgs/{}\">{}</a> (0x{:X}) - {}\n".\
+ format(msg.idx, msg.idx, msg.idx, hlesc(msg.capt)))
def path_names(self, path):
self.switch_view(0)
Commit: ee14e7f6c33e74976e17f4fecd2a6802fa32eb1e
https://github.com/scummvm/scummvm-tools/commit/ee14e7f6c33e74976e17f4fecd2a6802fa32eb1e
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Dialogue.fix groups (partial)
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 69bf2e2c9..86f3f986b 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -975,7 +975,7 @@ class App(tkinter.Frame):
if len(capt) > 25:
capt = capt[:25] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt), \
- [self.curr_path[0], idx])
+ ["msgs", idx])
# change
msg = None
if len(path) > 1:
@@ -1001,21 +1001,34 @@ class App(tkinter.Frame):
self.switch_view(0)
if self.last_path[:1] != ("dlgs",):
self.update_gui("Dialog groups ({})".format(len(self.sim.dlgs)))
- for idx, dlg in enumerate(self.sim.dlgs):
- self.insert_lb_act(name, ["dlgs", idx])
+ for idx, grp in enumerate(self.sim.dlgs):
+ self.insert_lb_act("{} (0x{:X})".format(grp.idx, grp.idx), \
+ ["dlgs", idx])
# change
- name = None
+ grp = None
if len(path) > 1:
# parts
self.select_lb_item(path[1])
- dlg = self.sim.dlgs[path[1]]
+ grp = self.sim.dlgs[path[1]]
# display
self.clear_info()
- if not name:
+ if not grp:
self.add_info("Select <b>dialog group</b>\n")
else:
- # dlg info
- self.add_info("<b>Dialog group</b>: {}\n".format(path[1]))
+ # grp info
+ self.add_info("<b>Dialog group</b>: {} (0x{:X})\n".format(\
+ grp.idx, grp.idx))
+ self.add_info(" arg1: {} (0x{:X})\n\n".format(grp.arg1, grp.arg1))
+ self.add_info("<b>Dialog sets<b>: {}\n".format(len(grp.sets)))
+ for idx, dlgset in enumerate(grp.sets):
+ self.add_info(" {}) <u>0x{:X} 0x{:X} 0x{:X}</u>, dlgs: {}\n".\
+ format(idx, dlgset.arg1, dlgset.arg2, dlgset.arg3, \
+ len(dlgset.dlgs)))
+ for didx, dlg in enumerate(dlgset.dlgs):
+ self.add_info(" {}) 0x{:X} 0x{:X}, ops: {}\n".\
+ format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
+
+
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 0979f2d3f..25f230aec 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -83,6 +83,28 @@ class MsgObject:
self.arg3 = arg3
self.capt = None
+class DlgGrpObject:
+ def __init__(self, idx, num_sets, arg1):
+ self.idx = idx
+ self.num_sets = num_sets
+ self.arg1 = arg1
+ self.sets = None
+
+class DlgSetObject:
+ def __init__(self, num_dlgs, arg1, arg2, arg3):
+ self.num_dlgs = num_dlgs
+ self.arg1 = arg1
+ self.arg2 = arg2
+ self.arg3 = arg3
+ self.dlgs = None
+
+class DlgObject:
+ def __init__(self, op_start, arg1, arg2):
+ self.op_start = op_start
+ self.arg1 = arg1
+ self.arg2 = arg2
+ self.ops = None
+
class Engine:
def __init__(self):
self.fman = None
@@ -345,4 +367,36 @@ class Engine:
fp = self.curr_path + "dialogue.fix"
if self.fman.exists(fp):
f = self.fman.read_file_stream(fp)
+ try:
+ temp = f.read(4)
+ num_grps = struct.unpack_from("<I", temp)[0]
+ for i in range(num_grps):
+ temp = f.read(12)
+ idx, num_sets, arg1 = struct.unpack_from("<III", temp)
+ grp = DlgGrpObject(idx, num_sets, arg1)
+ self.dlgs.append(grp)
+ for grp in self.dlgs:
+ grp.sets = []
+ for i in range(grp.num_sets):
+ temp = f.read(16)
+ arg1, num_dlgs, arg2, arg3 = \
+ struct.unpack_from("<4I", temp)
+ dlgset = DlgSetObject(num_dlgs, arg1, arg2, arg3)
+ grp.sets.append(dlgset)
+ for dlgset in grp.sets:
+ dlgset.dlgs = []
+ for i in range(dlgset.num_dlgs):
+ temp = f.read(12)
+ op_start, arg1, arg2 = \
+ struct.unpack_from("<3I", temp)
+ dlg = DlgObject(op_start, arg1, arg2)
+ dlg.ops = []
+ dlgset.dlgs.append(dlg)
+ temp = f.read(4)
+ num_ops = struct.unpack_from("<I", temp)[0]
+ for i in range(num_ops):
+ temp = f.read(4)
+ ref, arg, code = struct.unpack_from("<HBB", temp)
+ finally:
+ f.close()
Commit: 423e063c13f3065a75994f1714c0b87139397a1e
https://github.com/scummvm/scummvm-tools/commit/423e063c13f3065a75994f1714c0b87139397a1e
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: dialogues works
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 86f3f986b..368d716eb 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1025,9 +1025,21 @@ class App(tkinter.Frame):
format(idx, dlgset.arg1, dlgset.arg2, dlgset.arg3, \
len(dlgset.dlgs)))
for didx, dlg in enumerate(dlgset.dlgs):
- self.add_info(" {}) 0x{:X} 0x{:X}, ops: {}\n".\
+ self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
-
+ for op in dlg.ops:
+ cmt = ""
+ opref = "0x{:X}".format(op.ref)
+ opcode = "OP_{:02X}".format(op.opcode)
+ if op.opcode == 7:
+ opcode = "PLAY"
+ if op.msg:
+ opref = "<a href=\"/msgs/{}\">{}</a>".format(\
+ op.ref, op.ref)
+ cmt = " / (0x{:X}) - {}".\
+ format(op.ref, hlesc(op.msg.capt))
+ self.add_info(" {} 0x{:X} {}{}\n".\
+ format(opcode, op.arg, opref, hlesc(cmt)))
def path_test(self, path):
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 25f230aec..8b8006e86 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -104,6 +104,13 @@ class DlgObject:
self.arg1 = arg1
self.arg2 = arg2
self.ops = None
+
+class DlgOpObject:
+ def __init__(self, opcode, arg, ref):
+ self.opcode = opcode
+ self.arg = arg
+ self.ref = ref
+ self.msg = None
class Engine:
def __init__(self):
@@ -347,11 +354,7 @@ class Engine:
msg = MsgObject(len(self.msgs), \
wav.decode(self.enc).strip(), arg1, arg2, arg3)
# scan objects
- msg.obj = None
- for obj in self.objects:
- if obj.idx == arg1:
- msg.obj = obj
- break
+ msg.obj = self.obj_idx.get(arg1, None)
if not msg.obj:
raise EngineError("DEBUG: Message ref = 0x{:x} not found".\
format(obj[0]))
@@ -363,6 +366,7 @@ class Engine:
f.close()
self.dlgs = []
+ self.dlgops = []
# DIALOGUES.FIX
fp = self.curr_path + "dialogue.fix"
if self.fman.exists(fp):
@@ -375,6 +379,7 @@ class Engine:
idx, num_sets, arg1 = struct.unpack_from("<III", temp)
grp = DlgGrpObject(idx, num_sets, arg1)
self.dlgs.append(grp)
+ opref = {}
for grp in self.dlgs:
grp.sets = []
for i in range(grp.num_sets):
@@ -389,14 +394,33 @@ class Engine:
temp = f.read(12)
op_start, arg1, arg2 = \
struct.unpack_from("<3I", temp)
+ if op_start in opref:
+ raise EngineError(
+ "Multiple dialog opcodes reference")
dlg = DlgObject(op_start, arg1, arg2)
- dlg.ops = []
+ opref[op_start] = dlg
+ dlg.ops = None
dlgset.dlgs.append(dlg)
temp = f.read(4)
num_ops = struct.unpack_from("<I", temp)[0]
for i in range(num_ops):
temp = f.read(4)
ref, arg, code = struct.unpack_from("<HBB", temp)
+ dlgop = DlgOpObject(code, arg, ref)
+ if ref < len(self.msgs):
+ dlgop.msg = self.msgs[ref]
+ self.dlgops.append(dlgop)
+ dlg = None
+ oparr = []
+ for idx, oprec in enumerate(self.dlgops):
+ if idx in opref:
+ if len(oparr) > 0:
+ dlg.ops = oparr
+ oparr = []
+ dlg = opref[idx]
+ oparr.append(oprec)
+ if len(oparr) > 0:
+ dlg.ops = oparr
finally:
f.close()
Commit: d3f052e1bd65761f574bbb178f45805c523164c7
https://github.com/scummvm/scummvm-tools/commit/d3f052e1bd65761f574bbb178f45805c523164c7
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: links from messages to dialoggroups
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 368d716eb..7348b0df8 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -546,6 +546,12 @@ class App(tkinter.Frame):
return "/invntr/{}".format(idx)
return "/no_invntr/{}".format(key)
+ def find_path_dlggrp(self, grp_idx):
+ for idx, grp in enumerate(self.sim.dlgs):
+ if grp.idx == grp_idx:
+ return "/dlgs/{}".format(idx)
+ return "/no_dlgs/{}".format(grp_idx)
+
def path_info_outline(self):
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
@@ -995,8 +1001,21 @@ class App(tkinter.Frame):
msg.obj.name))
self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
- self.add_info("\n{}".format(hlesc(msg.capt)))
+ self.add_info("\n{}\n".format(hlesc(msg.capt)))
+ self.add_info("\n<b>Used by dialog groups</b>:\n")
+ for grp in self.sim.dlgs:
+ for dlgset in grp.sets:
+ for dlg in dlgset.dlgs:
+ for op in dlg.ops:
+ if not op.msg: continue
+ if op.msg.idx == msg.idx and op.opcode == 7:
+ self.add_info(" <a href=\"{}\">{}</a>\n".\
+ format(self.find_path_dlggrp(grp.idx),
+ grp.idx))
+
+
+
def path_dlgs(self, path):
self.switch_view(0)
if self.last_path[:1] != ("dlgs",):
@@ -1034,12 +1053,15 @@ class App(tkinter.Frame):
if op.opcode == 7:
opcode = "PLAY"
if op.msg:
- opref = "<a href=\"/msgs/{}\">{}</a>".format(\
+ opref = "<a href=\"/msgs/{}\">{}</a>".format(
op.ref, op.ref)
- cmt = " / (0x{:X}) - {}".\
- format(op.ref, hlesc(op.msg.capt))
+ objref = "<a href=\"{}\">{}</a>".format(
+ self.find_path_obj(op.msg.obj.idx),
+ op.msg.obj.idx)
+ cmt = " / (0x{:X}) - {}, {}".\
+ format(op.ref, objref, hlesc(op.msg.capt))
self.add_info(" {} 0x{:X} {}{}\n".\
- format(opcode, op.arg, opref, hlesc(cmt)))
+ format(opcode, op.arg, opref, cmt))
def path_test(self, path):
Commit: a1665895e4e850103584d67c36cea85e579c567f
https://github.com/scummvm/scummvm-tools/commit/a1665895e4e850103584d67c36cea85e579c567f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 7348b0df8..7b02e6063 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -25,6 +25,10 @@ APPNAME = "P1&2 Explorer"
def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
+def fmt_opcode(opcode):
+ return petka.OPCODES.get(opcode, ["OP_{:X}".format(opcode)])[0]
+
+
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
def __init__(self, text):
@@ -874,14 +878,13 @@ class App(tkinter.Frame):
resused = []
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
for idx, (act_id, act_cond, act_arg, ops) in enumerate(rec.acts):
- msg = petka.OPCODES.get(act_id, ["OP_{:X}".format(act_id)])[0]
+ msg = fmt_opcode(act_id)
if act_cond != 0xff or act_arg != 0xffff:
msg += " 0x{:02X} 0x{:04X}".format(act_cond, act_arg)
self.add_info(" {}) <u>on {}</u>, ops: {}\n".format(\
idx, msg, len(ops)))
for oidx, op in enumerate(ops):
- msg = petka.OPCODES.get(op[1], ["OP_{:X}".format(op[1])])[0]
- self.add_info(" {}) {} ".format(oidx, msg))
+ self.add_info(" {}) {} ".format(oidx, fmt_opcode(op[1])))
if op[0] == rec.idx:
self.add_info("THIS")
else:
@@ -969,7 +972,7 @@ class App(tkinter.Frame):
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
self.add_info(" <a href=\"/objs/{}\">{}</a> (0x{:X}) "\
- "- {}\n".format(idx, obj.idx, obj.idx, \
+ "- {}\n".format(idx, obj.idx, obj.idx,
hlesc(obj.name)))
def path_msgs(self, path):
@@ -980,7 +983,7 @@ class App(tkinter.Frame):
capt = msg.capt
if len(capt) > 25:
capt = capt[:25] + "|"
- self.insert_lb_act("{} - {}".format(msg.idx, capt), \
+ self.insert_lb_act("{} - {}".format(msg.idx, capt),
["msgs", idx])
# change
msg = None
@@ -997,8 +1000,8 @@ class App(tkinter.Frame):
self.add_info("<b>Message</b>: {}\n".format(path[1]))
self.add_info(" wav: {}\n".format(msg.wav))
self.add_info(" object: <a href=\"{}\">{}</a> (0x{:X}) - {}\n".\
- format(self.find_path_obj(msg.arg1), msg.arg1, msg.arg1, \
- msg.obj.name))
+ format(self.find_path_obj(msg.arg1), msg.arg1, msg.arg1,
+ msg.obj.name))
self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
self.add_info("\n{}\n".format(hlesc(msg.capt)))
@@ -1021,7 +1024,7 @@ class App(tkinter.Frame):
if self.last_path[:1] != ("dlgs",):
self.update_gui("Dialog groups ({})".format(len(self.sim.dlgs)))
for idx, grp in enumerate(self.sim.dlgs):
- self.insert_lb_act("{} (0x{:X})".format(grp.idx, grp.idx), \
+ self.insert_lb_act("{} (0x{:X})".format(grp.idx, grp.idx),
["dlgs", idx])
# change
grp = None
Commit: 58398995a414167a4830323f2d486e8896df53b8
https://github.com/scummvm/scummvm-tools/commit/58398995a414167a4830323f2d486e8896df53b8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 7b02e6063..c14e35004 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1041,7 +1041,7 @@ class App(tkinter.Frame):
self.add_info("<b>Dialog group</b>: {} (0x{:X})\n".format(\
grp.idx, grp.idx))
self.add_info(" arg1: {} (0x{:X})\n\n".format(grp.arg1, grp.arg1))
- self.add_info("<b>Dialog sets<b>: {}\n".format(len(grp.sets)))
+ self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.sets)))
for idx, dlgset in enumerate(grp.sets):
self.add_info(" {}) <u>0x{:X} 0x{:X} 0x{:X}</u>, dlgs: {}\n".\
format(idx, dlgset.arg1, dlgset.arg2, dlgset.arg3, \
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 8b8006e86..7d6b07643 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -73,6 +73,7 @@ class ScrObject:
def __init__(self, idx, name):
self.idx = idx
self.name = name
+ self.acts = None
class MsgObject:
def __init__(self, idx, wav, arg1, arg2, arg3):
@@ -88,14 +89,15 @@ class DlgGrpObject:
self.idx = idx
self.num_sets = num_sets
self.arg1 = arg1
- self.sets = None
+ self.acts = None
-class DlgSetObject:
- def __init__(self, num_dlgs, arg1, arg2, arg3):
+class DlgActObject:
+ def __init__(self, num_dlgs, opcode, ref, arg1, arg2):
self.num_dlgs = num_dlgs
+ self.opcode = opcode
+ self.ref = ref
self.arg1 = arg1
self.arg2 = arg2
- self.arg3 = arg3
self.dlgs = None
class DlgObject:
Commit: ac443fbabfdc4e5af3f7e80d8fd9ce2a6f1ea02c
https://github.com/scummvm/scummvm-tools/commit/ac443fbabfdc4e5af3f7e80d8fd9ce2a6f1ea02c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: links from dialog acts to objects
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c14e35004..64a1fb432 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -26,7 +26,10 @@ def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
def fmt_opcode(opcode):
- return petka.OPCODES.get(opcode, ["OP_{:X}".format(opcode)])[0]
+ return petka.OPCODES.get(opcode, ["OP{:04X}".format(opcode)])[0]
+
+def fmt_hl(loc, desc):
+ return "<a href=\"{}\">{}</a>".format(loc, desc)
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
@@ -158,9 +161,10 @@ class App(tkinter.Frame):
self.path_handler["test"] = self.path_test
self.update_after()
- self.open_path("")
+ #self.open_path("")
#self.open_path(self.find_path_scene(36))
#self.open_path(["res", "flt", "BMP", 7])
+ self.open_path(["dlgs", 6])
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -537,6 +541,26 @@ class App(tkinter.Frame):
if rec.idx == rec_idx:
return "/scenes/{}".format(idx)
return "/no_obj_scene/{}".format(rec_idx)
+
+ def fmt_hl_rec(self, lst, pref, rec_idx, full = False):
+ for idx, rec in enumerate(lst):
+ if rec.idx == rec_idx:
+ fmt = fmt_hl("/{}/{}".format(pref, idx), str(rec_idx))
+ if full:
+ fmt += " (0x{:X}) - {}".format(rec.idx, hlesc(rec.name))
+ return fmt
+ return "{} (0x{:X})".format(rec_idx, rec_idx)
+
+ def fmt_hl_obj(self, obj_idx, full = False):
+ return self.fmt_hl_rec(self.sim.objects, "objs", obj_idx, full)
+
+ def fmt_hl_scene(self, scn_idx, full = False):
+ return self.fmt_hl_rec(self.sim.scenes, "scene", scn_idx, full)
+
+ def fmt_hl_obj_scene(self, rec_idx, full = False):
+ if rec_idx in self.sim.obj_idx:
+ return self.fmt_hl_rec(self.sim.objects, "objs", obj_idx, full)
+ return self.fmt_hl_rec(self.sim.scenes, "scene", scn_idx, full)
def find_path_name(self, key):
for idx, name in enumerate(self.sim.namesord):
@@ -1041,12 +1065,13 @@ class App(tkinter.Frame):
self.add_info("<b>Dialog group</b>: {} (0x{:X})\n".format(\
grp.idx, grp.idx))
self.add_info(" arg1: {} (0x{:X})\n\n".format(grp.arg1, grp.arg1))
- self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.sets)))
- for idx, dlgset in enumerate(grp.sets):
- self.add_info(" {}) <u>0x{:X} 0x{:X} 0x{:X}</u>, dlgs: {}\n".\
- format(idx, dlgset.arg1, dlgset.arg2, dlgset.arg3, \
- len(dlgset.dlgs)))
- for didx, dlg in enumerate(dlgset.dlgs):
+ self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.acts)))
+ for idx, act in enumerate(grp.acts):
+ self.add_info(" {}) <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: "\
+ "{} / {}\n".format(idx, fmt_opcode(act.opcode),
+ self.fmt_hl_obj(act.ref), act.arg1, act.arg2, \
+ len(act.dlgs), self.fmt_hl_obj(act.ref, True)))
+ for didx, dlg in enumerate(act.dlgs):
self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
for op in dlg.ops:
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 7d6b07643..d0ae3c49f 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -85,9 +85,9 @@ class MsgObject:
self.capt = None
class DlgGrpObject:
- def __init__(self, idx, num_sets, arg1):
+ def __init__(self, idx, num_acts, arg1):
self.idx = idx
- self.num_sets = num_sets
+ self.num_acts = num_acts
self.arg1 = arg1
self.acts = None
@@ -99,6 +99,7 @@ class DlgActObject:
self.arg1 = arg1
self.arg2 = arg2
self.dlgs = None
+ self.obj = None
class DlgObject:
def __init__(self, op_start, arg1, arg2):
@@ -378,21 +379,25 @@ class Engine:
num_grps = struct.unpack_from("<I", temp)[0]
for i in range(num_grps):
temp = f.read(12)
- idx, num_sets, arg1 = struct.unpack_from("<III", temp)
- grp = DlgGrpObject(idx, num_sets, arg1)
+ idx, num_acts, arg1 = struct.unpack_from("<III", temp)
+ grp = DlgGrpObject(idx, num_acts, arg1)
self.dlgs.append(grp)
opref = {}
for grp in self.dlgs:
- grp.sets = []
- for i in range(grp.num_sets):
+ grp.acts = []
+ for i in range(grp.num_acts):
temp = f.read(16)
- arg1, num_dlgs, arg2, arg3 = \
- struct.unpack_from("<4I", temp)
- dlgset = DlgSetObject(num_dlgs, arg1, arg2, arg3)
- grp.sets.append(dlgset)
- for dlgset in grp.sets:
- dlgset.dlgs = []
- for i in range(dlgset.num_dlgs):
+ opcode, ref, num_dlgs, arg1, arg2 = \
+ struct.unpack_from("<2H3I", temp)
+ act = DlgActObject(num_dlgs, opcode, ref, arg1, arg2)
+ if ref not in self.obj_idx:
+ raise EngineError("Dialog group 0x{:x} refered "\
+ "to unexisted object 0x{:x}".format(grp.idx, ref))
+ act.obj = self.obj_idx[act.ref]
+ grp.acts.append(act)
+ for act in grp.acts:
+ act.dlgs = []
+ for i in range(act.num_dlgs):
temp = f.read(12)
op_start, arg1, arg2 = \
struct.unpack_from("<3I", temp)
@@ -402,7 +407,7 @@ class Engine:
dlg = DlgObject(op_start, arg1, arg2)
opref[op_start] = dlg
dlg.ops = None
- dlgset.dlgs.append(dlg)
+ act.dlgs.append(dlg)
temp = f.read(4)
num_ops = struct.unpack_from("<I", temp)[0]
for i in range(num_ops):
Commit: f6dc6ed300fdb606e79f25e7a51c9f14507e0339
https://github.com/scummvm/scummvm-tools/commit/f6dc6ed300fdb606e79f25e7a51c9f14507e0339
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 64a1fb432..00ff0ef5d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -555,12 +555,12 @@ class App(tkinter.Frame):
return self.fmt_hl_rec(self.sim.objects, "objs", obj_idx, full)
def fmt_hl_scene(self, scn_idx, full = False):
- return self.fmt_hl_rec(self.sim.scenes, "scene", scn_idx, full)
+ return self.fmt_hl_rec(self.sim.scenes, "scenes", scn_idx, full)
def fmt_hl_obj_scene(self, rec_idx, full = False):
if rec_idx in self.sim.obj_idx:
- return self.fmt_hl_rec(self.sim.objects, "objs", obj_idx, full)
- return self.fmt_hl_rec(self.sim.scenes, "scene", scn_idx, full)
+ return self.fmt_hl_rec(self.sim.objects, "objs", rec_idx, full)
+ return self.fmt_hl_rec(self.sim.scenes, "scenes", rec_idx, full)
def find_path_name(self, key):
for idx, name in enumerate(self.sim.namesord):
@@ -580,6 +580,9 @@ class App(tkinter.Frame):
return "/dlgs/{}".format(idx)
return "/no_dlgs/{}".format(grp_idx)
+ def fmt_hl_msg(self, obj_idx, full = False):
+ return self.fmt_hl_rec(self.sim.msgs, "msgs", obj_idx, full)
+
def path_info_outline(self):
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
@@ -732,9 +735,8 @@ class App(tkinter.Frame):
if ru: break
for op_id, op_code, op_res, op4, op5 in ops:
if res_id == op_res:
- self.add_info(" <a href=\"/{}/{}\">{}</a> "\
- "(0x{:X}) - {}\n".format(tp, idx, rec.idx, \
- rec.idx, hlesc(rec.name)))
+ self.add_info(" " +
+ self.fmt_hl_obj_scene(rec.idx, True) + "\n")
ru = True
break
#print(op_id, op_code, op_res, op4, op5)
@@ -789,7 +791,7 @@ class App(tkinter.Frame):
ftk = list(fts.keys())
ftk.sort()
for ft in ftk:
- self.add_info(" <a href=\"/res/flt/{}\">{}</a>: {}\n".format(\
+ self.add_info(" <a href=\"/res/flt/{}\">{}</a>: {}\n".format(
ft, ft, fts[ft]))
def path_res_all(self, path):
@@ -860,14 +862,13 @@ class App(tkinter.Frame):
self.add_info(" Index: {} (0x{:X})\n Name: {}\n".\
format(rec.idx, rec.idx, hlesc(rec.name)))
if rec.name in self.sim.names:
- self.add_info(" <a href=\"{}\">Alias</a>: {}\n".format(\
- self.find_path_name(rec.name), \
- hlesc(self.sim.names[rec.name])))
+ self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ "Alias") + ": {}\n".format(
+ hlesc(self.sim.names[rec.name])))
if rec.name in self.sim.invntr:
- self.add_info(" <a href=\"{}\">Invntr</a>: {}\n".format(\
- self.find_path_invntr(rec.name), \
- hlesc(self.sim.invntr[rec.name])))
-
+ self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ "Invntr") + ": {}\n".format(
+ hlesc(self.sim.invntr[rec.name])))
# references / backreferences
if isobj:
# search where object used
@@ -875,9 +876,8 @@ class App(tkinter.Frame):
for scn in self.sim.scenes:
for ref in scn.refs:
if ref[0].idx == rec.idx:
- self.add_info(" <a href=\"{}\">{}</a> (0x{:X}) "\
- "- {}\n".format(self.find_path_scene(scn.idx), \
- scn.idx, scn.idx, scn.name))
+ self.add_info(" " +
+ self.fmt_hl_scene(scn.idx, True) + "\n")
break
else:
if len(rec.refs) == 0:
@@ -886,8 +886,8 @@ class App(tkinter.Frame):
self.add_info("\n<b>References</b>: {}\n".\
format(len(rec.refs)))
for idx, ref in enumerate(rec.refs):
- self.add_info(" {}) <a href=\"{}\">{}</a>".format(idx,\
- self.find_path_obj(ref[0].idx), ref[0].idx))
+ self.add_info(" {}) ".format(idx) +
+ self.fmt_hl_obj(ref[0].idx))
msg = ""
for arg in ref[1:]:
msg += " "
@@ -940,8 +940,7 @@ class App(tkinter.Frame):
self.add_info("\n<b>Messages</b>:\n")
for msg in self.sim.msgs:
if msg.obj.idx != rec.idx: continue
- self.add_info(" <a href=\"/msgs/{}\">{}</a> (0x{:X}) - {}\n".\
- format(msg.idx, msg.idx, msg.idx, hlesc(msg.capt)))
+ self.add_info(" " + self.fmt_hl_msg(msg.idx, True) + "\n")
def path_names(self, path):
self.switch_view(0)
@@ -967,10 +966,7 @@ class App(tkinter.Frame):
self.add_info("<b>Applied for</b>:\n")
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
- self.add_info(" <a href=\"/objs/{}\">{}</a> (0x{:X}) "\
- "- {}\n".format(idx, obj.idx, obj.idx, \
- hlesc(obj.name)))
-
+ self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
def path_invntr(self, path):
self.switch_view(0)
if self.last_path[:1] != ("invntr",):
@@ -995,16 +991,14 @@ class App(tkinter.Frame):
self.add_info("<b>Applied for</b>:\n")
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
- self.add_info(" <a href=\"/objs/{}\">{}</a> (0x{:X}) "\
- "- {}\n".format(idx, obj.idx, obj.idx,
- hlesc(obj.name)))
+ self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
def path_msgs(self, path):
self.switch_view(0)
if self.last_path[:1] != ("msgs",):
self.update_gui("Messages ({})".format(len(self.sim.msgs)))
for idx, msg in enumerate(self.sim.msgs):
- capt = msg.capt
+ capt = msg.name
if len(capt) > 25:
capt = capt[:25] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt),
@@ -1028,12 +1022,12 @@ class App(tkinter.Frame):
msg.obj.name))
self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
- self.add_info("\n{}\n".format(hlesc(msg.capt)))
+ self.add_info("\n{}\n".format(hlesc(msg.name)))
self.add_info("\n<b>Used by dialog groups</b>:\n")
for grp in self.sim.dlgs:
- for dlgset in grp.sets:
- for dlg in dlgset.dlgs:
+ for act in grp.acts:
+ for dlg in act.dlgs:
for op in dlg.ops:
if not op.msg: continue
if op.msg.idx == msg.idx and op.opcode == 7:
@@ -1083,11 +1077,9 @@ class App(tkinter.Frame):
if op.msg:
opref = "<a href=\"/msgs/{}\">{}</a>".format(
op.ref, op.ref)
- objref = "<a href=\"{}\">{}</a>".format(
- self.find_path_obj(op.msg.obj.idx),
- op.msg.obj.idx)
+ objref = self.fmt_hl_obj(op.msg.obj.idx)
cmt = " / (0x{:X}) - {}, {}".\
- format(op.ref, objref, hlesc(op.msg.capt))
+ format(op.ref, objref, hlesc(op.msg.name))
self.add_info(" {} 0x{:X} {}{}\n".\
format(opcode, op.arg, opref, cmt))
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index d0ae3c49f..539944a36 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -82,7 +82,7 @@ class MsgObject:
self.arg1 = arg1
self.arg2 = arg2
self.arg3 = arg3
- self.capt = None
+ self.name = None
class DlgGrpObject:
def __init__(self, idx, num_acts, arg1):
@@ -364,7 +364,7 @@ class Engine:
self.msgs.append(msg)
for i, capt in enumerate(f.read().split(b"\x00")):
if i < len(self.msgs):
- self.msgs[i].capt = capt.decode(self.enc)
+ self.msgs[i].name = capt.decode(self.enc)
finally:
f.close()
Commit: ace762238255ee93e0b74c0014d76833617714dc
https://github.com/scummvm/scummvm-tools/commit/ace762238255ee93e0b74c0014d76833617714dc
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: more links to dialogs
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 00ff0ef5d..d64404a18 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,6 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
+VERSION = "v0.2 2014-05-15"
def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
@@ -159,12 +160,14 @@ class App(tkinter.Frame):
self.path_handler["msgs"] = self.path_msgs
self.path_handler["dlgs"] = self.path_dlgs
self.path_handler["test"] = self.path_test
+ self.path_handler["about"] = self.path_about
self.update_after()
- #self.open_path("")
+ self.open_path("/about")
#self.open_path(self.find_path_scene(36))
#self.open_path(["res", "flt", "BMP", 7])
- self.open_path(["dlgs", 6])
+ #self.open_path(["dlgs", 6])
+ #self.open_path(self.find_path_obj(448))
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -214,6 +217,13 @@ class App(tkinter.Frame):
command = lambda: self.open_path("/dlgs"),
label = "Dialog groups")
+ self.menuhelp = tkinter.Menu(self.master, tearoff = 0)
+ self.menubar.add_cascade(menu = self.menuhelp,
+ label = "Help")
+ self.menuhelp.add_command(
+ command = lambda: self.open_path("/about"),
+ label = "About")
+
def update_after(self):
if not self.need_update:
self.after_idle(self.on_idle)
@@ -547,7 +557,10 @@ class App(tkinter.Frame):
if rec.idx == rec_idx:
fmt = fmt_hl("/{}/{}".format(pref, idx), str(rec_idx))
if full:
- fmt += " (0x{:X}) - {}".format(rec.idx, hlesc(rec.name))
+ try:
+ fmt += " (0x{:X}) - {}".format(rec.idx, hlesc(rec.name))
+ except:
+ fmt += " (0x{:X})".format(rec.idx)
return fmt
return "{} (0x{:X})".format(rec_idx, rec_idx)
@@ -583,6 +596,9 @@ class App(tkinter.Frame):
def fmt_hl_msg(self, obj_idx, full = False):
return self.fmt_hl_rec(self.sim.msgs, "msgs", obj_idx, full)
+ def fmt_hl_dlg(self, grp_idx, full = False):
+ return self.fmt_hl_rec(self.sim.dlgs, "dlgs", grp_idx, full)
+
def path_info_outline(self):
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
@@ -676,8 +692,7 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("<b>Resource</b>: {} (0x{:X}) - \"{}\"\n\n".\
format(res_id, res_id, hlesc(fn)))
- self.add_info("<a href=\"{}/view\">View</a> "\
- "<a href=\"{}/used\">Used by</a>\n\n".\
+ self.add_info("<a href=\"{}/view\">View</a>\n\n".\
format(resref, resref))
try:
if fn[-4:].lower() == ".bmp":
@@ -716,19 +731,13 @@ class App(tkinter.Frame):
flc.frame_num, flc.delay))
else:
self.add_info("No information availiable")
+
+
except:
self.add_info("Error loading {} - \"{}\" \n\n{}".\
format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
-
- elif mode[0] == "view":
- self.path_res_view(res_id)
- elif mode[0] == "used":
- self.switch_view(0)
- fn = self.sim.res[res_id]
- self.clear_info()
- self.add_info("<b>Resource</b>: <a href=\"{}\">{}</a> (0x{:X}) "\
- "- \"{}\"\n\n".format(resref, res_id, res_id, hlesc(fn)))
- def usedby(lst, tp):
+
+ def usedby(lst):
for idx, rec in enumerate(lst):
ru = False
for act_id, act_cond, act_arg, ops in rec.acts:
@@ -740,10 +749,14 @@ class App(tkinter.Frame):
ru = True
break
#print(op_id, op_code, op_res, op4, op5)
- self.add_info("<b>Used by objects</b>:\n")
- usedby(self.sim.objects, "objs")
+
+ self.add_info("\n\n<b>Used by objects</b>:\n")
+ usedby(self.sim.objects)
self.add_info("\n<b>Used by scenes</b>:\n")
- usedby(self.sim.scenes, "scenes")
+ usedby(self.sim.scenes)
+
+ elif mode[0] == "view":
+ self.path_res_view(res_id)
def path_res_view(self, res_id):
fn = self.sim.res[res_id]
@@ -900,6 +913,7 @@ class App(tkinter.Frame):
self.add_info(msg + " / {}\n".format(hlesc(ref[0].name)))
resused = []
+ dlgused = []
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
for idx, (act_id, act_cond, act_arg, ops) in enumerate(rec.acts):
msg = fmt_opcode(act_id)
@@ -909,11 +923,12 @@ class App(tkinter.Frame):
idx, msg, len(ops)))
for oidx, op in enumerate(ops):
self.add_info(" {}) {} ".format(oidx, fmt_opcode(op[1])))
+ cmt = ""
if op[0] == rec.idx:
self.add_info("THIS")
else:
- self.add_info("<a href=\"{}\">{}</a>".format(\
- self.find_path_obj_scene(op[0]), op[0]))
+ self.add_info(self.fmt_hl_obj_scene(op[0]))
+ cmt = " / " + self.fmt_hl_obj_scene(op[0], True)
msg = ""
if op[2] != 0xffff:
if op[2] not in resused and op[2] in self.sim.res:
@@ -926,7 +941,10 @@ class App(tkinter.Frame):
msg += "-1"
else:
msg += "0x{:X}".format(arg)
- self.add_info("{}\n".format(msg))
+ self.add_info("{}{}\n".format(msg, cmt))
+ if op[1] == 0x11: # DIALOG
+ if op[0] not in dlgused:
+ dlgused.append(op[0])
if len(resused) > 0:
self.add_info("\n<b>Used resources</b>: {}\n".\
@@ -935,6 +953,12 @@ class App(tkinter.Frame):
self.add_info(" <a href=\"{}\">{}</a> (0x{:X}) - {}\n".\
format(self.find_path_res(res_id), res_id, res_id, \
hlesc(self.sim.res[res_id])))
+
+ if len(dlgused) > 0:
+ self.add_info("\n<b>Used dialog groups</b>: {}\n".\
+ format(len(dlgused)))
+ for grp_id in dlgused:
+ self.add_info(" " + self.fmt_hl_dlg(grp_id, True)+ "\n")
if isobj:
self.add_info("\n<b>Messages</b>:\n")
@@ -967,6 +991,7 @@ class App(tkinter.Frame):
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
+
def path_invntr(self, path):
self.switch_view(0)
if self.last_path[:1] != ("invntr",):
@@ -1031,11 +1056,8 @@ class App(tkinter.Frame):
for op in dlg.ops:
if not op.msg: continue
if op.msg.idx == msg.idx and op.opcode == 7:
- self.add_info(" <a href=\"{}\">{}</a>\n".\
- format(self.find_path_dlggrp(grp.idx),
- grp.idx))
-
-
+ self.add_info(" " +
+ self.fmt_hl_dlg(grp.idx, True) + "\n")
def path_dlgs(self, path):
self.switch_view(0)
@@ -1070,18 +1092,36 @@ class App(tkinter.Frame):
format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
for op in dlg.ops:
cmt = ""
- opref = "0x{:X}".format(op.ref)
- opcode = "OP_{:02X}".format(op.opcode)
+ msgref = "0x{:X}".format(op.ref)
+ opcode = "OP{:02X}".format(op.opcode)
if op.opcode == 7:
opcode = "PLAY"
if op.msg:
- opref = "<a href=\"/msgs/{}\">{}</a>".format(
- op.ref, op.ref)
- objref = self.fmt_hl_obj(op.msg.obj.idx)
- cmt = " / (0x{:X}) - {}, {}".\
- format(op.ref, objref, hlesc(op.msg.name))
+ msgref = self.fmt_hl_msg(op.ref)
+ objref = self.fmt_hl_obj(op.msg.obj.idx)
+ cmt = " / obj={}, msg={}".\
+ format(objref,
+ self.fmt_hl_msg(op.ref, True))
self.add_info(" {} 0x{:X} {}{}\n".\
- format(opcode, op.arg, opref, cmt))
+ format(opcode, op.arg, msgref, cmt))
+
+ def usedby(lst):
+ for idx, rec in enumerate(lst):
+ ru = False
+ for act_id, act_cond, act_arg, ops in rec.acts:
+ if ru: break
+ for op_id, op_code, op_res, op4, op5 in ops:
+ if op_code == 0x11 and op_id == grp.idx: # DIALOG
+ self.add_info(" " +
+ self.fmt_hl_obj_scene(rec.idx, True) + "\n")
+ ru = True
+ break
+ #print(op_id, op_code, op_res, op4, op5)
+
+ self.add_info("\n\n<b>Used by objects</b>:\n")
+ usedby(self.sim.objects)
+ self.add_info("\n<b>Used by scenes</b>:\n")
+ usedby(self.sim.scenes)
def path_test(self, path):
@@ -1100,6 +1140,19 @@ class App(tkinter.Frame):
for i in range(100):
self.add_info(" Item {}\n".format(i))
+ def path_about(self, path):
+ self.switch_view(0)
+ self.update_gui("About")
+ self.insert_lb_act("Outline", [])
+ self.clear_info()
+ self.add_info("Welcome to <b>Petka 1 & 2 resource explorer</b>\n\n")
+ self.add_info(" " + APPNAME + " " + VERSION + "\n")
+ self.add_info(" romiq.kh at gmail.com\n")
+ self.add_info(" https://bitbucket.org/romiq/p12simtran\n")
+ self.add_info("\n")
+ self.path_info_outline()
+
+
def on_open_data(self):
# open data - select TODO
pass
Commit: 720c836c5d5d109af8ccb8e08da182d346af6d85
https://github.com/scummvm/scummvm-tools/commit/720c836c5d5d109af8ccb8e08da182d346af6d85
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: fix underline on win
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index d64404a18..74373f427 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -47,9 +47,9 @@ class HyperlinkManager:
italic_font = font.Font(text, self.text.cget("font"))
italic_font.configure(slant = "italic")
self.text.tag_config("italic", font = italic_font)
- underline_font = font.Font(text, self.text.cget("font"))
- underline_font.configure(underline = 1)
- self.text.tag_config("underline", font = underline_font)
+ #underline_font = font.Font(text, self.text.cget("font"))
+ #underline_font.configure(underline = 1)
+ self.text.tag_config("underline", underline = 1)
self.reset()
def reset(self):
Commit: b3e0b4b37b5d6e5fd83dfbfb910bf4ee2e1fec5e
https://github.com/scummvm/scummvm-tools/commit/b3e0b4b37b5d6e5fd83dfbfb910bf4ee2e1fec5e
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: History (only back)
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 74373f427..6683b871f 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -47,8 +47,6 @@ class HyperlinkManager:
italic_font = font.Font(text, self.text.cget("font"))
italic_font.configure(slant = "italic")
self.text.tag_config("italic", font = italic_font)
- #underline_font = font.Font(text, self.text.cget("font"))
- #underline_font.configure(underline = 1)
self.text.tag_config("underline", underline = 1)
self.reset()
@@ -97,10 +95,13 @@ class App(tkinter.Frame):
self.curr_main = -1 # 0 - frame, 1 - canvas
self.curr_path = []
self.last_path = [None]
+ self.last_capt = ""
self.curr_mode = 0
self.curr_mode_sub = None
self.curr_gui = []
self.curr_lb_acts = None
+ self.hist = []
+ self.histf = []
# canvas
self.need_update = False
self.canv_view_fact = 1
@@ -113,8 +114,21 @@ class App(tkinter.Frame):
ttk.Style().configure("TLabel", padding = self.pad)
ttk.Style().configure('Info.TFrame', background = 'white', \
foreground = "black")
+
+ # toolbar
+ self.toolbar = ttk.Frame(self)
+ self.toolbar.pack(fill = tkinter.BOTH)
+ btns = [
+ ["Outline", lambda: self.open_path("")],
+ ["<-", self.on_back],
+ ["->", self.on_forward],
+ ]
+ for text, cmd in btns:
+ btn = ttk.Button(self.toolbar, text = text, \
+ style = "Tool.TButton", command = cmd)
+ btn.pack(side = tkinter.LEFT)
- # main paned
+ # main panel
self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
self.pan_main.pack(fill = tkinter.BOTH, expand = 1)
@@ -187,10 +201,6 @@ class App(tkinter.Frame):
self.menuedit = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuedit,
label = "Edit")
- self.menuedit.add_command(
- command = lambda: self.open_path([]),
- label = "Outline")
- self.menuedit.add_separator()
self.menuedit.add_command(
command = lambda: self.open_path("/parts"),
label = "Select part")
@@ -217,6 +227,24 @@ class App(tkinter.Frame):
command = lambda: self.open_path("/dlgs"),
label = "Dialog groups")
+ self.menunav = tkinter.Menu(self.master, tearoff = 0)
+ self.menubar.add_cascade(menu = self.menunav,
+ label = "Navigation")
+ self.menunav.add_command(
+ command = self.on_back,
+ label = "Back")
+ self.menunav.add_command(
+ command = self.on_forward,
+ label = "Forward")
+ self.menunav.add_separator()
+ self.menunav.add_command(
+ command = lambda: self.open_path(""),
+ label = "Outline")
+ self.menunav.add_separator()
+ self.menunav.add_command(
+ command = lambda: self.open_path("/hist"),
+ label = "History")
+
self.menuhelp = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuhelp,
label = "Help")
@@ -251,7 +279,7 @@ class App(tkinter.Frame):
def on_resize_view(self, event):
self.update_after()
- def open_path(self, loc):
+ def open_path(self, loc, withhist = True):
if isinstance(loc, str):
path = []
if loc[:1] == "/":
@@ -265,6 +293,12 @@ class App(tkinter.Frame):
else:
path = loc
path = tuple(path)
+
+ if withhist:
+ self.hist.append([path])
+ self.histf = []
+ print(self.hist)
+
print("DEBUG: Open", path)
self.curr_path = path
if len(path) > 0:
@@ -525,6 +559,19 @@ class App(tkinter.Frame):
if act[1] is not None:
self.open_path(act[1])
+ def on_back(self):
+ print("BACK", self.hist)
+ if len(self.hist) > 1:
+ np = self.hist[-2:-1][0]
+ print(np[0])
+ self.hist = self.hist[:-1]
+ self.histf = [np] + self.histf
+ self.open_path(np[0], False)
+
+
+ def on_forward(self):
+ print("FORWARD")
+
def find_path_res(self, res):
for idx, res_id in enumerate(self.sim.resord):
if res_id == res:
Commit: 0430f3a412b172b168a21880967ea4227253238d
https://github.com/scummvm/scummvm-tools/commit/0430f3a412b172b168a21880967ea4227253238d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: History (only back)
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 6683b871f..714905a10 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -535,7 +535,7 @@ class App(tkinter.Frame):
def select_lb_item(self, idx):
idx = "{}".format(idx)
- need = True
+ need = (idx is not None)
for sel in self.curr_lb.curselection():
if sel == idx:
need = False
@@ -543,7 +543,8 @@ class App(tkinter.Frame):
self.curr_lb.selection_clear(sel)
if need:
self.curr_lb.selection_set(idx)
- self.curr_lb.see(idx)
+ if idx is not None:
+ self.curr_lb.see(idx)
def on_left_listbox(self, event):
def currsel():
@@ -713,6 +714,8 @@ class App(tkinter.Frame):
else:
cnum = 0
self.sim.open_part(pnum, cnum)
+ else:
+ self.select_lb_item(None)
# display
self.clear_info()
self.add_info("Select <b>part</b>\n\n")
@@ -868,6 +871,7 @@ class App(tkinter.Frame):
self.path_res_open(path[:3], res_id, path[3:])
else:
self.path_res_status()
+ self.select_lb_item(None)
def path_res_flt(self, path):
lst = []
@@ -889,6 +893,7 @@ class App(tkinter.Frame):
self.path_res_open(path[:4], res_id, path[4:])
else:
self.path_res_status()
+ self.select_lb_item(None)
def path_objs_scenes(self, path):
self.switch_view(0)
@@ -911,6 +916,8 @@ class App(tkinter.Frame):
# index
self.select_lb_item(path[1])
rec = lst[path[1]]
+ else:
+ self.select_lb_item(None)
# display
self.clear_info()
if not rec:
@@ -1025,6 +1032,8 @@ class App(tkinter.Frame):
# parts
self.select_lb_item(path[1])
name = self.sim.namesord[path[1]]
+ else:
+ self.select_lb_item(None)
# display
self.clear_info()
if not name:
@@ -1081,6 +1090,8 @@ class App(tkinter.Frame):
# parts
self.select_lb_item(path[1])
msg = self.sim.msgs[path[1]]
+ else:
+ self.select_lb_item(None)
# display
self.clear_info()
if not msg:
@@ -1119,6 +1130,8 @@ class App(tkinter.Frame):
# parts
self.select_lb_item(path[1])
grp = self.sim.dlgs[path[1]]
+ else:
+ self.select_lb_item(None)
# display
self.clear_info()
if not grp:
Commit: 0e69814055093fc0ec885ef5e26e2058e0786403
https://github.com/scummvm/scummvm-tools/commit/0e69814055093fc0ec885ef5e26e2058e0786403
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: History fixed for not item selected
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 714905a10..d7240112a 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -534,17 +534,17 @@ class App(tkinter.Frame):
self.curr_lb.insert(tkinter.END, name)
def select_lb_item(self, idx):
- idx = "{}".format(idx)
need = (idx is not None)
+ idxs = "{}".format(idx)
for sel in self.curr_lb.curselection():
- if sel == idx:
+ if sel == idxs:
need = False
else:
self.curr_lb.selection_clear(sel)
if need:
- self.curr_lb.selection_set(idx)
+ self.curr_lb.selection_set(idxs)
if idx is not None:
- self.curr_lb.see(idx)
+ self.curr_lb.see(idxs)
def on_left_listbox(self, event):
def currsel():
Commit: 05a3a114030457a6db649e3d238c2f3cdbb04d53
https://github.com/scummvm/scummvm-tools/commit/05a3a114030457a6db649e3d238c2f3cdbb04d53
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: History fixed for not item selected
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index d7240112a..271af2dda 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -561,7 +561,6 @@ class App(tkinter.Frame):
self.open_path(act[1])
def on_back(self):
- print("BACK", self.hist)
if len(self.hist) > 1:
np = self.hist[-2:-1][0]
print(np[0])
@@ -571,7 +570,7 @@ class App(tkinter.Frame):
def on_forward(self):
- print("FORWARD")
+ print("FORWARD", self.histf)
def find_path_res(self, res):
for idx, res_id in enumerate(self.sim.resord):
Commit: 655ff79ed95dd02ff21009f209f0a46c2b37072d
https://github.com/scummvm/scummvm-tools/commit/655ff79ed95dd02ff21009f209f0a46c2b37072d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: History back and forward works
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 271af2dda..86368422d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -297,7 +297,6 @@ class App(tkinter.Frame):
if withhist:
self.hist.append([path])
self.histf = []
- print(self.hist)
print("DEBUG: Open", path)
self.curr_path = path
@@ -563,14 +562,16 @@ class App(tkinter.Frame):
def on_back(self):
if len(self.hist) > 1:
np = self.hist[-2:-1][0]
- print(np[0])
+ self.histf = self.hist[-1:] + self.histf
self.hist = self.hist[:-1]
- self.histf = [np] + self.histf
self.open_path(np[0], False)
-
def on_forward(self):
- print("FORWARD", self.histf)
+ if len(self.histf) > 0:
+ np = self.histf[0]
+ self.histf = self.histf[1:]
+ self.hist.append(np)
+ self.open_path(np[0], False)
def find_path_res(self, res):
for idx, res_id in enumerate(self.sim.resord):
Commit: a7922be8fa34bb8784ebb0bafe577f48267ead7d
https://github.com/scummvm/scummvm-tools/commit/a7922be8fa34bb8784ebb0bafe577f48267ead7d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Clear history on part change
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 86368422d..2dd42ae77 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -714,6 +714,8 @@ class App(tkinter.Frame):
else:
cnum = 0
self.sim.open_part(pnum, cnum)
+ self.hist = self.hist[-1:]
+ self.histf = []
else:
self.select_lb_item(None)
# display
Commit: eec272940b1ca22469298eecdec8def8c02ff8c8
https://github.com/scummvm/scummvm-tools/commit/eec272940b1ca22469298eecdec8def8c02ff8c8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Open dialog, small fixes
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 2dd42ae77..62b828efc 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -5,7 +5,7 @@
import sys, os
import tkinter
-from tkinter import ttk, font
+from tkinter import ttk, font, filedialog, messagebox
from idlelib.WidgetRedirector import WidgetRedirector
import traceback
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2 2014-05-15"
+VERSION = "v0.2 2014-05-16"
def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
@@ -120,13 +120,20 @@ class App(tkinter.Frame):
self.toolbar.pack(fill = tkinter.BOTH)
btns = [
["Outline", lambda: self.open_path("")],
+ [None, None],
["<-", self.on_back],
["->", self.on_forward],
]
for text, cmd in btns:
+ if text is None:
+ frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
+ frm.pack(side = tkinter.LEFT)
+ continue
btn = ttk.Button(self.toolbar, text = text, \
style = "Tool.TButton", command = cmd)
btn.pack(side = tkinter.LEFT)
+ frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
+ frm.pack(side = tkinter.LEFT)
# main panel
self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
@@ -559,6 +566,21 @@ class App(tkinter.Frame):
if act[1] is not None:
self.open_path(act[1])
+ def add_toolbtn(self, text, cmd):
+ if text is None:
+ frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
+ frm.pack(side = tkinter.LEFT)
+ self.curr_gui.append(lambda:frm.pack_forget())
+ return
+ btn = ttk.Button(self.toolbar, text = text, \
+ style = "Tool.TButton", command = cmd)
+ btn.pack(side = tkinter.LEFT)
+ self.curr_gui.append(lambda:btn.pack_forget())
+
+ def clear_hist(self):
+ self.hist = self.hist[-1:]
+ self.histf = []
+
def on_back(self):
if len(self.hist) > 1:
np = self.hist[-2:-1][0]
@@ -648,6 +670,9 @@ class App(tkinter.Frame):
return self.fmt_hl_rec(self.sim.dlgs, "dlgs", grp_idx, full)
def path_info_outline(self):
+ if self.sim is None:
+ self.add_info("No data loaded. Open BGS.INI or SCRIPT.DAT first.")
+ return
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
@@ -714,8 +739,7 @@ class App(tkinter.Frame):
else:
cnum = 0
self.sim.open_part(pnum, cnum)
- self.hist = self.hist[-1:]
- self.histf = []
+ self.clear_hist()
else:
self.select_lb_item(None)
# display
@@ -784,7 +808,6 @@ class App(tkinter.Frame):
else:
self.add_info("No information availiable")
-
except:
self.add_info("Error loading {} - \"{}\" \n\n{}".\
format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
@@ -839,8 +862,10 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("Error loading {} - \"{}\" \n\n{}".\
format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
+ dataf = None
finally:
- dataf.close()
+ if dataf:
+ dataf.close()
def path_res_status(self):
self.switch_view(0)
@@ -858,10 +883,18 @@ class App(tkinter.Frame):
for ft in ftk:
self.add_info(" <a href=\"/res/flt/{}\">{}</a>: {}\n".format(
ft, ft, fts[ft]))
+
+ def on_path_res_info(self):
+ self.switch_view(0)
+
+ def on_path_res_view(self):
+ self.switch_view(1)
def path_res_all(self, path):
if self.last_path[:2] != ("res", "all",):
self.update_gui("Resources ({})".format(len(self.sim.res)))
+ #self.add_toolbtn("Info", self.on_path_res_info)
+ #self.add_toolbtn("View", self.on_path_res_view)
for idx, res_id in enumerate(self.sim.resord):
self.insert_lb_act("{} - {}".format(\
res_id, self.sim.res[res_id]), ["res", "all", idx])
@@ -974,7 +1007,11 @@ class App(tkinter.Frame):
for idx, (act_id, act_cond, act_arg, ops) in enumerate(rec.acts):
msg = fmt_opcode(act_id)
if act_cond != 0xff or act_arg != 0xffff:
- msg += " 0x{:02X} 0x{:04X}".format(act_cond, act_arg)
+ if act_arg == rec.idx:
+ act_arg = "THIS"
+ else:
+ act_arg = "0x:{:X}".format(act_arg)
+ msg += " 0x{:02X} {}".format(act_cond, act_arg)
self.add_info(" {}) <u>on {}</u>, ops: {}\n".format(\
idx, msg, len(ops)))
for oidx, op in enumerate(ops):
@@ -1216,22 +1253,41 @@ class App(tkinter.Frame):
def on_open_data(self):
- # open data - select TODO
- pass
+ ft = [\
+ ('all files', '.*')]
+ fn = filedialog.askopenfilename(parent = self,
+ title = "Open BGS.INI or SCRIPT.DAT",
+ filetypes = ft,
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return
+ os.chdir(os.path.dirname(fn))
+ self.clear_hist()
+ if self.open_data_from(os.path.dirname(fn)):
+ self.open_path("")
+ self.clear_hist()
+
def open_data_from(self, folder):
- self.sim = petka.Engine()
- self.sim.load_data(folder, "cp1251")
- self.sim.open_part(1, 0)
+ try:
+ self.sim = petka.Engine()
+ self.sim.load_data(folder, "cp1251")
+ self.sim.open_part(0, 0)
+ return True
+ except:
+ print("DEBUG: Error opening")
+ self.sim = None
+ self.switch_view(0)
+ self.update_gui("")
+ self.clear_info()
+ self.add_info("Error opening \"{}\" \n\n{}".\
+ format(hlesc(folder), hlesc(traceback.format_exc())))
+ self.clear_hist()
def main():
root = tkinter.Tk()
app = App(master = root)
if len(sys.argv) > 1:
- fn = sys.argv[1]
- else:
- fn = "."
- app.open_data_from(fn)
+ app.open_data_from(sys.argv[1])
app.mainloop()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 539944a36..acc943436 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -7,6 +7,7 @@ import struct
import io
from .fman import FileManager
+from . import EngineError
OPCODES = {
1: ("USE", 0),
@@ -259,7 +260,10 @@ class Engine:
self.obj_idx = {}
self.scn_idx = {}
- data = self.fman.read_file(self.curr_path + "script.dat")
+ try:
+ data = self.fman.read_file(self.curr_path + "script.dat")
+ except:
+ raise EngineError("Can't open SCRIPT.DAT")
num_obj, num_scn = struct.unpack_from("<II", data[:8])
off = 8
def read_rec(off):
Commit: d2c1894e9c0c60f3f21f24e3e6ab0fc412ce0755
https://github.com/scummvm/scummvm-tools/commit/d2c1894e9c0c60f3f21f24e3e6ab0fc412ce0755
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: ref to object from action handler
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 62b828efc..23915175b 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1004,16 +1004,21 @@ class App(tkinter.Frame):
resused = []
dlgused = []
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
- for idx, (act_id, act_cond, act_arg, ops) in enumerate(rec.acts):
- msg = fmt_opcode(act_id)
- if act_cond != 0xff or act_arg != 0xffff:
- if act_arg == rec.idx:
- act_arg = "THIS"
+ for idx, (act_op, act_status, act_ref, ops) in enumerate(rec.acts):
+ msg = fmt_opcode(act_op)
+ cmt = ""
+ if act_status != 0xff or act_ref != 0xffff:
+ if act_ref == rec.idx:
+ act_ref = "THIS"
else:
- act_arg = "0x:{:X}".format(act_arg)
- msg += " 0x{:02X} {}".format(act_cond, act_arg)
- self.add_info(" {}) <u>on {}</u>, ops: {}\n".format(\
- idx, msg, len(ops)))
+ if act_ref in self.sim.obj_idx:
+ cmt = " / " + self.fmt_hl_obj(act_ref, True)
+ act_ref = self.fmt_hl_obj(act_ref)
+ else:
+ act_ref = "0x{:X}".format(act_ref)
+ msg += " 0x{:02X} {}".format(act_status, act_ref)
+ self.add_info(" {}) <u>on {}</u>, ops: {}{}\n".format(\
+ idx, msg, len(ops), cmt))
for oidx, op in enumerate(ops):
self.add_info(" {}) {} ".format(oidx, fmt_opcode(op[1])))
cmt = ""
Commit: b590021b4ce4fda0a3b882af74bcbe059f7654ff
https://github.com/scummvm/scummvm-tools/commit/b590021b4ce4fda0a3b882af74bcbe059f7654ff
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: Dist file for cx_Freeze
Changed paths:
A engines/petka/dist/setup.py
diff --git a/engines/petka/dist/setup.py b/engines/petka/dist/setup.py
new file mode 100644
index 000000000..729cd75b0
--- /dev/null
+++ b/engines/petka/dist/setup.py
@@ -0,0 +1,27 @@
+from cx_Freeze import setup, Executable
+
+import cx_Freeze.util
+
+import sys, os, struct
+
+# Dependencies are automatically detected, but it might need
+# fine tuning.
+buildOptions = dict(packages = ["re", "io", "PIL", "traceback", "zlib", "gzip", "argparse", "struct", "binascii"], \
+ excludes = ["_posixsubprocess"],
+ include_files = [],
+ compressed = True, silent = True,\
+ optimize = 2, copy_dependent_files = True, \
+ create_shared_zip = True, include_in_shared_zip = True)
+
+executables = [
+ Executable('p12explore.py',
+ base = 'Win32GUI',
+ targetName = "p12explore.exe")
+]
+
+setup(name='p12explore',
+ version = '0.2',
+ description = 'Petka 1&2 explorer',
+ author = "romiq.kh at gmail.com, https://bitbucket.org/romiq/p12simtran",
+ options = dict(build_exe = buildOptions),
+ executables = executables)
Commit: 726a9148be0e13d8096ccf52433ea00fb6c79a03
https://github.com/scummvm/scummvm-tools/commit/726a9148be0e13d8096ccf52433ea00fb6c79a03
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: release 0.2a (fix using resources in freeze mode)
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/imgbmp.py
engines/petka/petka/imgflc.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 23915175b..cbf8fd0b3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2 2014-05-16"
+VERSION = "v0.2a 2014-05-16"
def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 631c367a0..7f3ec4c4e 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -104,8 +104,6 @@ class BMPLoader:
self.height = ph
self.rgb = self.pixelswap16(pw, ph, pd)
except:
- import traceback
- traceback.print_exc()
f.seek(0)
self.image = Image.open(f)
diff --git a/engines/petka/petka/imgflc.py b/engines/petka/petka/imgflc.py
index 63040d7a8..c692db697 100644
--- a/engines/petka/petka/imgflc.py
+++ b/engines/petka/petka/imgflc.py
@@ -11,6 +11,11 @@ try:
except ImportError:
Image = None
+try:
+ from PIL import FliImagePlugin
+except ImportError:
+ pass
+
class FLCLoader:
def __init__(self):
self.rgb = None
Commit: 71e35612b7f792b1db0952e0114c0cb979dab13e
https://github.com/scummvm/scummvm-tools/commit/71e35612b7f792b1db0952e0114c0cb979dab13e
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: release 0.2b (fix errors when no data loaded, add support information)
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index cbf8fd0b3..35da3708c 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2a 2014-05-16"
+VERSION = "v0.2b 2014-05-16"
def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
@@ -95,7 +95,7 @@ class App(tkinter.Frame):
self.curr_main = -1 # 0 - frame, 1 - canvas
self.curr_path = []
self.last_path = [None]
- self.last_capt = ""
+ self.last_fn = ""
self.curr_mode = 0
self.curr_mode_sub = None
self.curr_gui = []
@@ -182,6 +182,7 @@ class App(tkinter.Frame):
self.path_handler["dlgs"] = self.path_dlgs
self.path_handler["test"] = self.path_test
self.path_handler["about"] = self.path_about
+ self.path_handler["support"] = self.path_support
self.update_after()
self.open_path("/about")
@@ -258,6 +259,9 @@ class App(tkinter.Frame):
self.menuhelp.add_command(
command = lambda: self.open_path("/about"),
label = "About")
+ self.menuhelp.add_command(
+ command = lambda: self.open_path("/support"),
+ label = "Support")
def update_after(self):
if not self.need_update:
@@ -700,7 +704,8 @@ class App(tkinter.Frame):
for item in path:
spath += "/" + str(item)
self.add_info("Path {} not found\n\n".format(spath))
- self.add_info("Select from <b>outline</b>\n\n")
+ if self.sim is not None:
+ self.add_info("Select from <b>outline</b>\n\n")
self.path_info_outline()
if self.sim is not None:
acts = [
@@ -720,7 +725,8 @@ class App(tkinter.Frame):
self.insert_lb_act(name, act)
def path_parts(self, path):
- self.switch_view(0)
+ if self.sim is None:
+ return self.path_default([])
if self.last_path[:1] != ("parts",):
self.update_gui("Parts ({})".format(len(self.sim.parts)))
for idx, name in enumerate(self.sim.parts):
@@ -751,6 +757,8 @@ class App(tkinter.Frame):
# res - full list
# res/flt/<ext> - list by <ext>
# res/all/<id> - display res by id
+ if self.sim is None:
+ return self.path_default([])
if path == ("res",):
path = ("res", "all")
if path[1] == "flt":
@@ -931,6 +939,8 @@ class App(tkinter.Frame):
self.select_lb_item(None)
def path_objs_scenes(self, path):
+ if self.sim is None:
+ return self.path_default([])
self.switch_view(0)
isobj = (self.curr_path[0] == "objs")
if isobj:
@@ -1065,6 +1075,8 @@ class App(tkinter.Frame):
self.add_info(" " + self.fmt_hl_msg(msg.idx, True) + "\n")
def path_names(self, path):
+ if self.sim is None:
+ return self.path_default([])
self.switch_view(0)
if self.last_path[:1] != ("names",):
self.update_gui("Names ({})".format(len(self.sim.names)))
@@ -1093,6 +1105,8 @@ class App(tkinter.Frame):
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
def path_invntr(self, path):
+ if self.sim is None:
+ return self.path_default([])
self.switch_view(0)
if self.last_path[:1] != ("invntr",):
self.update_gui("Invntr ({})".format(len(self.sim.invntr)))
@@ -1119,6 +1133,8 @@ class App(tkinter.Frame):
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
def path_msgs(self, path):
+ if self.sim is None:
+ return self.path_default([])
self.switch_view(0)
if self.last_path[:1] != ("msgs",):
self.update_gui("Messages ({})".format(len(self.sim.msgs)))
@@ -1162,6 +1178,8 @@ class App(tkinter.Frame):
self.fmt_hl_dlg(grp.idx, True) + "\n")
def path_dlgs(self, path):
+ if self.sim is None:
+ return self.path_default([])
self.switch_view(0)
if self.last_path[:1] != ("dlgs",):
self.update_gui("Dialog groups ({})".format(len(self.sim.dlgs)))
@@ -1256,6 +1274,26 @@ class App(tkinter.Frame):
self.add_info("\n")
self.path_info_outline()
+ def path_support(self, path):
+ self.switch_view(0)
+ self.update_gui("Support")
+ self.insert_lb_act("Outline", [])
+ self.clear_info()
+ self.add_info("" + APPNAME + " " + VERSION + "\n")
+ self.add_info("=" * 40 + "\n")
+ self.add_info("<b>Game folder</b>: {}\n".format(hlesc(self.last_fn)))
+ if self.sim is None:
+ self.add_info("<i>Engine not initialized</i>\n")
+ else:
+ self.add_info("<i>Engine works</i>\n\n")
+ self.add_info(" <b>Path</b>: {}\n".format(
+ hlesc(self.sim.curr_path)))
+ self.add_info(" <b>Speech</b>: {}\n".format(
+ hlesc(self.sim.curr_speech)))
+ self.add_info(" <b>Disk ID</b>: {}\n\n".format(
+ hlesc(self.sim.curr_diskid)))
+ self.path_info_outline()
+
def on_open_data(self):
ft = [\
@@ -1273,6 +1311,7 @@ class App(tkinter.Frame):
def open_data_from(self, folder):
+ self.last_fn = folder
try:
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
Commit: df731096071420ed406088fb166b734ec4a4512f
https://github.com/scummvm/scummvm-tools/commit/df731096071420ed406088fb166b734ec4a4512f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:14+01:00
Commit Message:
TOOLS: PETKA: release 0.2c (fix support page)
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 35da3708c..05bb13933 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -24,6 +24,8 @@ APPNAME = "P1&2 Explorer"
VERSION = "v0.2b 2014-05-16"
def hlesc(value):
+ if value is None:
+ return "None"
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
def fmt_opcode(opcode):
Commit: ccbd3e23f86dfcba6d687a88af56821bc9822b89
https://github.com/scummvm/scummvm-tools/commit/ccbd3e23f86dfcba6d687a88af56821bc9822b89
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: release 0.2c
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 05bb13933..34bfe56c4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2b 2014-05-16"
+VERSION = "v0.2c 2014-05-16"
def hlesc(value):
if value is None:
Commit: 706c7d5b1a62a312d97eaf6a2b53fae6dafad3a9
https://github.com/scummvm/scummvm-tools/commit/706c7d5b1a62a312d97eaf6a2b53fae6dafad3a9
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix gui, wat to fix path with incorrect loading
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 34bfe56c4..f8fe445f0 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2c 2014-05-16"
+VERSION = "v0.2d 2014-05-16"
def hlesc(value):
if value is None:
@@ -444,7 +444,9 @@ class App(tkinter.Frame):
scr_lb_x.grid(row = 1, column = 0, sticky = tkinter.E + tkinter.W)
scr_lb_y = ttk.Scrollbar(frm_lb)
scr_lb_y.grid(row = 0, column = 1, sticky = tkinter.N + tkinter.S)
+ frmlbpad = ttk.Frame(frm_lb, borderwidth = self.pad)
lb = tkinter.Listbox(frm_lb,
+ highlightthickness = 0,
xscrollcommand = scr_lb_x.set,
yscrollcommand = scr_lb_y.set)
lb.grid(row = 0, column = 0, \
@@ -543,7 +545,10 @@ class App(tkinter.Frame):
def insert_lb_act(self, name, act):
self.curr_lb_acts.append((name, act))
- self.curr_lb.insert(tkinter.END, name)
+ if name == "-" and act is None:
+ self.curr_lb.insert(tkinter.END, "")
+ else:
+ self.curr_lb.insert(tkinter.END, " " + name)
def select_lb_item(self, idx):
need = (idx is not None)
@@ -677,7 +682,7 @@ class App(tkinter.Frame):
def path_info_outline(self):
if self.sim is None:
- self.add_info("No data loaded. Open BGS.INI or SCRIPT.DAT first.")
+ self.add_info("No data loaded. Open PARTS.INI or SCRIPT.DAT first.")
return
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
@@ -726,6 +731,7 @@ class App(tkinter.Frame):
for name, act in acts:
self.insert_lb_act(name, act)
+
def path_parts(self, path):
if self.sim is None:
return self.path_default([])
@@ -733,6 +739,19 @@ class App(tkinter.Frame):
self.update_gui("Parts ({})".format(len(self.sim.parts)))
for idx, name in enumerate(self.sim.parts):
self.insert_lb_act(name, ["parts", idx])
+ if len(self.sim.parts) == 0:
+ # Option to fix paths
+ def fix_paths():
+ self.sim.curr_path = ""
+ path = self.sim.fman.root
+ while self.sim.curr_path == "":
+ self.sim.curr_path = os.path.basename(path)
+ path2 = os.path.dirname(path)
+ if path2 == path: break
+ path = path2
+ path = self.sim.fman.root = path
+ self.sim.curr_path += "\\"
+ self.add_toolbtn("Fix paths", fix_paths)
# change
if len(path) > 1:
# parts
@@ -1283,7 +1302,8 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("" + APPNAME + " " + VERSION + "\n")
self.add_info("=" * 40 + "\n")
- self.add_info("<b>Game folder</b>: {}\n".format(hlesc(self.last_fn)))
+ self.add_info("<b>Game folder</b>: {}\n".format(
+ hlesc(self.sim.fman.root)))
if self.sim is None:
self.add_info("<i>Engine not initialized</i>\n")
else:
@@ -1301,7 +1321,7 @@ class App(tkinter.Frame):
ft = [\
('all files', '.*')]
fn = filedialog.askopenfilename(parent = self,
- title = "Open BGS.INI or SCRIPT.DAT",
+ title = "Open PARTS.INI or SCRIPT.DAT",
filetypes = ft,
initialdir = os.path.abspath(os.curdir))
if not fn: return
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index acb5c362b..e9f9dea76 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -11,7 +11,7 @@ from . import EngineError
# manage files data
class FileManager:
def __init__(self, root):
- self.root = root
+ self.root = os.path.abspath(root)
self.strfd = []
self.strtable = {}
Commit: 186095934c485810babfc0eeffde8a44af7e3840
https://github.com/scummvm/scummvm-tools/commit/186095934c485810babfc0eeffde8a44af7e3840
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Help pages
Changed paths:
A engines/petka/help/changes.txt
A engines/petka/help/faq.txt
A engines/petka/help/index.txt
A engines/petka/help/list
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
new file mode 100644
index 000000000..73a82330d
--- /dev/null
+++ b/engines/petka/help/changes.txt
@@ -0,0 +1,31 @@
+ЧÑо нового
+==========
+
+2014-05-16 веÑÑÐ¸Ñ 0.2e
+----------------------
+ÐÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑе Support
+Ðобавлена ÑпÑавка по пÑогÑамме
+
+2014-05-16 веÑÑÐ¸Ñ 0.2d
+----------------------
+ÐÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑе Support
+Ðобавлена кнопка "Fix Paths" - иÑпÑавление пÑÑей когда загÑÑжена ÑолÑко одна
+ ÑаÑÑÑ
+
+2014-05-16 веÑÑÐ¸Ñ 0.2c
+----------------------
+ÐÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑе Support
+
+2014-05-16 веÑÑÐ¸Ñ 0.2b
+----------------------
+ÐÑпÑавлено оÑкÑÑÑие Ñазделов когда даннÑе не загÑÑженÑ
+Ðобавлена ÑÑÑаниÑа Support
+
+2014-05-16 веÑÑÐ¸Ñ 0.2a
+----------------------
+ÐÑпÑавлено оÑкÑÑÑие ÑеÑÑÑÑов пÑи иÑполÑзовании cx_Freeze
+
+2014-05-16 веÑÑÐ¸Ñ 0.2
+---------------------
+ÐеÑвÑй пÑблиÑнÑй Ñелиз
+
diff --git a/engines/petka/help/faq.txt b/engines/petka/help/faq.txt
new file mode 100644
index 000000000..1e30f7fe7
--- /dev/null
+++ b/engines/petka/help/faq.txt
@@ -0,0 +1,9 @@
+ЧаÑÑо задаваемÑе вопÑоÑÑ (FAQ)
+
+<i>Я ÑÑпеÑно оÑкÑÑл Ñайл SCRIPT.DAT, но ни один из ÑеÑÑÑÑов не загÑÑжаеÑÑÑ</i>
+1. ÐÑовеÑÑÑе пÑÑи к ÑеÑÑÑÑам
+2. Ðозможно, Ð²Ñ Ð¾ÑкÑÑли Ñайл из каÑалога PART_0 (PART_1 и Ñ.д.) вмеÑÑо
+ PARTS.INI из коÑневого каÑалога. ФÑнкÑÐ¸Ñ Ð¾ÑкÑÑÑÐ¸Ñ Ñайла SCRIPT.DAT
+ пÑедназнаÑена Ð´Ð»Ñ Ðемо-веÑÑии 1й ÑаÑÑи. Тем не менее Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пеÑейÑи в
+ Ñаздел вÑÐ±Ð¾Ñ ÑаÑÑи (Edit->Parts) и нажаÑÑ ÐºÐ½Ð¾Ð¿ÐºÑ [Fix Paths].
+
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
new file mode 100644
index 000000000..4a2dcad34
--- /dev/null
+++ b/engines/petka/help/index.txt
@@ -0,0 +1,7 @@
+СпÑавка
+
+ÐеÑÑиÑ: 0.2e 2014-05-16
+
+ * <a href="/help/changes">ЧÑо нового</a>
+ * <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
+
diff --git a/engines/petka/help/list b/engines/petka/help/list
new file mode 100644
index 000000000..74879b370
--- /dev/null
+++ b/engines/petka/help/list
@@ -0,0 +1,4 @@
+index
+changes
+faq
+
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index f8fe445f0..6b724abd3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2d 2014-05-16"
+VERSION = "v0.2e 2014-05-16"
def hlesc(value):
if value is None:
@@ -92,6 +92,12 @@ class App(tkinter.Frame):
self.pack(fill = tkinter.BOTH, expand = 1)
self.pad = None
self.sim = None
+ # path
+ if hasattr(sys, 'frozen'):
+ self.app_path = sys.executable
+ else:
+ self.app_path = __file__
+ self.app_path = os.path.abspath(os.path.dirname(self.app_path))
# gui
self.path_handler = {}
self.curr_main = -1 # 0 - frame, 1 - canvas
@@ -185,6 +191,7 @@ class App(tkinter.Frame):
self.path_handler["test"] = self.path_test
self.path_handler["about"] = self.path_about
self.path_handler["support"] = self.path_support
+ self.path_handler["help"] = self.path_help
self.update_after()
self.open_path("/about")
@@ -259,11 +266,15 @@ class App(tkinter.Frame):
self.menubar.add_cascade(menu = self.menuhelp,
label = "Help")
self.menuhelp.add_command(
- command = lambda: self.open_path("/about"),
- label = "About")
+ command = lambda: self.open_path("/help/index"),
+ label = "Contents")
+ self.menuhelp.add_separator()
self.menuhelp.add_command(
command = lambda: self.open_path("/support"),
label = "Support")
+ self.menuhelp.add_command(
+ command = lambda: self.open_path("/about"),
+ label = "About")
def update_after(self):
if not self.need_update:
@@ -1302,8 +1313,10 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("" + APPNAME + " " + VERSION + "\n")
self.add_info("=" * 40 + "\n")
+ self.add_info("<b>App folder</b>: {}\n".format(
+ hlesc(self.app_path)))
self.add_info("<b>Game folder</b>: {}\n".format(
- hlesc(self.sim.fman.root)))
+ hlesc(self.last_fn)))
if self.sim is None:
self.add_info("<i>Engine not initialized</i>\n")
else:
@@ -1316,6 +1329,64 @@ class App(tkinter.Frame):
hlesc(self.sim.curr_diskid)))
self.path_info_outline()
+ def path_help(self, path):
+ self.switch_view(0)
+
+ lfn = os.path.join(self.app_path, "help", "list")
+ hi = []
+ f = open(lfn, "rb")
+ try:
+ for item in f.readlines():
+ item = item.decode("UTF-8").strip()
+ if not item: continue
+ try:
+ hf = open(os.path.join(self.app_path,
+ "help", item + ".txt"), "rb")
+ try:
+ for line in hf.readlines():
+ line = line.decode("UTF-8").strip()
+ break
+ finally:
+ hf.close()
+ except:
+ line = item
+ hi.append([item, line])
+ finally:
+ f.close()
+
+ if self.last_path[:1] != ("help",):
+ self.update_gui("Help")
+ for item, line in hi:
+ self.insert_lb_act(line, ["help", item])
+ self.insert_lb_act("-", None)
+ self.insert_lb_act("Outline", [])
+
+ # change
+ if len(path) > 1:
+ # parts
+ for idx, (item, line) in enumerate(hi):
+ if item == path[1]:
+ self.select_lb_item(idx)
+ self.clear_info()
+ hfn = os.path.join(self.app_path, "help", path[1] + ".txt")
+ try:
+ hf = open(hfn, "rb")
+ try:
+ for idx, line in enumerate(hf.readlines()):
+ line = line.decode("UTF-8").rstrip()
+ if idx == 0:
+ self.add_info("<b>" + line + "</b>\n")
+ else:
+ self.add_info(line + "\n")
+ finally:
+ hf.close()
+ except:
+ self.add_info("Error loading \"{}\" \n\n{}".\
+ format(hlesc(hfn), hlesc(traceback.format_exc())))
+ else:
+ self.select_lb_item(None)
+
+
def on_open_data(self):
ft = [\
Commit: f3918517d02923a6a87d7b2a94f30a34ed056f96
https://github.com/scummvm/scummvm-tools/commit/f3918517d02923a6a87d7b2a94f30a34ed056f96
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor internal paths
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 6b724abd3..8ac6d45b3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -108,6 +108,7 @@ class App(tkinter.Frame):
self.curr_mode_sub = None
self.curr_gui = []
self.curr_lb_acts = None
+ self.curr_lb_idx = None
self.hist = []
self.histf = []
# canvas
@@ -472,6 +473,7 @@ class App(tkinter.Frame):
# actions on listbox
self.curr_lb = lb
self.curr_lb_acts = []
+ self.curr_lb_idx = {}
def switch_view(self, main):
# main view
@@ -550,18 +552,42 @@ class App(tkinter.Frame):
mode = 0
else:
curr_tag += ch
- if len(curr_text) > 0:
+ if len(curr_text) > 0: lfn = os.path.join(self.app_path, "help", "list")
+ hi = []
+ f = open(lfn, "rb")
+ try:
+ for item in f.readlines():
+ item = item.decode("UTF-8").strip()
+ if not item: continue
+ try:
+ hf = open(os.path.join(self.app_path,
+ "help", item + ".txt"), "rb")
+ try:
+ for line in hf.readlines():
+ line = line.decode("UTF-8").strip()
+ break
+ finally:
+ hf.close()
+ except:
+ line = item
+ hi.append([item, line])
+ finally:
+ f.close()
+
self.text_view.insert(tkinter.INSERT, curr_text, \
tuple([x for x in tags for x in x]))
- def insert_lb_act(self, name, act):
+ def insert_lb_act(self, name, act, key = None):
+ if key is not None:
+ self.curr_lb_idx[key] = len(self.curr_lb_acts)
self.curr_lb_acts.append((name, act))
if name == "-" and act is None:
self.curr_lb.insert(tkinter.END, "")
else:
self.curr_lb.insert(tkinter.END, " " + name)
- def select_lb_item(self, idx):
+ def select_lb_item(self, key):
+ idx = self.curr_lb_idx.get(key, None)
need = (idx is not None)
idxs = "{}".format(idx)
for sel in self.curr_lb.curselection():
@@ -617,32 +643,32 @@ class App(tkinter.Frame):
self.hist.append(np)
self.open_path(np[0], False)
- def find_path_res(self, res):
- for idx, res_id in enumerate(self.sim.resord):
- if res_id == res:
- return "/res/all/{}".format(idx)
- return "/no_res/{}".format(res)
-
- def find_path_obj(self, obj_idx):
- for idx, rec in enumerate(self.sim.objects):
- if rec.idx == obj_idx:
- return "/objs/{}".format(idx)
- return "/no_obj/{}".format(obj_idx)
-
- def find_path_scene(self, scn_idx):
- for idx, rec in enumerate(self.sim.scenes):
- if rec.idx == scn_idx:
- return "/scenes/{}".format(idx)
- return "/no_scene/{}".format(scn_idx)
-
- def find_path_obj_scene(self, rec_idx):
- for idx, rec in enumerate(self.sim.objects):
- if rec.idx == rec_idx:
- return "/objs/{}".format(idx)
- for idx, rec in enumerate(self.sim.scenes):
- if rec.idx == rec_idx:
- return "/scenes/{}".format(idx)
- return "/no_obj_scene/{}".format(rec_idx)
+ #def find_path_res(self, res):
+ # for idx, res_id in enumerate(self.sim.resord):
+ # if res_id == res:
+ # return "/res/all/{}".format(idx)
+ # return "/no_res/{}".format(res)
+
+ #def find_path_obj(self, obj_idx):
+ # for idx, rec in enumerate(self.sim.objects):
+ # if rec.idx == obj_idx:
+ # return "/objs/{}".format(idx)
+ # return "/no_obj/{}".format(obj_idx)
+
+ #def find_path_scene(self, scn_idx):
+ # for idx, rec in enumerate(self.sim.scenes):
+ # if rec.idx == scn_idx:
+ # return "/scenes/{}".format(idx)
+ # return "/no_scene/{}".format(scn_idx)
+
+ #def find_path_obj_scene(self, rec_idx):
+ # for idx, rec in enumerate(self.sim.objects):
+ # if rec.idx == rec_idx:
+ # return "/objs/{}".format(idx)
+ # for idx, rec in enumerate(self.sim.scenes):
+ # if rec.idx == rec_idx:
+ # return "/scenes/{}".format(idx)
+ # return "/no_obj_scene/{}".format(rec_idx)
def fmt_hl_rec(self, lst, pref, rec_idx, full = False):
for idx, rec in enumerate(lst):
@@ -679,11 +705,11 @@ class App(tkinter.Frame):
return "/invntr/{}".format(idx)
return "/no_invntr/{}".format(key)
- def find_path_dlggrp(self, grp_idx):
- for idx, grp in enumerate(self.sim.dlgs):
- if grp.idx == grp_idx:
- return "/dlgs/{}".format(idx)
- return "/no_dlgs/{}".format(grp_idx)
+ #def find_path_dlggrp(self, grp_idx):
+ # for idx, grp in enumerate(self.sim.dlgs):
+ # if grp.idx == grp_idx:
+ # return "/dlgs/{}".format(idx)
+ # return "/no_dlgs/{}".format(grp_idx)
def fmt_hl_msg(self, obj_idx, full = False):
return self.fmt_hl_rec(self.sim.msgs, "msgs", obj_idx, full)
@@ -1331,42 +1357,37 @@ class App(tkinter.Frame):
def path_help(self, path):
self.switch_view(0)
-
- lfn = os.path.join(self.app_path, "help", "list")
- hi = []
- f = open(lfn, "rb")
- try:
- for item in f.readlines():
- item = item.decode("UTF-8").strip()
- if not item: continue
- try:
- hf = open(os.path.join(self.app_path,
- "help", item + ".txt"), "rb")
- try:
- for line in hf.readlines():
- line = line.decode("UTF-8").strip()
- break
- finally:
- hf.close()
- except:
- line = item
- hi.append([item, line])
- finally:
- f.close()
-
if self.last_path[:1] != ("help",):
self.update_gui("Help")
- for item, line in hi:
- self.insert_lb_act(line, ["help", item])
+ # build help index
+ lfn = os.path.join(self.app_path, "help", "list")
+ f = open(lfn, "rb")
+ try:
+ for item in f.readlines():
+ item = item.decode("UTF-8").strip()
+ if not item: continue
+ try:
+ hf = open(os.path.join(self.app_path,
+ "help", item + ".txt"), "rb")
+ try:
+ for line in hf.readlines():
+ line = line.decode("UTF-8").strip()
+ break
+ finally:
+ hf.close()
+ except:
+ line = item
+ self.insert_lb_act(line, ["help", item], item)
+ finally:
+ f.close()
+
self.insert_lb_act("-", None)
self.insert_lb_act("Outline", [])
# change
if len(path) > 1:
# parts
- for idx, (item, line) in enumerate(hi):
- if item == path[1]:
- self.select_lb_item(idx)
+ self.select_lb_item(path[1])
self.clear_info()
hfn = os.path.join(self.app_path, "help", path[1] + ".txt")
try:
@@ -1385,7 +1406,6 @@ class App(tkinter.Frame):
format(hlesc(hfn), hlesc(traceback.format_exc())))
else:
self.select_lb_item(None)
-
def on_open_data(self):
Commit: c2f1863df4280fae012fcae544e55fd0261a5d13
https://github.com/scummvm/scummvm-tools/commit/c2f1863df4280fae012fcae544e55fd0261a5d13
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor onjs and scenes
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 8ac6d45b3..e729ffff4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -552,28 +552,7 @@ class App(tkinter.Frame):
mode = 0
else:
curr_tag += ch
- if len(curr_text) > 0: lfn = os.path.join(self.app_path, "help", "list")
- hi = []
- f = open(lfn, "rb")
- try:
- for item in f.readlines():
- item = item.decode("UTF-8").strip()
- if not item: continue
- try:
- hf = open(os.path.join(self.app_path,
- "help", item + ".txt"), "rb")
- try:
- for line in hf.readlines():
- line = line.decode("UTF-8").strip()
- break
- finally:
- hf.close()
- except:
- line = item
- hi.append([item, line])
- finally:
- f.close()
-
+ if len(curr_text) > 0:
self.text_view.insert(tkinter.INSERT, curr_text, \
tuple([x for x in tags for x in x]))
@@ -670,39 +649,43 @@ class App(tkinter.Frame):
# return "/scenes/{}".format(idx)
# return "/no_obj_scene/{}".format(rec_idx)
- def fmt_hl_rec(self, lst, pref, rec_idx, full = False):
- for idx, rec in enumerate(lst):
- if rec.idx == rec_idx:
- fmt = fmt_hl("/{}/{}".format(pref, idx), str(rec_idx))
- if full:
- try:
- fmt += " (0x{:X}) - {}".format(rec.idx, hlesc(rec.name))
- except:
- fmt += " (0x{:X})".format(rec.idx)
- return fmt
- return "{} (0x{:X})".format(rec_idx, rec_idx)
+ def fmt_hl_rec(self, lst, lst_idx, pref, rec_id, full = False):
+ if rec_id in lst_idx:
+ fmt = fmt_hl("/{}/{}".format(pref, rec_id), str(rec_id))
+ if full:
+ try:
+ rec = lst[lst_idx[rec_id]]
+ fmt += " (0x{:X}) - {}".format(rec_id, hlesc(rec.name))
+ except:
+ fmt += " (0x{:X})".format(rec_id)
+ return fmt
+ return "{} (0x{:X})".format(rec_id, rec_id)
- def fmt_hl_obj(self, obj_idx, full = False):
- return self.fmt_hl_rec(self.sim.objects, "objs", obj_idx, full)
+ def fmt_hl_obj(self, obj_id, full = False):
+ return self.fmt_hl_rec(self.sim.objects, self.sim.obj_idx, "objs",
+ obj_id, full)
- def fmt_hl_scene(self, scn_idx, full = False):
- return self.fmt_hl_rec(self.sim.scenes, "scenes", scn_idx, full)
-
- def fmt_hl_obj_scene(self, rec_idx, full = False):
- if rec_idx in self.sim.obj_idx:
- return self.fmt_hl_rec(self.sim.objects, "objs", rec_idx, full)
- return self.fmt_hl_rec(self.sim.scenes, "scenes", rec_idx, full)
+ def fmt_hl_scene(self, scn_id, full = False):
+ return self.fmt_hl_rec(self.sim.scenes, self.sim.scn_idx, "scenes",
+ scn_id, full)
+
+ def fmt_hl_obj_scene(self, rec_id, full = False):
+ if rec_id in self.sim.obj_idx:
+ return self.fmt_hl_rec(self.sim.objects, self.sim.obj_idx, "objs",
+ rec_id, full)
+ return self.fmt_hl_rec(self.sim.scenes, self.sim.scn_idx, "scenes",
+ rec_id, full)
def find_path_name(self, key):
- for idx, name in enumerate(self.sim.namesord):
+ for name_id, name in enumerate(self.sim.namesord):
if name == key:
- return "/names/{}".format(idx)
+ return "/names/{}".format(name_id)
return "/no_name/{}".format(key)
def find_path_invntr(self, key):
- for idx, name in enumerate(self.sim.invntrord):
+ for inv_id, name in enumerate(self.sim.invntrord):
if name == key:
- return "/invntr/{}".format(idx)
+ return "/invntr/{}".format(inv_id)
return "/no_invntr/{}".format(key)
#def find_path_dlggrp(self, grp_idx):
@@ -711,11 +694,16 @@ class App(tkinter.Frame):
# return "/dlgs/{}".format(idx)
# return "/no_dlgs/{}".format(grp_idx)
- def fmt_hl_msg(self, obj_idx, full = False):
- return self.fmt_hl_rec(self.sim.msgs, "msgs", obj_idx, full)
+ def fmt_hl_msg(self, msg_id, full = False):
+ msg_idx = []
+ if msg_id < len(self.sim.msgs):
+ msg_idx[msg_id] = self.sim.msgs[msg_id]
+ return self.fmt_hl_rec(self.sim.msgs, msg_idx, "msgs",
+ msg_id, full)
- def fmt_hl_dlg(self, grp_idx, full = False):
- return self.fmt_hl_rec(self.sim.dlgs, "dlgs", grp_idx, full)
+ def fmt_hl_dlg(self, grp_id, full = False):
+ return self.fmt_hl_rec(self.sim.dlgs, self.sim.dlg_idx, "dlgs",
+ grp_id, full)
def path_info_outline(self):
if self.sim is None:
@@ -1003,22 +991,24 @@ class App(tkinter.Frame):
isobj = (self.curr_path[0] == "objs")
if isobj:
lst = self.sim.objects
+ lst_idx = self.sim.obj_idx
else:
lst = self.sim.scenes
+ lst_idx = self.sim.scn_idx
if self.last_path[:1] != (self.curr_path[0],):
if isobj:
self.update_gui("Objects ({})".format(len(lst)))
else:
self.update_gui("Scenes ({})".format(len(lst)))
- for idx, rec in enumerate(lst):
+ for rec in lst:
self.insert_lb_act("{} - {}".format(rec.idx, rec.name), \
- [self.curr_path[0], idx])
+ [self.curr_path[0], rec.idx], rec.idx)
# change
rec = None
if len(path) > 1:
# index
self.select_lb_item(path[1])
- rec = lst[path[1]]
+ rec = lst_idx[path[1]]
else:
self.select_lb_item(None)
# display
Commit: 9b7ff2f6ff4dafeff8340e698a1bffee325819f3
https://github.com/scummvm/scummvm-tools/commit/9b7ff2f6ff4dafeff8340e698a1bffee325819f3
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index e729ffff4..5245c10a4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -98,6 +98,7 @@ class App(tkinter.Frame):
else:
self.app_path = __file__
self.app_path = os.path.abspath(os.path.dirname(self.app_path))
+ self.start_path = "/about"
# gui
self.path_handler = {}
self.curr_main = -1 # 0 - frame, 1 - canvas
@@ -195,11 +196,7 @@ class App(tkinter.Frame):
self.path_handler["help"] = self.path_help
self.update_after()
- self.open_path("/about")
- #self.open_path(self.find_path_scene(36))
- #self.open_path(["res", "flt", "BMP", 7])
- #self.open_path(["dlgs", 6])
- #self.open_path(self.find_path_obj(448))
+ self.open_path(self.start_path)
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -649,32 +646,28 @@ class App(tkinter.Frame):
# return "/scenes/{}".format(idx)
# return "/no_obj_scene/{}".format(rec_idx)
- def fmt_hl_rec(self, lst, lst_idx, pref, rec_id, full = False):
+ def fmt_hl_rec(self, lst_idx, pref, rec_id, full = False):
if rec_id in lst_idx:
fmt = fmt_hl("/{}/{}".format(pref, rec_id), str(rec_id))
if full:
try:
- rec = lst[lst_idx[rec_id]]
- fmt += " (0x{:X}) - {}".format(rec_id, hlesc(rec.name))
+ fmt += " (0x{:X}) - {}".format(rec_id,
+ lst_idx[rec_id].name)
except:
fmt += " (0x{:X})".format(rec_id)
return fmt
return "{} (0x{:X})".format(rec_id, rec_id)
def fmt_hl_obj(self, obj_id, full = False):
- return self.fmt_hl_rec(self.sim.objects, self.sim.obj_idx, "objs",
- obj_id, full)
+ return self.fmt_hl_rec(self.sim.obj_idx, "objs", obj_id, full)
def fmt_hl_scene(self, scn_id, full = False):
- return self.fmt_hl_rec(self.sim.scenes, self.sim.scn_idx, "scenes",
- scn_id, full)
+ return self.fmt_hl_rec(self.sim.scn_idx, "scenes", scn_id, full)
def fmt_hl_obj_scene(self, rec_id, full = False):
if rec_id in self.sim.obj_idx:
- return self.fmt_hl_rec(self.sim.objects, self.sim.obj_idx, "objs",
- rec_id, full)
- return self.fmt_hl_rec(self.sim.scenes, self.sim.scn_idx, "scenes",
- rec_id, full)
+ return self.fmt_hl_rec(self.sim.obj_idx, "objs", rec_id, full)
+ return self.fmt_hl_rec(self.sim.scn_idx, "scenes", rec_id, full)
def find_path_name(self, key):
for name_id, name in enumerate(self.sim.namesord):
@@ -688,22 +681,14 @@ class App(tkinter.Frame):
return "/invntr/{}".format(inv_id)
return "/no_invntr/{}".format(key)
- #def find_path_dlggrp(self, grp_idx):
- # for idx, grp in enumerate(self.sim.dlgs):
- # if grp.idx == grp_idx:
- # return "/dlgs/{}".format(idx)
- # return "/no_dlgs/{}".format(grp_idx)
-
def fmt_hl_msg(self, msg_id, full = False):
- msg_idx = []
+ msg_idx = {}
if msg_id < len(self.sim.msgs):
msg_idx[msg_id] = self.sim.msgs[msg_id]
- return self.fmt_hl_rec(self.sim.msgs, msg_idx, "msgs",
- msg_id, full)
+ return self.fmt_hl_rec(msg_idx, "msgs", msg_id, full)
def fmt_hl_dlg(self, grp_id, full = False):
- return self.fmt_hl_rec(self.sim.dlgs, self.sim.dlg_idx, "dlgs",
- grp_id, full)
+ return self.fmt_hl_rec(self.sim.dlg_idx, "dlgs", grp_id, full)
def path_info_outline(self):
if self.sim is None:
@@ -760,10 +745,21 @@ class App(tkinter.Frame):
def path_parts(self, path):
if self.sim is None:
return self.path_default([])
+ def parsepart(part_id):
+ return pnum, cnum
+
if self.last_path[:1] != ("parts",):
self.update_gui("Parts ({})".format(len(self.sim.parts)))
- for idx, name in enumerate(self.sim.parts):
- self.insert_lb_act(name, ["parts", idx])
+ for name in self.sim.parts:
+ pnum = name[5:]
+ cnum = pnum.split("Chapter", 1)
+ if len(cnum) > 1:
+ pnum = int(cnum[0].strip(), 10)
+ cnum = int(cnum[1].strip(), 10)
+ else:
+ cnum = 0
+ part_id = "{}.{}".format(pnum, cnum)
+ self.insert_lb_act(name, ["parts", part_id], part_id)
if len(self.sim.parts) == 0:
# Option to fix paths
def fix_paths():
@@ -781,15 +777,10 @@ class App(tkinter.Frame):
if len(path) > 1:
# parts
self.select_lb_item(path[1])
- part_id = self.sim.parts[path[1]]
- # parse
- pnum = part_id[5:]
- cnum = pnum.split("Chapter", 1)
- if len(cnum) > 1:
- pnum = int(cnum[0].strip(), 10)
- cnum = int(cnum[1].strip(), 10)
- else:
- cnum = 0
+ part_id = path[1]
+ part_id = part_id.split(".", 1)
+ pnum = int(part_id[0])
+ cnum = int(part_id[1])
self.sim.open_part(pnum, cnum)
self.clear_hist()
else:
@@ -815,6 +806,12 @@ class App(tkinter.Frame):
return self.path_default(path)
def path_res_open(self, pref, res_id, mode):
+ if res_id not in self.sim.res:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("<b>Resource</b> \"{}\" not found\n".format(res_id))
+ return
+ self.select_lb_item(res_id)
resref = "/" + "/".join([str(x) for x in pref])
if len(mode) == 0:
self.switch_view(0)
@@ -937,6 +934,7 @@ class App(tkinter.Frame):
for ft in ftk:
self.add_info(" <a href=\"/res/flt/{}\">{}</a>: {}\n".format(
ft, ft, fts[ft]))
+ self.select_lb_item(None)
def on_path_res_info(self):
self.switch_view(0)
@@ -945,22 +943,18 @@ class App(tkinter.Frame):
self.switch_view(1)
def path_res_all(self, path):
- if self.last_path[:2] != ("res", "all",):
+ if self.last_path[:2] != ("res", "all",) and self.last_path != ("res",):
self.update_gui("Resources ({})".format(len(self.sim.res)))
#self.add_toolbtn("Info", self.on_path_res_info)
#self.add_toolbtn("View", self.on_path_res_view)
- for idx, res_id in enumerate(self.sim.resord):
+ for res_id in self.sim.resord:
self.insert_lb_act("{} - {}".format(\
- res_id, self.sim.res[res_id]), ["res", "all", idx])
+ res_id, self.sim.res[res_id]), ["res", "all", res_id], res_id)
# change
if len(path) > 2:
- # parts
- self.select_lb_item(path[2])
- res_id = self.sim.resord[path[2]]
- self.path_res_open(path[:3], res_id, path[3:])
+ self.path_res_open(path[:3], path[2], path[3:])
else:
self.path_res_status()
- self.select_lb_item(None)
def path_res_flt(self, path):
lst = []
@@ -971,18 +965,15 @@ class App(tkinter.Frame):
self.update_gui("Resources {} ({})".format(path[2], len(lst)))
self.insert_lb_act("All", "/res")
self.insert_lb_act("-", None)
- for idx, res_id in enumerate(lst):
+ for res_id in lst:
self.insert_lb_act("{} - {}".format(\
- res_id, self.sim.res[res_id]), ["res", "flt", path[2], idx])
+ res_id, self.sim.res[res_id]), ["res", "flt", path[2], res_id],
+ res_id)
# change
if len(path) > 3:
- # parts
- self.select_lb_item(path[3] + 2)
- res_id = lst[path[3]]
- self.path_res_open(path[:4], res_id, path[4:])
+ self.path_res_open(path[:4], path[3], path[4:])
else:
self.path_res_status()
- self.select_lb_item(None)
def path_objs_scenes(self, path):
if self.sim is None:
@@ -1008,12 +999,18 @@ class App(tkinter.Frame):
if len(path) > 1:
# index
self.select_lb_item(path[1])
- rec = lst_idx[path[1]]
+ try:
+ rec = lst_idx[path[1]]
+ except:
+ pass
else:
self.select_lb_item(None)
# display
self.clear_info()
if not rec:
+ if len(path) > 1:
+ self.add_info("Item \"{}\" at <b>{}</b> not found\n\n".format(
+ path[1], path[0]))
self.add_info("Select item from list\n")
else:
# record info
@@ -1026,7 +1023,7 @@ class App(tkinter.Frame):
"Alias") + ": {}\n".format(
hlesc(self.sim.names[rec.name])))
if rec.name in self.sim.invntr:
- self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
"Invntr") + ": {}\n".format(
hlesc(self.sim.invntr[rec.name])))
# references / backreferences
@@ -1106,10 +1103,9 @@ class App(tkinter.Frame):
self.add_info("\n<b>Used resources</b>: {}\n".\
format(len(resused)))
for res_id in resused:
- self.add_info(" <a href=\"{}\">{}</a> (0x{:X}) - {}\n".\
- format(self.find_path_res(res_id), res_id, res_id, \
- hlesc(self.sim.res[res_id])))
-
+ self.add_info(" " + fmt_hl("/res/all/{}".format(res_id),
+ "{}".format(res_id)) + " (0x{:X}) - {}\n".format(res_id,
+ hlesc(self.sim.res[res_id])))
if len(dlgused) > 0:
self.add_info("\n<b>Used dialog groups</b>: {}\n".\
format(len(dlgused)))
@@ -1191,26 +1187,30 @@ class App(tkinter.Frame):
if len(capt) > 25:
capt = capt[:25] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt),
- ["msgs", idx])
+ ["msgs", idx], idx)
# change
msg = None
if len(path) > 1:
- # parts
+ # index
self.select_lb_item(path[1])
- msg = self.sim.msgs[path[1]]
+ try:
+ msg = self.sim.msgs[path[1]]
+ except:
+ pass
else:
self.select_lb_item(None)
# display
self.clear_info()
if not msg:
- self.add_info("Select <b>message</b>\n")
+ if len(path) > 1:
+ self.add_info("<b>MEssage</b> \"{}\" not found\n\n".format(
+ path[1]))
+ self.add_info("Select <b>message</b> from list\n")
else:
# msg info
self.add_info("<b>Message</b>: {}\n".format(path[1]))
self.add_info(" wav: {}\n".format(msg.wav))
- self.add_info(" object: <a href=\"{}\">{}</a> (0x{:X}) - {}\n".\
- format(self.find_path_obj(msg.arg1), msg.arg1, msg.arg1,
- msg.obj.name))
+ self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx) + "\n")
self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
self.add_info("\n{}\n".format(hlesc(msg.name)))
@@ -1231,21 +1231,28 @@ class App(tkinter.Frame):
self.switch_view(0)
if self.last_path[:1] != ("dlgs",):
self.update_gui("Dialog groups ({})".format(len(self.sim.dlgs)))
- for idx, grp in enumerate(self.sim.dlgs):
+ for grp in self.sim.dlgs:
self.insert_lb_act("{} (0x{:X})".format(grp.idx, grp.idx),
- ["dlgs", idx])
+ ["dlgs", grp.idx], grp.idx)
+
# change
grp = None
if len(path) > 1:
- # parts
+ # index
self.select_lb_item(path[1])
- grp = self.sim.dlgs[path[1]]
+ try:
+ grp = self.sim.dlg_idx[path[1]]
+ except:
+ pass
else:
self.select_lb_item(None)
# display
self.clear_info()
if not grp:
- self.add_info("Select <b>dialog group</b>\n")
+ if len(path) > 1:
+ self.add_info("<b>Dialog</b> \"{}\" not found\n\n".format(
+ path[1]))
+ self.add_info("Select <b>dialog group</b> from list\n")
else:
# grp info
self.add_info("<b>Dialog group</b>: {} (0x{:X})\n".format(\
@@ -1435,6 +1442,8 @@ def main():
app = App(master = root)
if len(sys.argv) > 1:
app.open_data_from(sys.argv[1])
+ if len(sys.argv) > 2:
+ app.start_path = sys.argv[2]
app.mainloop()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index acc943436..86cbdb2e5 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -373,6 +373,7 @@ class Engine:
f.close()
self.dlgs = []
+ self.dlg_idx = {}
self.dlgops = []
# DIALOGUES.FIX
fp = self.curr_path + "dialogue.fix"
@@ -388,6 +389,7 @@ class Engine:
self.dlgs.append(grp)
opref = {}
for grp in self.dlgs:
+ self.dlg_idx[grp.idx] = grp
grp.acts = []
for i in range(grp.num_acts):
temp = f.read(16)
Commit: 92814b2799c5e9ff101d976f419b6f51c7b0c54a
https://github.com/scummvm/scummvm-tools/commit/92814b2799c5e9ff101d976f419b6f51c7b0c54a
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 5245c10a4..b22efa402 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -190,6 +190,7 @@ class App(tkinter.Frame):
self.path_handler["invntr"] = self.path_invntr
self.path_handler["msgs"] = self.path_msgs
self.path_handler["dlgs"] = self.path_dlgs
+ self.path_handler["casts"] = self.path_casts
self.path_handler["test"] = self.path_test
self.path_handler["about"] = self.path_about
self.path_handler["support"] = self.path_support
@@ -741,6 +742,7 @@ class App(tkinter.Frame):
for name, act in acts:
self.insert_lb_act(name, act)
+
def path_parts(self, path):
if self.sim is None:
@@ -1125,19 +1127,22 @@ class App(tkinter.Frame):
if self.last_path[:1] != ("names",):
self.update_gui("Names ({})".format(len(self.sim.names)))
for idx, name in enumerate(self.sim.namesord):
- self.insert_lb_act(name, ["names", idx])
+ self.insert_lb_act(name, ["names", idx], idx)
# change
name = None
if len(path) > 1:
# parts
self.select_lb_item(path[1])
- name = self.sim.namesord[path[1]]
+ try:
+ name = self.sim.namesord[path[1]]
+ except:
+ pass
else:
self.select_lb_item(None)
# display
self.clear_info()
if not name:
- self.add_info("Select <b>name</b>\n")
+ self.add_info("Select <b>name</b> from list\n")
else:
# name info
self.add_info("<b>Alias</b>: {}\n".format(hlesc(name)))
@@ -1300,7 +1305,9 @@ class App(tkinter.Frame):
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
-
+ def path_casts(self, path):
+ pass
+
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
self.insert_lb_act("Outline", [])
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 86cbdb2e5..4ae1e17a7 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -345,6 +345,19 @@ class Engine:
self.invntr = ini["ALL"]
self.invntrord = ini["__order__"]["ALL"]
f.close()
+
+ self.casts = {}
+ self.castsord = []
+ fp = self.curr_path + "cast.ini"
+ if self.fman.exists(fp):
+ f = self.fman.read_file_stream(fp)
+ ini = self.parse_ini(f)
+ self.casts = ini["all"]
+ self.castsord = ini["__order__"]["all"]
+ f.close()
+ # bind casts to objects
+ for cast in self.castsord:
+ #print(cast)
def load_dialogs(self):
self.msgs = []
Commit: 855c321e5ad5760b8cec4a02a8a98daa93f47cc4
https://github.com/scummvm/scummvm-tools/commit/855c321e5ad5760b8cec4a02a8a98daa93f47cc4
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Casts data
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index b22efa402..a453cc926 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -236,6 +236,9 @@ class App(tkinter.Frame):
self.menuedit.add_command(
command = lambda: self.open_path("/invntr"),
label = "Invntr")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/casts"),
+ label = "Casts")
self.menuedit.add_command(
command = lambda: self.open_path("/msgs"),
label = "Messages")
@@ -742,13 +745,9 @@ class App(tkinter.Frame):
for name, act in acts:
self.insert_lb_act(name, act)
-
-
def path_parts(self, path):
if self.sim is None:
return self.path_default([])
- def parsepart(part_id):
- return pnum, cnum
if self.last_path[:1] != ("parts",):
self.update_gui("Parts ({})".format(len(self.sim.parts)))
@@ -775,22 +774,36 @@ class App(tkinter.Frame):
path = self.sim.fman.root = path
self.sim.curr_path += "\\"
self.add_toolbtn("Fix paths", fix_paths)
- # change
+
+ # change
+ part = None
if len(path) > 1:
# parts
self.select_lb_item(path[1])
- part_id = path[1]
- part_id = part_id.split(".", 1)
- pnum = int(part_id[0])
- cnum = int(part_id[1])
- self.sim.open_part(pnum, cnum)
- self.clear_hist()
+ try:
+ part = path[1]
+ part = part.split(".", 1)
+ part[0] = int(part[0])
+ part[1] = int(part[1])
+ except:
+ part = None
+ pass
else:
self.select_lb_item(None)
# display
self.clear_info()
- self.add_info("Select <b>part</b>\n\n")
- self.path_info_outline()
+ if not part:
+ self.add_info("Select <b>part</b>\n\n")
+ self.path_info_outline()
+ else:
+ try:
+ self.clear_hist()
+ self.sim.open_part(part[0], part[1])
+ self.path_info_outline()
+ except:
+ self.add_info("Error open part {} chapter {} - \n\n{}".\
+ format(part[0], part[1], hlesc(traceback.format_exc())))
+
def path_res(self, path):
# res - full list
@@ -1208,14 +1221,15 @@ class App(tkinter.Frame):
self.clear_info()
if not msg:
if len(path) > 1:
- self.add_info("<b>MEssage</b> \"{}\" not found\n\n".format(
+ self.add_info("<b>Message</b> \"{}\" not found\n\n".format(
path[1]))
self.add_info("Select <b>message</b> from list\n")
else:
# msg info
self.add_info("<b>Message</b>: {}\n".format(path[1]))
self.add_info(" wav: {}\n".format(msg.wav))
- self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx) + "\n")
+ self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx, True) +
+ "\n")
self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
self.add_info("\n{}\n".format(hlesc(msg.name)))
@@ -1306,7 +1320,37 @@ class App(tkinter.Frame):
usedby(self.sim.scenes)
def path_casts(self, path):
- pass
+ if self.sim is None:
+ return self.path_default([])
+ self.switch_view(0)
+ if self.last_path[:1] != ("casts",):
+ self.update_gui("Cast ({})".format(len(self.sim.casts)))
+ for idx, name in enumerate(self.sim.castsord):
+ self.insert_lb_act(name, ["casts", idx], idx)
+ # change
+ name = None
+ if len(path) > 1:
+ # parts
+ self.select_lb_item(path[1])
+ try:
+ name = self.sim.castsord[path[1]]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ if not name:
+ self.add_info("Select <b>cast</b> from list\n")
+ else:
+ # name info
+ self.add_info("<b>Cast</b>: {}\n".format(hlesc(name)))
+ self.add_info("Value: {}\n\n".format(self.sim.casts[name]))
+ # search for objects
+ self.add_info("<b>Applied for</b>:\n")
+ for idx, obj in enumerate(self.sim.objects):
+ if obj.name == name:
+ self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 4ae1e17a7..d2dc27126 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -358,7 +358,8 @@ class Engine:
# bind casts to objects
for cast in self.castsord:
#print(cast)
-
+ pass
+
def load_dialogs(self):
self.msgs = []
# DIALOGUES.LOD
Commit: 5faa3663585917268afedba21f46710b798045cc
https://github.com/scummvm/scummvm-tools/commit/5faa3663585917268afedba21f46710b798045cc
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Casts data
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index a453cc926..95615c5a3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -710,6 +710,8 @@ class App(tkinter.Frame):
format(len(self.sim.names)))
self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
format(len(self.sim.invntr)))
+ self.add_info(" Casts: <a href=\"/casts\">{}</a>\n".\
+ format(len(self.sim.casts)))
self.add_info(" Messages <a href=\"/msgs\">{}</a>\n".\
format(len(self.sim.msgs)))
self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
@@ -736,6 +738,7 @@ class App(tkinter.Frame):
("Scenes ({})".format(len(self.sim.scenes)), "/scenes"),
("Names ({})".format(len(self.sim.names)), "/names"),
("Invntr ({})".format(len(self.sim.invntr)), "/invntr"),
+ ("Casts ({})".format(len(self.sim.casts)), "/casts"),
("Messages ({})".format(len(self.sim.msgs)), "/msgs"),
("Dialog groups ({})".format(len(self.sim.dlgs)), "/dlgs"),
("-", None),
Commit: d8cc88b71b5299fbe3667f56675946ad502f937d
https://github.com/scummvm/scummvm-tools/commit/d8cc88b71b5299fbe3667f56675946ad502f937d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 95615c5a3..28b7b2cb5 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -623,40 +623,13 @@ class App(tkinter.Frame):
self.hist.append(np)
self.open_path(np[0], False)
- #def find_path_res(self, res):
- # for idx, res_id in enumerate(self.sim.resord):
- # if res_id == res:
- # return "/res/all/{}".format(idx)
- # return "/no_res/{}".format(res)
-
- #def find_path_obj(self, obj_idx):
- # for idx, rec in enumerate(self.sim.objects):
- # if rec.idx == obj_idx:
- # return "/objs/{}".format(idx)
- # return "/no_obj/{}".format(obj_idx)
-
- #def find_path_scene(self, scn_idx):
- # for idx, rec in enumerate(self.sim.scenes):
- # if rec.idx == scn_idx:
- # return "/scenes/{}".format(idx)
- # return "/no_scene/{}".format(scn_idx)
-
- #def find_path_obj_scene(self, rec_idx):
- # for idx, rec in enumerate(self.sim.objects):
- # if rec.idx == rec_idx:
- # return "/objs/{}".format(idx)
- # for idx, rec in enumerate(self.sim.scenes):
- # if rec.idx == rec_idx:
- # return "/scenes/{}".format(idx)
- # return "/no_obj_scene/{}".format(rec_idx)
-
def fmt_hl_rec(self, lst_idx, pref, rec_id, full = False):
if rec_id in lst_idx:
fmt = fmt_hl("/{}/{}".format(pref, rec_id), str(rec_id))
if full:
try:
fmt += " (0x{:X}) - {}".format(rec_id,
- lst_idx[rec_id].name)
+ hlesc(lst_idx[rec_id].name))
except:
fmt += " (0x{:X})".format(rec_id)
return fmt
@@ -1136,21 +1109,23 @@ class App(tkinter.Frame):
if msg.obj.idx != rec.idx: continue
self.add_info(" " + self.fmt_hl_msg(msg.idx, True) + "\n")
- def path_names(self, path):
- if self.sim is None:
- return self.path_default([])
+ def path_std_items(self, path, level, guiname, guiitem, lst, lst_idx,
+ lbmode, cb):
self.switch_view(0)
- if self.last_path[:1] != ("names",):
- self.update_gui("Names ({})".format(len(self.sim.names)))
- for idx, name in enumerate(self.sim.namesord):
- self.insert_lb_act(name, ["names", idx], idx)
+ if self.last_path[:level] != path[:level]:
+ self.update_gui("{} ({})".format(guiname, len(lst)))
+ for idx, name in enumerate(lst_idx):
+ lb = name
+ if lbmode == 1:
+ lb = "{} - {}".format(name, lst[name])
+ self.insert_lb_act(lb, path[:level] + tuple([idx]), idx)
# change
name = None
if len(path) > 1:
- # parts
+ # lb
self.select_lb_item(path[1])
try:
- name = self.sim.namesord[path[1]]
+ name = lst_idx[path[1]]
except:
pass
else:
@@ -1158,44 +1133,54 @@ class App(tkinter.Frame):
# display
self.clear_info()
if not name:
- self.add_info("Select <b>name</b> from list\n")
+ self.add_info("Select <b>{}</b> from list\n".format(guiitem))
else:
- # name info
+ # info
+ cb(name)
+
+
+ def path_names(self, path):
+ if self.sim is None:
+ return self.path_default([])
+ def info(name):
self.add_info("<b>Alias</b>: {}\n".format(hlesc(name)))
self.add_info("Value: {}\n\n".format(self.sim.names[name]))
# search for objects
self.add_info("<b>Applied for</b>:\n")
- for idx, obj in enumerate(self.sim.objects):
+ for obj in self.sim.objects:
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
-
+ return self.path_std_items(path, 1, "Names", "name", self.sim.names,
+ self.sim.namesord, 0, info)
+
def path_invntr(self, path):
if self.sim is None:
return self.path_default([])
- self.switch_view(0)
- if self.last_path[:1] != ("invntr",):
- self.update_gui("Invntr ({})".format(len(self.sim.invntr)))
- for idx, name in enumerate(self.sim.invntrord):
- self.insert_lb_act(name, ["invntr", idx])
- # change
- name = None
- if len(path) > 1:
- # parts
- self.select_lb_item(path[1])
- name = self.sim.invntrord[path[1]]
- # display
- self.clear_info()
- if not name:
- self.add_info("Select <b>invntr</b>\n")
- else:
- # invntr info
- self.add_info("<b>Invntr</b>: {}\n".format(name))
- self.add_info("{}\n\n".format(hlesc(self.sim.invntr[name])))
+ def info(name):
+ self.add_info("<b>Invntr</b>: {}\n".format(hlesc(name)))
+ self.add_info("{}\n\n".format(self.sim.invntr[name]))
+ # search for objects
+ self.add_info("<b>Applied for</b>:\n")
+ for obj in self.sim.objects:
+ if obj.name == name:
+ self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
+ return self.path_std_items(path, 1, "Invntr", "invntr", self.sim.invntr,
+ self.sim.invntrord, 0, info)
+
+
+ def path_casts(self, path):
+ if self.sim is None:
+ return self.path_default([])
+ def info(name):
+ self.add_info("<b>Cast</b>: {}\n".format(hlesc(name)))
+ self.add_info("Value: {}\n\n".format(self.sim.casts[name]))
# search for objects
self.add_info("<b>Applied for</b>:\n")
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
+ return self.path_std_items(path, 1, "Cast", "cast", self.sim.casts,
+ self.sim.castsord, 0, info)
def path_msgs(self, path):
if self.sim is None:
@@ -1322,38 +1307,6 @@ class App(tkinter.Frame):
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
- def path_casts(self, path):
- if self.sim is None:
- return self.path_default([])
- self.switch_view(0)
- if self.last_path[:1] != ("casts",):
- self.update_gui("Cast ({})".format(len(self.sim.casts)))
- for idx, name in enumerate(self.sim.castsord):
- self.insert_lb_act(name, ["casts", idx], idx)
- # change
- name = None
- if len(path) > 1:
- # parts
- self.select_lb_item(path[1])
- try:
- name = self.sim.castsord[path[1]]
- except:
- pass
- else:
- self.select_lb_item(None)
- # display
- self.clear_info()
- if not name:
- self.add_info("Select <b>cast</b> from list\n")
- else:
- # name info
- self.add_info("<b>Cast</b>: {}\n".format(hlesc(name)))
- self.add_info("Value: {}\n\n".format(self.sim.casts[name]))
- # search for objects
- self.add_info("<b>Applied for</b>:\n")
- for idx, obj in enumerate(self.sim.objects):
- if obj.name == name:
- self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
Commit: 82d97637d1997b2d9b15e8a577829297100b0557
https://github.com/scummvm/scummvm-tools/commit/82d97637d1997b2d9b15e8a577829297100b0557
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 28b7b2cb5..6cf64dba7 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -130,6 +130,7 @@ class App(tkinter.Frame):
self.toolbar.pack(fill = tkinter.BOTH)
btns = [
["Outline", lambda: self.open_path("")],
+ ["Help", self.on_help],
[None, None],
["<-", self.on_back],
["->", self.on_forward],
Commit: e5adc359d0f3544b05d36b685bacf700ae06f156
https://github.com/scummvm/scummvm-tools/commit/e5adc359d0f3544b05d36b685bacf700ae06f156
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Context help
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 6cf64dba7..a19934122 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -610,6 +610,12 @@ class App(tkinter.Frame):
self.hist = self.hist[-1:]
self.histf = []
+ def on_help(self):
+ if len(self.curr_path) > 0:
+ self.open_path(["help", self.curr_path[0]])
+ else:
+ self.open_path(["help"])
+
def on_back(self):
if len(self.hist) > 1:
np = self.hist[-2:-1][0]
Commit: fc10e027f2ff70322d1c92c1e41a00a689e175a0
https://github.com/scummvm/scummvm-tools/commit/fc10e027f2ff70322d1c92c1e41a00a689e175a0
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Info, help pages
Changed paths:
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
engines/petka/petka/__init__.py
engines/petka/petka/engine.py
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 4a2dcad34..69a5846bc 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -5,3 +5,21 @@
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
+ÐÑобÑажаемÑе ÑазделÑ
+
+ * <a href="/help/parts">ÐÑÐ±Ð¾Ñ ÑаÑÑи</a>
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/scenes">СÑенÑ</a>
+ * <a href="/help/names">ÐÑобÑажаемнÑе имена</a>
+ * <a href="/help/invntr">ÐнвенÑаÑÑ</a>
+ * <a href="/help/casts">ЦвеÑа пÑедмеÑов</a>
+ * <a href="/help/msgs">СобÑениÑ</a>
+ * <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
+
+ÐÑоÑÐ°Ñ Ð¸Ð½ÑоÑмаÑиÑ
+
+ * <a href="/help/support">ÐнÑоÑмаÑÐ¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð´ÐµÑжки</a>
+ * <a href="/help/info">СпÑавоÑники</a>
+ * <a href="/help/about">РпÑогÑамме</a>
+
diff --git a/engines/petka/help/list b/engines/petka/help/list
index 74879b370..62df0df1f 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -1,4 +1,16 @@
index
changes
faq
+parts
+res
+objs
+scenes
+names
+invntr
+casts
+msgs
+dlgs
+support
+info
+about
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index a19934122..97a4b5881 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -196,6 +196,7 @@ class App(tkinter.Frame):
self.path_handler["about"] = self.path_about
self.path_handler["support"] = self.path_support
self.path_handler["help"] = self.path_help
+ self.path_handler["info"] = self.path_info
self.update_after()
self.open_path(self.start_path)
@@ -275,6 +276,9 @@ class App(tkinter.Frame):
self.menuhelp.add_command(
command = lambda: self.open_path("/support"),
label = "Support")
+ self.menuhelp.add_command(
+ command = lambda: self.open_path("/info"),
+ label = "Info")
self.menuhelp.add_command(
command = lambda: self.open_path("/about"),
label = "About")
@@ -721,9 +725,9 @@ class App(tkinter.Frame):
("Casts ({})".format(len(self.sim.casts)), "/casts"),
("Messages ({})".format(len(self.sim.msgs)), "/msgs"),
("Dialog groups ({})".format(len(self.sim.dlgs)), "/dlgs"),
- ("-", None),
- ("Test image", ["test", "image"]),
- ("Test info", ["test","info"]),
+ #("-", None),
+ #("Test image", ["test", "image"]),
+ #("Test info", ["test","info"]),
]
for name, act in acts:
self.insert_lb_act(name, act)
@@ -1145,7 +1149,6 @@ class App(tkinter.Frame):
# info
cb(name)
-
def path_names(self, path):
if self.sim is None:
return self.path_default([])
@@ -1368,6 +1371,8 @@ class App(tkinter.Frame):
def path_help(self, path):
self.switch_view(0)
+ if path == ("help",):
+ path = ("help", "index")
if self.last_path[:1] != ("help",):
self.update_gui("Help")
# build help index
@@ -1418,6 +1423,42 @@ class App(tkinter.Frame):
else:
self.select_lb_item(None)
+ def path_info(self, path):
+ self.switch_view(0)
+ if self.last_path[:1] != ("info",):
+ self.update_gui("Info")
+ self.insert_lb_act("Opcodes", ["info", "opcodes"], "opcodes")
+ self.insert_lb_act("Dialog opcodes", ["info", "dlgops"], "dlgops")
+ # change
+ name = None
+ if len(path) > 1:
+ # lb
+ self.select_lb_item(path[1])
+ name = path[1]
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ if not name:
+ self.add_info("Select <b>info</b> from list\n")
+ else:
+ # info
+ if name == "opcodes":
+ self.add_info("<b>Opcodes<b>\n\n")
+ k = list(petka.OPCODES.keys())
+ k.sort()
+ for key in k:
+ self.add_info(" {} (0x{:X}) - {}\n".format(key, key,
+ petka.OPCODES[key][0]))
+ elif name == "dlgops":
+ self.add_info("<b>Dialog opcodes<b>\n\n")
+ k = list(petka.DLGOPS.keys())
+ k.sort()
+ for key in k:
+ self.add_info(" {} (0x{:X}) - {}\n".format(key, key,
+ petka.DLGOPS[key][0]))
+ else:
+ self.add_info("Unknown data type \"{}\"\n".format(hlesc(name)))
def on_open_data(self):
ft = [\
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index 42388d6d6..40b354c6f 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -1,7 +1,7 @@
class EngineError(Exception): pass
-from .engine import Engine, OPCODES
+from .engine import Engine, OPCODES, DLGOPS
from .fman import FileManager
from .imgbmp import BMPLoader
from .imgflc import FLCLoader
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index d2dc27126..ce8d4fdd8 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -70,6 +70,13 @@ OPCODES = {
63: ("TOMAP", 0),
}
+DLGOPS = {
+ 1: ("BREAK", 0),
+ 6: ("RETURN", 0),
+ 7: ("PLAY", 1),
+ 8: ("CIRCLE", 3),
+}
+
class ScrObject:
def __init__(self, idx, name):
self.idx = idx
Commit: 1bd7e2b3b9181aee2a187f1a6eaf82c2b9e2d7cd
https://github.com/scummvm/scummvm-tools/commit/1bd7e2b3b9181aee2a187f1a6eaf82c2b9e2d7cd
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: help pages
Changed paths:
A engines/petka/help/about.txt
A engines/petka/help/casts.txt
A engines/petka/help/dlgs.txt
A engines/petka/help/help.txt
A engines/petka/help/info.txt
A engines/petka/help/invntr.txt
A engines/petka/help/msgs.txt
A engines/petka/help/names.txt
A engines/petka/help/objs.txt
A engines/petka/help/parts.txt
A engines/petka/help/res.txt
A engines/petka/help/scenes.txt
A engines/petka/help/support.txt
diff --git a/engines/petka/help/about.txt b/engines/petka/help/about.txt
new file mode 100644
index 000000000..d42abfc4e
--- /dev/null
+++ b/engines/petka/help/about.txt
@@ -0,0 +1,4 @@
+РпÑогÑамме
+
+Ðа ÑÑой ÑÑÑаниÑе оÑобÑажаÑÑÑÑ Ð¾ÑновнÑе ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ пÑогÑамме и загÑÑженнÑÑ
+даннÑÑ
.
diff --git a/engines/petka/help/casts.txt b/engines/petka/help/casts.txt
new file mode 100644
index 000000000..eade4010a
--- /dev/null
+++ b/engines/petka/help/casts.txt
@@ -0,0 +1,5 @@
+ЦвеÑа пÑедмеÑов
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ ÑвеÑа опиÑаний пÑедмеÑов на ÑкÑане.
+
+
diff --git a/engines/petka/help/dlgs.txt b/engines/petka/help/dlgs.txt
new file mode 100644
index 000000000..e95d96cde
--- /dev/null
+++ b/engines/petka/help/dlgs.txt
@@ -0,0 +1,5 @@
+ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð²Ñе иÑполÑзÑемÑе гÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð².
+
+
diff --git a/engines/petka/help/help.txt b/engines/petka/help/help.txt
new file mode 100644
index 000000000..b3268bd5b
--- /dev/null
+++ b/engines/petka/help/help.txt
@@ -0,0 +1 @@
+См. <a href="/help">СпÑавка</a>
diff --git a/engines/petka/help/info.txt b/engines/petka/help/info.txt
new file mode 100644
index 000000000..51ea6c817
--- /dev/null
+++ b/engines/petka/help/info.txt
@@ -0,0 +1,7 @@
+СпÑавоÑники
+
+Ðа ÑÑой ÑÑÑаниÑе оÑобÑажаÑÑÑÑ ÑеÑ
ниÑеÑкие ÑпÑавоÑники.
+
+ * ÐÐ¾Ð´Ñ Ð¾Ð¿ÐµÑаÑий в обÑабоÑÑикаÑ
+ * ÐÐ¾Ð´Ñ Ð¾Ð¿ÐµÑаÑий в диалогаÑ
+
diff --git a/engines/petka/help/invntr.txt b/engines/petka/help/invntr.txt
new file mode 100644
index 000000000..7bfdd3be9
--- /dev/null
+++ b/engines/petka/help/invntr.txt
@@ -0,0 +1,5 @@
+ÐнвенÑаÑÑ
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¾Ð¿Ð¸Ñание пÑедмеÑов инвенÑаÑÑ.
+
+
diff --git a/engines/petka/help/msgs.txt b/engines/petka/help/msgs.txt
new file mode 100644
index 000000000..2221caceb
--- /dev/null
+++ b/engines/petka/help/msgs.txt
@@ -0,0 +1,5 @@
+СообÑениÑ
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð²Ñе иÑполÑзÑемÑе ÑообÑениÑ.
+
+
diff --git a/engines/petka/help/names.txt b/engines/petka/help/names.txt
new file mode 100644
index 000000000..11331ac02
--- /dev/null
+++ b/engines/petka/help/names.txt
@@ -0,0 +1,5 @@
+ÐÑобÑажаемÑе имена
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе оÑобÑажаемÑе имена.
+
+
diff --git a/engines/petka/help/objs.txt b/engines/petka/help/objs.txt
new file mode 100644
index 000000000..3a4f380f7
--- /dev/null
+++ b/engines/petka/help/objs.txt
@@ -0,0 +1,5 @@
+ÐбÑекÑÑ
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе обÑекÑÑ Ð¸ иÑ
паÑамеÑÑÑ.
+
+
diff --git a/engines/petka/help/parts.txt b/engines/petka/help/parts.txt
new file mode 100644
index 000000000..0554a03d0
--- /dev/null
+++ b/engines/petka/help/parts.txt
@@ -0,0 +1,6 @@
+ÐÑÐ±Ð¾Ñ ÑаÑÑи
+
+Ðа ÑÑой ÑÑÑаниÑе можно вÑбÑаÑÑ ÑаÑÑÑ Ñ ÐºÐ¾ÑоÑой бÑÐ´ÐµÑ Ð² далÑнейÑем веÑÑиÑÑ
+ÑабоÑа.
+
+
diff --git a/engines/petka/help/res.txt b/engines/petka/help/res.txt
new file mode 100644
index 000000000..9060002f3
--- /dev/null
+++ b/engines/petka/help/res.txt
@@ -0,0 +1,5 @@
+РеÑÑÑÑÑ
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе ÑеÑÑÑÑÑ (BMP, FLC, AVI и Ñ. д.)
+
+
diff --git a/engines/petka/help/scenes.txt b/engines/petka/help/scenes.txt
new file mode 100644
index 000000000..31e7e9302
--- /dev/null
+++ b/engines/petka/help/scenes.txt
@@ -0,0 +1,5 @@
+СÑенÑ
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе ÑÑÐµÐ½Ñ Ð¸ иÑ
паÑамеÑÑÑ.
+
+
diff --git a/engines/petka/help/support.txt b/engines/petka/help/support.txt
new file mode 100644
index 000000000..878f5cc98
--- /dev/null
+++ b/engines/petka/help/support.txt
@@ -0,0 +1,6 @@
+ÐнÑоÑмаÑÐ¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð´Ð´ÐµÑжки
+
+Ðа ÑÑой ÑÑÑаниÑе оÑобÑажаÑÑÑÑ ÑеÑ
ниÑеÑкие ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ Ð¾ пÑогÑамме и загÑÑженнÑÑ
+даннÑÑ
.
+
+ÐеÑедайÑе ÑÑи ÑÐ²ÐµÐ´ÐµÐ½Ð¸Ñ ÑазÑабоÑÑикам, пÑи необÑ
одимоÑÑи.
Commit: 1f44482793c93a988f34674b510f093e179adc92
https://github.com/scummvm/scummvm-tools/commit/1f44482793c93a988f34674b510f093e179adc92
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fixes
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 97a4b5881..2a0f2066d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -736,6 +736,7 @@ class App(tkinter.Frame):
if self.sim is None:
return self.path_default([])
+ self.switch_view(0)
if self.last_path[:1] != ("parts",):
self.update_gui("Parts ({})".format(len(self.sim.parts)))
for name in self.sim.parts:
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index ce8d4fdd8..9e5b2b352 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -250,8 +250,8 @@ class Engine:
# load .STR
strs = ["Flics", "Background", "Wav", "Music", "SFX"]
for strf in strs:
- pf = self.fman.find_path(self.curr_path + "bgs.ini")
- if not pf: continue
+ #pf = self.fman.find_path(self.curr_path + "bgs.ini")
+ #if not pf: continue
if strf in ini:
self.fman.load_store(ini[strf], 1)
# load script.dat, backgrnd.bg and resources.qrc
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index e9f9dea76..142597b92 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -67,6 +67,7 @@ class FileManager:
format(fname, name))
# add file descriptor
self.strfd.append((f, name, tag))
+ print("DEBUG: Loaded store \"{}\"".format(name))
def read_file(self, fname):
sf = fname.lower().replace("\\", "/")
Commit: 5aa3199fde98d5a12a3aba07d5f79ffcef973c31
https://github.com/scummvm/scummvm-tools/commit/5aa3199fde98d5a12a3aba07d5f79ffcef973c31
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Open data and select item from command line
Changed paths:
A engines/petka/help/cmdline.txt
engines/petka/help/changes.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 73a82330d..f3e341d8c 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -5,6 +5,7 @@
----------------------
ÐÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑе Support
Ðобавлена ÑпÑавка по пÑогÑамме
+Ðобавлен вÑÐ±Ð¾Ñ Ñаздела из командной ÑÑÑоки
2014-05-16 веÑÑÐ¸Ñ 0.2d
----------------------
diff --git a/engines/petka/help/cmdline.txt b/engines/petka/help/cmdline.txt
new file mode 100644
index 000000000..a0cae8862
--- /dev/null
+++ b/engines/petka/help/cmdline.txt
@@ -0,0 +1,21 @@
+ÐÐ¾Ð¼Ð¼Ð°Ð½Ð´Ð½Ð°Ñ ÑÑÑока
+
+СинÑакÑÐ¸Ñ Ð²Ñзова пÑогÑÐ°Ð¼Ð¼Ñ Ð¸Ð· коммандной ÑÑÑоки
+
+ p12simtran [пÑÑÑ Ðº даннÑм [оÑкÑÑваемÑе ÑазделÑ]
+
+ÐÑÑÑ Ðº даннÑм - пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð¸Ð»Ð¸ каÑÐ°Ð»Ð¾Ð³Ñ Ð³Ð´Ðµ наÑ
одиÑÑÑ Ñайл Ñ Ð´Ð°Ð½Ð½Ñми.
+
+ÐÑновнÑе ÑазделÑ:
+
+ * /parts - вÑÐ±Ð¾Ñ ÑаÑÑи
+ * /parts/2.1 - загÑÑзиÑÑ ÑаÑÑÑ 2 Ð³Ð»Ð°Ð²Ñ 1
+ * /res/all - ÑеÑÑÑÑÑ
+ * /res/all/31000 - загÑÑзиÑÑ ÑеÑÑÑÑ 31000
+ * /objs - обÑекÑÑ
+ * /scenes - ÑÑенÑ
+ * /msgs - ÑообÑениÑ
+ * /dlgs - гÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²
+
+
+
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 69a5846bc..265425f56 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -19,6 +19,7 @@
ÐÑоÑÐ°Ñ Ð¸Ð½ÑоÑмаÑиÑ
+ * <a href="/help/cmdline">ÐÑгÑменÑÑ ÐºÐ¾Ð¼Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ ÑÑÑоки</a>
* <a href="/help/support">ÐнÑоÑмаÑÐ¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð´ÐµÑжки</a>
* <a href="/help/info">СпÑавоÑники</a>
* <a href="/help/about">РпÑогÑамме</a>
diff --git a/engines/petka/help/list b/engines/petka/help/list
index 62df0df1f..a43ec9fd3 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -10,6 +10,7 @@ invntr
casts
msgs
dlgs
+cmdline
support
info
about
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 2a0f2066d..f435c6fc9 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -98,7 +98,7 @@ class App(tkinter.Frame):
else:
self.app_path = __file__
self.app_path = os.path.abspath(os.path.dirname(self.app_path))
- self.start_path = "/about"
+ self.start_act = []
# gui
self.path_handler = {}
self.curr_main = -1 # 0 - frame, 1 - canvas
@@ -199,7 +199,16 @@ class App(tkinter.Frame):
self.path_handler["info"] = self.path_info
self.update_after()
- self.open_path(self.start_path)
+ repath = "/about"
+ for cmd, arg in self.start_act:
+ if cmd == "load":
+ self.open_data_from(arg)
+ repath = "/"
+ elif cmd == "open":
+ self.open_path(arg)
+ repath = ""
+ if repath:
+ self.open_path(repath)
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
@@ -1497,9 +1506,9 @@ def main():
root = tkinter.Tk()
app = App(master = root)
if len(sys.argv) > 1:
- app.open_data_from(sys.argv[1])
- if len(sys.argv) > 2:
- app.start_path = sys.argv[2]
+ app.start_act.append(["load", sys.argv[1]])
+ for arg in sys.argv[2:]:
+ app.start_act.append(["open", arg])
app.mainloop()
Commit: d1f513f4325d33ab72a08d5021b7c20c998f79f1
https://github.com/scummvm/scummvm-tools/commit/d1f513f4325d33ab72a08d5021b7c20c998f79f1
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix dist
Changed paths:
engines/petka/dist/setup.py
diff --git a/engines/petka/dist/setup.py b/engines/petka/dist/setup.py
index 729cd75b0..fb31ef8dc 100644
--- a/engines/petka/dist/setup.py
+++ b/engines/petka/dist/setup.py
@@ -8,7 +8,7 @@ import sys, os, struct
# fine tuning.
buildOptions = dict(packages = ["re", "io", "PIL", "traceback", "zlib", "gzip", "argparse", "struct", "binascii"], \
excludes = ["_posixsubprocess"],
- include_files = [],
+ include_files = ["help"],
compressed = True, silent = True,\
optimize = 2, copy_dependent_files = True, \
create_shared_zip = True, include_in_shared_zip = True)
Commit: 30075a24503ffe4ac3cc8018bab3f95d5a3578a8
https://github.com/scummvm/scummvm-tools/commit/30075a24503ffe4ac3cc8018bab3f95d5a3578a8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Commant for dialog opcode 8
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index f3e341d8c..c80c386a9 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,10 @@
ЧÑо нового
==========
+2014-05-16 веÑÑÐ¸Ñ 0.2f
+----------------------
+ÐодÑказка пÑи декодиÑовании опкода 8 в дилогаÑ
+
2014-05-16 веÑÑÐ¸Ñ 0.2e
----------------------
ÐÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð½Ð° ÑÑÑаниÑе Support
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index f435c6fc9..006563d64 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2e 2014-05-16"
+VERSION = "v0.2f 2014-05-16"
def hlesc(value):
if value is None:
@@ -31,6 +31,9 @@ def hlesc(value):
def fmt_opcode(opcode):
return petka.OPCODES.get(opcode, ["OP{:04X}".format(opcode)])[0]
+def fmt_dlgop(opcode):
+ return petka.DLGOPS.get(opcode, ["OP{:02X}".format(opcode)])[0]
+
def fmt_hl(loc, desc):
return "<a href=\"{}\">{}</a>".format(loc, desc)
@@ -1294,20 +1297,43 @@ class App(tkinter.Frame):
for didx, dlg in enumerate(act.dlgs):
self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
- for op in dlg.ops:
+ for oidx, op in enumerate(dlg.ops):
cmt = ""
- msgref = "0x{:X}".format(op.ref)
- opcode = "OP{:02X}".format(op.opcode)
- if op.opcode == 7:
+ opref = "0x{:X}".format(op.ref)
+ opcode = fmt_dlgop(op.opcode)
+ if op.opcode == 0x7:
opcode = "PLAY"
if op.msg:
- msgref = self.fmt_hl_msg(op.ref)
+ opref = self.fmt_hl_msg(op.ref)
objref = self.fmt_hl_obj(op.msg.obj.idx)
cmt = " / obj={}, msg={}".\
format(objref,
self.fmt_hl_msg(op.ref, True))
+ if op.opcode == 8:
+ cmt = " / select from "
+ doarr = []
+ docurr = []
+ skiptobrk = False
+ for op2 in dlg.ops[oidx + 1:]:
+ #cmt += fmt_dlgop(op2.opcode) + " "
+ if op2.opcode == 0x1: # BREAK
+ doarr.append(docurr)
+ skiptobrk = False
+ if len(doarr) == op.ref:
+ break
+ docurr = []
+ elif op2.opcode == 0x7 and not skiptobrk: # PLAY
+ docurr.append(self.fmt_hl_msg(op2.ref))
+ else:
+ docurr = ["complex"]
+
+
+ if len(doarr) < op.ref:
+ cmt = " / circle select broken, required={}, "\
+ "got={}".format(op.ref, len(doarr))
+ cmt += ",".join(["+".join(x) for x in doarr])
self.add_info(" {} 0x{:X} {}{}\n".\
- format(opcode, op.arg, msgref, cmt))
+ format(opcode, op.arg, opref, cmt))
def usedby(lst):
for idx, rec in enumerate(lst):
Commit: aa5eafc13a5572ef3e620483df4fb406bb29a51f
https://github.com/scummvm/scummvm-tools/commit/aa5eafc13a5572ef3e620483df4fb406bb29a51f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: code position for dialog opcodes
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index c80c386a9..18339408c 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,10 @@
ЧÑо нового
==========
+2014-05-16 веÑÑÐ¸Ñ 0.2g
+----------------------
+Ðобавлено оÑобÑажение позиÑии дилоговÑÑ
опкодов в обÑем блоке кода
+
2014-05-16 веÑÑÐ¸Ñ 0.2f
----------------------
ÐодÑказка пÑи декодиÑовании опкода 8 в дилогаÑ
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 006563d64..c45a01d17 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2f 2014-05-16"
+VERSION = "v0.2g 2014-05-16"
def hlesc(value):
if value is None:
@@ -1309,17 +1309,17 @@ class App(tkinter.Frame):
cmt = " / obj={}, msg={}".\
format(objref,
self.fmt_hl_msg(op.ref, True))
- if op.opcode == 8:
- cmt = " / select from "
+ elif op.opcode == 2 or op.opcode == 8: # MENU or CIRCLE
+ cmt = " / select "
doarr = []
docurr = []
+ sellen = op.ref % 0x100
skiptobrk = False
for op2 in dlg.ops[oidx + 1:]:
- #cmt += fmt_dlgop(op2.opcode) + " "
if op2.opcode == 0x1: # BREAK
doarr.append(docurr)
skiptobrk = False
- if len(doarr) == op.ref:
+ if len(doarr) == sellen:
break
docurr = []
elif op2.opcode == 0x7 and not skiptobrk: # PLAY
@@ -1328,12 +1328,13 @@ class App(tkinter.Frame):
docurr = ["complex"]
- if len(doarr) < op.ref:
- cmt = " / circle select broken, required={}, "\
- "got={}".format(op.ref, len(doarr))
- cmt += ",".join(["+".join(x) for x in doarr])
- self.add_info(" {} 0x{:X} {}{}\n".\
- format(opcode, op.arg, opref, cmt))
+ if len(doarr) < sellen:
+ cmt = " / {} select broken, required={}, "\
+ "got={}".format(opcode, sellen, len(doarr))
+ else:
+ cmt += ",".join(["+".join(x) for x in doarr])
+ self.add_info(" <i>{:04X}:</i> {} 0x{:X} {}{}\n".\
+ format(op.pos, opcode, op.arg, opref, cmt))
def usedby(lst):
for idx, rec in enumerate(lst):
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 9e5b2b352..137cb24af 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -72,6 +72,7 @@ OPCODES = {
DLGOPS = {
1: ("BREAK", 0),
+ 2: ("MENU", 2),
6: ("RETURN", 0),
7: ("PLAY", 1),
8: ("CIRCLE", 3),
@@ -117,11 +118,12 @@ class DlgObject:
self.ops = None
class DlgOpObject:
- def __init__(self, opcode, arg, ref):
+ def __init__(self, opcode, arg, ref, pos):
self.opcode = opcode
self.arg = arg
self.ref = ref
self.msg = None
+ self.pos = pos
class Engine:
def __init__(self):
@@ -437,10 +439,10 @@ class Engine:
act.dlgs.append(dlg)
temp = f.read(4)
num_ops = struct.unpack_from("<I", temp)[0]
- for i in range(num_ops):
+ for oidx, i in enumerate(range(num_ops)):
temp = f.read(4)
ref, arg, code = struct.unpack_from("<HBB", temp)
- dlgop = DlgOpObject(code, arg, ref)
+ dlgop = DlgOpObject(code, arg, ref, oidx)
if ref < len(self.msgs):
dlgop.msg = self.msgs[ref]
self.dlgops.append(dlgop)
Commit: 5e4bfe56ef1258886e8be568ff42db410e6d05b7
https://github.com/scummvm/scummvm-tools/commit/5e4bfe56ef1258886e8be568ff42db410e6d05b7
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Improved help system
Changed paths:
A engines/petka/help/res_view.txt
engines/petka/help/changes.txt
engines/petka/help/res.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 18339408c..d446c5e63 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,11 @@
ЧÑо нового
==========
+2014-05-16 веÑÑÐ¸Ñ 0.2i
+----------------------
+ÐоÑабоÑана ÑпÑавоÑÐ½Ð°Ñ ÑиÑÑема.
+
+
2014-05-16 веÑÑÐ¸Ñ 0.2g
----------------------
Ðобавлено оÑобÑажение позиÑии дилоговÑÑ
опкодов в обÑем блоке кода
diff --git a/engines/petka/help/res.txt b/engines/petka/help/res.txt
index 9060002f3..0c3af508b 100644
--- a/engines/petka/help/res.txt
+++ b/engines/petka/help/res.txt
@@ -2,4 +2,4 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе ÑеÑÑÑÑÑ (BMP, FLC, AVI и Ñ. д.)
-
+ * <a href="/help/res_view">ÐодÑÐ¾Ð±Ð½Ð°Ñ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑеÑÑÑÑе</a>
diff --git a/engines/petka/help/res_view.txt b/engines/petka/help/res_view.txt
new file mode 100644
index 000000000..b0ff49f59
--- /dev/null
+++ b/engines/petka/help/res_view.txt
@@ -0,0 +1,3 @@
+ÐодÑÐ¾Ð±Ð½Ð°Ñ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑеÑÑÑÑе
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¿Ð¾Ð´ÑобнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑеÑÑÑÑе.
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c45a01d17..72ebd08b3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2g 2014-05-16"
+VERSION = "v0.2i 2014-05-16"
def hlesc(value):
if value is None:
@@ -106,6 +106,7 @@ class App(tkinter.Frame):
self.path_handler = {}
self.curr_main = -1 # 0 - frame, 1 - canvas
self.curr_path = []
+ self.curr_help = ""
self.last_path = [None]
self.last_fn = ""
self.curr_mode = 0
@@ -336,6 +337,8 @@ class App(tkinter.Frame):
else:
path = loc
path = tuple(path)
+ while path[-1:] == ("",):
+ path = path[:-1]
if withhist:
self.hist.append([path])
@@ -343,6 +346,10 @@ class App(tkinter.Frame):
print("DEBUG: Open", path)
self.curr_path = path
+ if len(path) > 0:
+ self.curr_help = path[0]
+ else:
+ self.curr_help = ""
if len(path) > 0:
if path[0] in self.path_handler:
return self.path_handler[path[0]](path)
@@ -603,7 +610,7 @@ class App(tkinter.Frame):
num = self.curr_lb.curselection()[0]
num = int(num)
except:
- pass
+ return None
return num
if self.curr_lb_acts:
@@ -627,10 +634,7 @@ class App(tkinter.Frame):
self.histf = []
def on_help(self):
- if len(self.curr_path) > 0:
- self.open_path(["help", self.curr_path[0]])
- else:
- self.open_path(["help"])
+ self.open_path(["help", self.curr_help])
def on_back(self):
if len(self.hist) > 1:
@@ -821,6 +825,7 @@ class App(tkinter.Frame):
return self.path_default(path)
def path_res_open(self, pref, res_id, mode):
+ self.curr_help = "res_view"
if res_id not in self.sim.res:
self.switch_view(0)
self.clear_info()
Commit: ce018979a3cfe9ba9a5347b28bd3a11edd4a2027
https://github.com/scummvm/scummvm-tools/commit/ce018979a3cfe9ba9a5347b28bd3a11edd4a2027
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: More dialog opcodes information in MENU
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 72ebd08b3..14f139cfe 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1302,44 +1302,68 @@ class App(tkinter.Frame):
for didx, dlg in enumerate(act.dlgs):
self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
+ # scan for used adreses
+ usedadr = []
+ for op in dlg.ops:
+ if op.opcode == 0x3 or \
+ op.opcode == 0x4: # GOTO or MENURET
+ if op.ref not in usedadr:
+ usedadr.append(op.ref)
+ if len(usedadr) > 0:
+ usedadr.append(dlg.op_start)
+ usedmenu = {}
for oidx, op in enumerate(dlg.ops):
cmt = ""
opref = "0x{:X}".format(op.ref)
opcode = fmt_dlgop(op.opcode)
- if op.opcode == 0x7:
- opcode = "PLAY"
- if op.msg:
- opref = self.fmt_hl_msg(op.ref)
- objref = self.fmt_hl_obj(op.msg.obj.idx)
- cmt = " / obj={}, msg={}".\
- format(objref,
- self.fmt_hl_msg(op.ref, True))
- elif op.opcode == 2 or op.opcode == 8: # MENU or CIRCLE
+ if op.pos in usedadr:
+ self.add_info(" <i>label_{:X}:</i>\n".format(
+ op.pos))
+ if op.opcode == 2 or op.opcode == 8: # MENU or CIRCLE
cmt = " / select "
doarr = []
docurr = []
sellen = op.ref % 0x100
skiptobrk = False
- for op2 in dlg.ops[oidx + 1:]:
+ menuactstart = None
+ for oidx2, op2 in enumerate(dlg.ops[oidx + 1:]):
if op2.opcode == 0x1: # BREAK
doarr.append(docurr)
skiptobrk = False
if len(doarr) == sellen:
+ menuactstart = oidx2 + oidx + 2
break
docurr = []
elif op2.opcode == 0x7 and not skiptobrk: # PLAY
docurr.append(self.fmt_hl_msg(op2.ref))
else:
docurr = ["complex"]
-
-
if len(doarr) < sellen:
cmt = " / {} select broken, required={}, "\
"got={}".format(opcode, sellen, len(doarr))
else:
cmt += ",".join(["+".join(x) for x in doarr])
- self.add_info(" <i>{:04X}:</i> {} 0x{:X} {}{}\n".\
- format(op.pos, opcode, op.arg, opref, cmt))
+ if menuactstart is not None:
+ for oidx2, op2 in enumerate(dlg.ops[\
+ menuactstart:menuactstart + sellen]):
+ usedmenu[op2.pos] = (op.pos, oidx2)
+ elif op.opcode == 0x3 or \
+ op.opcode == 0x4: # GOTO or MENURET
+ opref = "<i>label_{:X}</i>".format(op.ref)
+ if op.pos in usedmenu:
+ cmt = " / menu=<i>label_{:X}</i>, case=0x{:}".\
+ format(*usedmenu[op.pos])
+ elif op.opcode == 0x7:
+ opcode = "PLAY"
+ if op.msg:
+ opref = self.fmt_hl_msg(op.ref)
+ objref = self.fmt_hl_obj(op.msg.obj.idx)
+ cmt = " / obj={}, msg={}".\
+ format(objref,
+ self.fmt_hl_msg(op.ref, True))
+
+ self.add_info(" {} 0x{:X} {}{}\n".\
+ format(opcode, op.arg, opref, cmt))
def usedby(lst):
for idx, rec in enumerate(lst):
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 137cb24af..61bad62d9 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -72,10 +72,12 @@ OPCODES = {
DLGOPS = {
1: ("BREAK", 0),
- 2: ("MENU", 2),
+ 2: ("MENU", 1),
+ 3: ("GOTO", 3),
+ 4: ("MENURET", 4),
6: ("RETURN", 0),
- 7: ("PLAY", 1),
- 8: ("CIRCLE", 3),
+ 7: ("PLAY", 5),
+ 8: ("CIRCLE", 6),
}
class ScrObject:
Commit: 55c1dac47c46c985e3776cf6e68e4f28f073c35a
https://github.com/scummvm/scummvm-tools/commit/55c1dac47c46c985e3776cf6e68e4f28f073c35a
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: More dialog opcodes information in MENU
Changed paths:
engines/petka/help/changes.txt
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index d446c5e63..185f60226 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -4,7 +4,7 @@
2014-05-16 веÑÑÐ¸Ñ 0.2i
----------------------
ÐоÑабоÑана ÑпÑавоÑÐ½Ð°Ñ ÑиÑÑема.
-
+ÐобÑабоÑан вÑвод инÑоÑмаÑии о опкодаÑ
в диалогаÑ
2014-05-16 веÑÑÐ¸Ñ 0.2g
----------------------
Commit: 1caee4daec89ab029b11faeeff7b7dd26eb977f9
https://github.com/scummvm/scummvm-tools/commit/1caee4daec89ab029b11faeeff7b7dd26eb977f9
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: More dialog opcodes for BREAK
Changed paths:
engines/petka/help/index.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 265425f56..824919cb6 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -1,6 +1,6 @@
СпÑавка
-ÐеÑÑиÑ: 0.2e 2014-05-16
+ÐеÑÑиÑ: 0.2i 2014-05-16
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 14f139cfe..5be02ec98 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1312,6 +1312,7 @@ class App(tkinter.Frame):
if len(usedadr) > 0:
usedadr.append(dlg.op_start)
usedmenu = {}
+ usedcase = {}
for oidx, op in enumerate(dlg.ops):
cmt = ""
opref = "0x{:X}".format(op.ref)
@@ -1319,7 +1320,15 @@ class App(tkinter.Frame):
if op.pos in usedadr:
self.add_info(" <i>label_{:X}:</i>\n".format(
op.pos))
- if op.opcode == 2 or op.opcode == 8: # MENU or CIRCLE
+ if op.opcode == 0x1: # BREAK
+ if op.pos in usedcase:
+ if len(usedadr) > 0:
+ cmt = " / end select <i>label_{:X}</i>, "\
+ "case=0x{:}".format(*usedcase[op.pos])
+ else:
+ cmt = " / end select case=0x{:}".\
+ format(usedcase[op.pos][1])
+ elif op.opcode == 0x2 or op.opcode == 0x8: # MENU or CIRCLE
cmt = " / select "
doarr = []
docurr = []
@@ -1328,9 +1337,10 @@ class App(tkinter.Frame):
menuactstart = None
for oidx2, op2 in enumerate(dlg.ops[oidx + 1:]):
if op2.opcode == 0x1: # BREAK
+ usedcase[op2.pos] = (op.pos, len(doarr))
doarr.append(docurr)
skiptobrk = False
- if len(doarr) == sellen:
+ if op.opcode == 0x8 and len(doarr) == sellen:
menuactstart = oidx2 + oidx + 2
break
docurr = []
@@ -1351,8 +1361,8 @@ class App(tkinter.Frame):
op.opcode == 0x4: # GOTO or MENURET
opref = "<i>label_{:X}</i>".format(op.ref)
if op.pos in usedmenu:
- cmt = " / menu=<i>label_{:X}</i>, case=0x{:}".\
- format(*usedmenu[op.pos])
+ cmt = " / action menu=<i>label_{:X}</i>, "\
+ "case=0x{:}".format(*usedmenu[op.pos])
elif op.opcode == 0x7:
opcode = "PLAY"
if op.msg:
Commit: 86b69588ea7fd26a05b6f987385e0d112bdd9b81
https://github.com/scummvm/scummvm-tools/commit/86b69588ea7fd26a05b6f987385e0d112bdd9b81
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 5be02ec98..c6f5f535e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1340,8 +1340,9 @@ class App(tkinter.Frame):
usedcase[op2.pos] = (op.pos, len(doarr))
doarr.append(docurr)
skiptobrk = False
- if op.opcode == 0x8 and len(doarr) == sellen:
- menuactstart = oidx2 + oidx + 2
+ if len(doarr) == sellen:
+ if op.opcode == 0x2:
+ menuactstart = oidx2 + oidx + 2
break
docurr = []
elif op2.opcode == 0x7 and not skiptobrk: # PLAY
Commit: 45ef71d4bb5d000dee511a0e6ac04478c7cdfbd4
https://github.com/scummvm/scummvm-tools/commit/45ef71d4bb5d000dee511a0e6ac04478c7cdfbd4
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Decompile highlighting
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 185f60226..6479be033 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -5,6 +5,7 @@
----------------------
ÐоÑабоÑана ÑпÑавоÑÐ½Ð°Ñ ÑиÑÑема.
ÐобÑабоÑан вÑвод инÑоÑмаÑии о опкодаÑ
в диалогаÑ
+ÐоÑабоÑана подÑвеÑка комменÑаÑиев
2014-05-16 веÑÑÐ¸Ñ 0.2g
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c6f5f535e..986161ca9 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -29,14 +29,18 @@ def hlesc(value):
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
def fmt_opcode(opcode):
- return petka.OPCODES.get(opcode, ["OP{:04X}".format(opcode)])[0]
+ return petka.OPCODES.get(opcode, ["<font color=\"red\">OP{:04X}</font>".\
+ format(opcode)])[0]
def fmt_dlgop(opcode):
- return petka.DLGOPS.get(opcode, ["OP{:02X}".format(opcode)])[0]
+ return petka.DLGOPS.get(opcode, ["<font color=\"red\">OP{:02X}</font>".\
+ format(opcode)])[0]
def fmt_hl(loc, desc):
return "<a href=\"{}\">{}</a>".format(loc, desc)
+def fmt_cmt(cmt):
+ return "<font color=\"#606060\">{}</font>".format(cmt)
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
@@ -57,6 +61,7 @@ class HyperlinkManager:
def reset(self):
self.links = {}
+ self.colors = []
def add(self, action):
# add an action to the manager. returns tags to use in
@@ -65,6 +70,14 @@ class HyperlinkManager:
self.links[tag] = action
return "hyper", tag
+ def color(self, color):
+ tag = "color-{}".format(color)
+ if tag not in self.colors:
+ self.colors.append(tag)
+ self.text.tag_config(tag, foreground = color)
+ self.text.tag_raise("hyper")
+ return (tag,)
+
def _enter(self, event):
self.text.config(cursor = "hand2")
@@ -553,7 +566,7 @@ class App(tkinter.Frame):
if ch == ">":
if len(curr_text) > 0:
self.text_view.insert(tkinter.INSERT, curr_text, \
- tuple([x for x in tags for x in x]))
+ tuple(reversed([x for x in tags for x in x])))
if curr_tag[:7] == "a href=":
ref = curr_tag[7:]
if ref[:1] == "\"":
@@ -565,6 +578,13 @@ class App(tkinter.Frame):
return self.open_path(path)
return cb
tags.append(self.text_hl.add(make_cb(ref)))
+ elif curr_tag[:11] == "font color=":
+ ref = curr_tag[11:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.text_hl.color(ref))
elif curr_tag == "b":
tags.append(["bold"])
elif curr_tag == "i":
@@ -579,7 +599,7 @@ class App(tkinter.Frame):
curr_tag += ch
if len(curr_text) > 0:
self.text_view.insert(tkinter.INSERT, curr_text, \
- tuple([x for x in tags for x in x]))
+ tuple(reversed([x for x in tags for x in x])))
def insert_lb_act(self, name, act, key = None):
if key is not None:
@@ -1074,7 +1094,8 @@ class App(tkinter.Frame):
msg += "-1"
else:
msg += "0x{:X}".format(arg)
- self.add_info(msg + " / {}\n".format(hlesc(ref[0].name)))
+ self.add_info(msg + fmt_cmt(" // " + self.fmt_hl_obj(
+ ref[0].idx, True)) + "\n")
resused = []
dlgused = []
@@ -1087,7 +1108,8 @@ class App(tkinter.Frame):
act_ref = "THIS"
else:
if act_ref in self.sim.obj_idx:
- cmt = " / " + self.fmt_hl_obj(act_ref, True)
+ cmt = fmt_cmt(" // " + self.fmt_hl_obj(act_ref,
+ True))
act_ref = self.fmt_hl_obj(act_ref)
else:
act_ref = "0x{:X}".format(act_ref)
@@ -1101,7 +1123,8 @@ class App(tkinter.Frame):
self.add_info("THIS")
else:
self.add_info(self.fmt_hl_obj_scene(op[0]))
- cmt = " / " + self.fmt_hl_obj_scene(op[0], True)
+ cmt = fmt_cmt(" // " + self.fmt_hl_obj_scene(op[0],
+ True))
msg = ""
if op[2] != 0xffff:
if op[2] not in resused and op[2] in self.sim.res:
@@ -1296,9 +1319,10 @@ class App(tkinter.Frame):
self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.acts)))
for idx, act in enumerate(grp.acts):
self.add_info(" {}) <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: "\
- "{} / {}\n".format(idx, fmt_opcode(act.opcode),
+ "{}{}\n".format(idx, fmt_opcode(act.opcode),
self.fmt_hl_obj(act.ref), act.arg1, act.arg2, \
- len(act.dlgs), self.fmt_hl_obj(act.ref, True)))
+ len(act.dlgs), fmt_cmt(" // " +
+ self.fmt_hl_obj(act.ref, True))))
for didx, dlg in enumerate(act.dlgs):
self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
@@ -1323,11 +1347,13 @@ class App(tkinter.Frame):
if op.opcode == 0x1: # BREAK
if op.pos in usedcase:
if len(usedadr) > 0:
- cmt = " / end select <i>label_{:X}</i>, "\
- "case=0x{:}".format(*usedcase[op.pos])
+ cmt = fmt_cmt(" // end select <i>"\
+ "label_{:X}</i>, case=0x{:}"\
+ "".format(*usedcase[op.pos]))
else:
- cmt = " / end select case=0x{:}".\
- format(usedcase[op.pos][1])
+ cmt = fmt_cmt(" // end "\
+ "select case=0x{:}".\
+ format(usedcase[op.pos][1]))
elif op.opcode == 0x2 or op.opcode == 0x8: # MENU or CIRCLE
cmt = " / select "
doarr = []
@@ -1350,10 +1376,12 @@ class App(tkinter.Frame):
else:
docurr = ["complex"]
if len(doarr) < sellen:
- cmt = " / {} select broken, required={}, "\
- "got={}".format(opcode, sellen, len(doarr))
+ cmt = fmt_cmt(" // {} select broken, "\
+ "required={}, got={}".\
+ format(opcode, sellen, len(doarr)))
else:
cmt += ",".join(["+".join(x) for x in doarr])
+ cmt = fmt_cmt(cmt)
if menuactstart is not None:
for oidx2, op2 in enumerate(dlg.ops[\
menuactstart:menuactstart + sellen]):
@@ -1362,19 +1390,25 @@ class App(tkinter.Frame):
op.opcode == 0x4: # GOTO or MENURET
opref = "<i>label_{:X}</i>".format(op.ref)
if op.pos in usedmenu:
- cmt = " / action menu=<i>label_{:X}</i>, "\
- "case=0x{:}".format(*usedmenu[op.pos])
+ cmt = fmt_cmt(" // action menu=<i>"\
+ "label_{:X}</i>, case=0x{:}".\
+ format(*usedmenu[op.pos]))
elif op.opcode == 0x7:
opcode = "PLAY"
if op.msg:
opref = self.fmt_hl_msg(op.ref)
objref = self.fmt_hl_obj(op.msg.obj.idx)
- cmt = " / obj={}, msg={}".\
+ cmt = fmt_cmt(" // obj={}, msg={}".\
format(objref,
- self.fmt_hl_msg(op.ref, True))
-
- self.add_info(" {} 0x{:X} {}{}\n".\
- format(opcode, op.arg, opref, cmt))
+ self.fmt_hl_msg(op.ref, True)))
+
+ oparg = " 0x{:X} ".format(op.arg)
+ if (op.opcode == 0x1 or op.opcode == 0x6) and \
+ op.arg == 0 and op.ref == 0:
+ oparg = ""
+ opref = ""
+ self.add_info(" {}{}{}{}\n".\
+ format(opcode, oparg, opref, cmt))
def usedby(lst):
for idx, rec in enumerate(lst):
Commit: adf0fe0f22a40f79cd87da671d8a55b8dc007658
https://github.com/scummvm/scummvm-tools/commit/adf0fe0f22a40f79cd87da671d8a55b8dc007658
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Display cast colors
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 986161ca9..59ca956f5 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -40,7 +40,7 @@ def fmt_hl(loc, desc):
return "<a href=\"{}\">{}</a>".format(loc, desc)
def fmt_cmt(cmt):
- return "<font color=\"#606060\">{}</font>".format(cmt)
+ return "<font color=\"#4d4d4d\">{}</font>".format(cmt)
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
@@ -62,6 +62,7 @@ class HyperlinkManager:
def reset(self):
self.links = {}
self.colors = []
+ self.bgs = []
def add(self, action):
# add an action to the manager. returns tags to use in
@@ -78,6 +79,14 @@ class HyperlinkManager:
self.text.tag_raise("hyper")
return (tag,)
+ def bg(self, color):
+ tag = "bg-{}".format(color)
+ if tag not in self.bgs:
+ self.bgs.append(tag)
+ self.text.tag_config(tag, background = color)
+ self.text.tag_raise("hyper")
+ return (tag,)
+
def _enter(self, event):
self.text.config(cursor = "hand2")
@@ -585,6 +594,13 @@ class App(tkinter.Frame):
if ref[-1:] == "\"":
ref = ref[:-1]
tags.append(self.text_hl.color(ref))
+ elif curr_tag[:8] == "font bg=":
+ ref = curr_tag[8:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.text_hl.bg(ref))
elif curr_tag == "b":
tags.append(["bold"])
elif curr_tag == "i":
@@ -705,6 +721,12 @@ class App(tkinter.Frame):
return "/invntr/{}".format(inv_id)
return "/no_invntr/{}".format(key)
+ def find_path_cast(self, key):
+ for cast_id, name in enumerate(self.sim.castsord):
+ if name == key:
+ return "/casts/{}".format(cast_id)
+ return "/no_casts/{}".format(key)
+
def fmt_hl_msg(self, msg_id, full = False):
msg_idx = {}
if msg_id < len(self.sim.msgs):
@@ -1066,6 +1088,19 @@ class App(tkinter.Frame):
self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
"Invntr") + ": {}\n".format(
hlesc(self.sim.invntr[rec.name])))
+ if rec.cast:
+ bg = 0
+ r = rec.cast[0]
+ g = rec.cast[1]
+ b = rec.cast[2]
+ if (r + g * 2 + b) // 3 < 160:
+ bg = 255
+ self.add_info(" " + fmt_hl(self.find_path_cast(rec.name),
+ "Cast") + ": <font bg=\"#{bg:02x}{bg:02x}{bg:02x}\">"
+ "<font color=\"#{r:02x}{g:02x}{b:02x}\">"\
+ "<b> #{r:02x}{g:02x}{b:02x} </b></font></font>\n".\
+ format(bg = bg, r = r, g = g, b = b))
+
# references / backreferences
if isobj:
# search where object used
@@ -1224,7 +1259,19 @@ class App(tkinter.Frame):
return self.path_default([])
def info(name):
self.add_info("<b>Cast</b>: {}\n".format(hlesc(name)))
- self.add_info("Value: {}\n\n".format(self.sim.casts[name]))
+ self.add_info("Value: {}\n".format(self.sim.casts[name]))
+ try:
+ val = self.sim.casts[name].split(" ")
+ val = [x for x in val if x]
+ r = int(val[0])
+ g = int(val[1])
+ b = int(val[2])
+ except:
+ r, g, b = 0, 0, 0
+ hl = "<font bg=\"#{:02x}{:02x}{:02x}\"> </font>".\
+ format(r, g, b)
+ self.add_info(" " + hl + "\n")
+ self.add_info(" " + hl + "\n\n")
# search for objects
self.add_info("<b>Applied for</b>:\n")
for idx, obj in enumerate(self.sim.objects):
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 61bad62d9..3dd31ef1f 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -85,6 +85,7 @@ class ScrObject:
self.idx = idx
self.name = name
self.acts = None
+ self.cast = None
class MsgObject:
def __init__(self, idx, wav, arg1, arg2, arg3):
@@ -366,10 +367,20 @@ class Engine:
self.casts = ini["all"]
self.castsord = ini["__order__"]["all"]
f.close()
+
# bind casts to objects
- for cast in self.castsord:
- #print(cast)
- pass
+ for obj in self.objects:
+ if obj.name in self.casts:
+ # parse color
+ try:
+ val = self.casts[obj.name].split(" ")
+ val = [x for x in val if x]
+ r = int(val[0])
+ g = int(val[1])
+ b = int(val[2])
+ except:
+ r, g, b = 255, 255, 255
+ obj.cast = (r, g, b)
def load_dialogs(self):
self.msgs = []
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index 142597b92..b14ad3eea 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -63,7 +63,7 @@ class FileManager:
self.strtable[fname] = (len(self.strfd),) + index_table[idx]
else:
if len(fname) > 0:
- raise EngineError("Extra file record \"{}\" in \"{}\"".\
+ print("DEBUG:Extra file record \"{}\" in \"{}\"".\
format(fname, name))
# add file descriptor
self.strfd.append((f, name, tag))
Commit: 83c51d77a6d99917b581c78f1259d0432f4d674f
https://github.com/scummvm/scummvm-tools/commit/83c51d77a6d99917b581c78f1259d0432f4d674f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Show where object used in TALK opcode
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 6479be033..3918a1c3e 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,10 @@
ЧÑо нового
==========
+2014-05-16 веÑÑÐ¸Ñ 0.2j
+----------------------
+ÐÑобÑажаемÑе ÑвеÑа изобÑажаÑÑÑÑ Ð½ÑжнÑм ÑвеÑом
+
2014-05-16 веÑÑÐ¸Ñ 0.2i
----------------------
ÐоÑабоÑана ÑпÑавоÑÐ½Ð°Ñ ÑиÑÑема.
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 59ca956f5..58bc1b31a 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2i 2014-05-16"
+VERSION = "v0.2j 2014-05-16"
def hlesc(value):
if value is None:
@@ -1189,13 +1189,35 @@ class App(tkinter.Frame):
format(len(dlgused)))
for grp_id in dlgused:
self.add_info(" " + self.fmt_hl_dlg(grp_id, True)+ "\n")
-
+
+ # messages used by this object
if isobj:
- self.add_info("\n<b>Messages</b>:\n")
+ wasmsg = False
for msg in self.sim.msgs:
if msg.obj.idx != rec.idx: continue
+ if not wasmsg:
+ self.add_info("\n<b>Messages</b>:\n")
+ wasmsg = True
self.add_info(" " + self.fmt_hl_msg(msg.idx, True) + "\n")
+ # objects tan use this objects in TALK opcode
+ wasmsg = False
+ for obj2 in self.sim.objects:
+ for idx, (act_op, act_status, act_ref, ops) in \
+ enumerate(obj2.acts):
+ for oidx, op in enumerate(ops):
+ if op[1] == 0xA and op[0] == rec.idx: # TALK
+ if not wasmsg:
+ self.add_info("\n<b>Used in TALK</b>:\n")
+ wasmsg = True
+ self.add_info(" " + self.fmt_hl_obj(obj2.idx) +
+ " on " + fmt_opcode(act_op) +
+ " #{}".format(idx) + fmt_cmt(" // " +
+ self.fmt_hl_obj(obj2.idx, True)) + "\n")
+ #print(op)
+ #print()
+
+
def path_std_items(self, path, level, guiname, guiitem, lst, lst_idx,
lbmode, cb):
self.switch_view(0)
@@ -1402,7 +1424,7 @@ class App(tkinter.Frame):
"select case=0x{:}".\
format(usedcase[op.pos][1]))
elif op.opcode == 0x2 or op.opcode == 0x8: # MENU or CIRCLE
- cmt = " / select "
+ cmt = " // select "
doarr = []
docurr = []
sellen = op.ref % 0x100
Commit: 611c55928c08aa2ef4a85bcd467cbe9959fdaf50
https://github.com/scummvm/scummvm-tools/commit/611c55928c08aa2ef4a85bcd467cbe9959fdaf50
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Show where object used in TALK opcode
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 3918a1c3e..a8a7f40f2 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,10 @@
ЧÑо нового
==========
+2014-05-16 веÑÑÐ¸Ñ 0.2k
+----------------------
+ÐÑобÑÐ°Ð¶Ð°ÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð³Ð´Ðµ иÑполÑзÑеÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ð² опкоде TALK
+
2014-05-16 веÑÑÐ¸Ñ 0.2j
----------------------
ÐÑобÑажаемÑе ÑвеÑа изобÑажаÑÑÑÑ Ð½ÑжнÑм ÑвеÑом
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 58bc1b31a..c163fca27 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -21,7 +21,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2j 2014-05-16"
+VERSION = "v0.2k 2014-05-16"
def hlesc(value):
if value is None:
Commit: 32232789613ee13cbb095fcf59e9be79e7548aae
https://github.com/scummvm/scummvm-tools/commit/32232789613ee13cbb095fcf59e9be79e7548aae
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Show where object used in all opcodes
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index a8a7f40f2..ae18f81a1 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -3,7 +3,8 @@
2014-05-16 веÑÑÐ¸Ñ 0.2k
----------------------
-ÐÑобÑÐ°Ð¶Ð°ÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð³Ð´Ðµ иÑполÑзÑеÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ð² опкоде TALK
+ÐÑобÑÐ°Ð¶Ð°ÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð³Ð´Ðµ иÑполÑзÑеÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ñ Ñказанием опкодов и
+ обÑабоÑÑиков
2014-05-16 веÑÑÐ¸Ñ 0.2j
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c163fca27..bc3151277 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1200,23 +1200,30 @@ class App(tkinter.Frame):
wasmsg = True
self.add_info(" " + self.fmt_hl_msg(msg.idx, True) + "\n")
+ oplst = {}
# objects tan use this objects in TALK opcode
wasmsg = False
for obj2 in self.sim.objects:
+ if obj2.idx == rec.idx: continue
for idx, (act_op, act_status, act_ref, ops) in \
enumerate(obj2.acts):
for oidx, op in enumerate(ops):
- if op[1] == 0xA and op[0] == rec.idx: # TALK
- if not wasmsg:
- self.add_info("\n<b>Used in TALK</b>:\n")
- wasmsg = True
- self.add_info(" " + self.fmt_hl_obj(obj2.idx) +
- " on " + fmt_opcode(act_op) +
- " #{}".format(idx) + fmt_cmt(" // " +
- self.fmt_hl_obj(obj2.idx, True)) + "\n")
- #print(op)
- #print()
-
+ if op[0] == rec.idx:
+ arr = oplst.get(op[1], [])
+ arr.append((obj2.idx, act_op, idx))
+ oplst[op[1]] = arr
+ break
+
+ klst = list(petka.OPCODES.keys())
+ klst.sort()
+ for k in klst:
+ if k not in oplst: continue
+ self.add_info("\n<b>Used in " + fmt_opcode(k) + "</b>:\n")
+ for oid, htp, hid in oplst[k]:
+ self.add_info(" " + self.fmt_hl_obj(oid) +
+ " on " + fmt_opcode(htp) +
+ " #{}".format(hid) + fmt_cmt(" // " +
+ self.fmt_hl_obj(oid, True)) + "\n")
def path_std_items(self, path, level, guiname, guiitem, lst, lst_idx,
lbmode, cb):
Commit: c32cf831b5519c8a32b629ebe0215c8106033243
https://github.com/scummvm/scummvm-tools/commit/c32cf831b5519c8a32b629ebe0215c8106033243
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: search opcodes refs in scenes too
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index bc3151277..2ef010c9d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1203,7 +1203,7 @@ class App(tkinter.Frame):
oplst = {}
# objects tan use this objects in TALK opcode
wasmsg = False
- for obj2 in self.sim.objects:
+ for obj2 in self.sim.objects + self.sim.scenes:
if obj2.idx == rec.idx: continue
for idx, (act_op, act_status, act_ref, ops) in \
enumerate(obj2.acts):
@@ -1220,10 +1220,10 @@ class App(tkinter.Frame):
if k not in oplst: continue
self.add_info("\n<b>Used in " + fmt_opcode(k) + "</b>:\n")
for oid, htp, hid in oplst[k]:
- self.add_info(" " + self.fmt_hl_obj(oid) +
+ self.add_info(" " + self.fmt_hl_obj_scene(oid) +
" on " + fmt_opcode(htp) +
" #{}".format(hid) + fmt_cmt(" // " +
- self.fmt_hl_obj(oid, True)) + "\n")
+ self.fmt_hl_obj_scene(oid, True)) + "\n")
def path_std_items(self, path, level, guiname, guiitem, lst, lst_idx,
lbmode, cb):
Commit: 5c26722f94d2e9f3cac5e4750bc50dccf7e2ec44
https://github.com/scummvm/scummvm-tools/commit/5c26722f94d2e9f3cac5e4750bc50dccf7e2ec44
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: test export .pot files
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 2ef010c9d..05e7dc253 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1514,12 +1514,40 @@ class App(tkinter.Frame):
if path[1] == "image":
self.switch_view(1)
self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
- else:
+ elif path[1] == "info":
self.switch_view(0)
self.clear_info()
self.add_info("Information panel for {}\n".format(path))
for i in range(100):
self.add_info(" Item {}\n".format(i))
+ elif path[1] == "translate":
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Save translation template\n ")
+ def savepot():
+ f = open("save_{}.pot".format(self.sim.curr_part), "wb")
+ try:
+ def saveitem(msgid, msgstr, msgctx):
+ if msgctx:
+ f.write("msgctx \"{}\"\n".format(hlesc(msgctx)).\
+ encode("UTF-8"))
+ f.write("msgid \"{}\"\n".format(hlesc(msgid)).\
+ encode("UTF-8"))
+ f.write("msgstr \"{}\"\n\n".format(hlesc(msgstr)).\
+ encode("UTF-8"))
+ # objects
+ for obj in self.sim.objects:
+ saveitem(obj.name, obj.name, "obj_{}".format(obj.idx))
+ for scn in self.sim.scenes:
+ saveitem(scn.name, scn.name, "scene_{}".format(scn.idx))
+
+ finally:
+ f.close()
+
+ btn = ttk.Button(self.text_view, text = "Save .POT", \
+ command = savepot)
+ self.text_view.window_create(tkinter.INSERT, window = btn)
+
def path_about(self, path):
self.switch_view(0)
Commit: 91b4caf9ce1dca7830a8699c9687001e1e63dfc2
https://github.com/scummvm/scummvm-tools/commit/91b4caf9ce1dca7830a8699c9687001e1e63dfc2
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Translation tools
Changed paths:
engines/petka/help/changes.txt
engines/petka/help/cmdline.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index ae18f81a1..b67406c46 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,13 @@
ЧÑо нового
==========
+2014-05-20 веÑÑÐ¸Ñ 0.2l
+----------------------
+Ðобавлена ÑÑнкÑÐ¸Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñаблона Ð´Ð»Ñ Ð¿ÐµÑевода (.pot)
+Ðобавлена загÑÑзка пеÑевода (.po)
+ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ñ Ð²Ñе ÑÐ°Ð·Ð´ÐµÐ»Ñ Ð³Ð´Ðµ Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑобÑажаÑÑÑÑ Ð¿ÐµÑеведÑнна инÑоÑмаÑиÑ
+Ðзменен поÑÑдок загÑÑÐ·ÐºÑ Ð´Ð°Ð½Ð½ÑÑ
из командной ÑÑÑоки
+
2014-05-16 веÑÑÐ¸Ñ 0.2k
----------------------
ÐÑобÑÐ°Ð¶Ð°ÐµÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð³Ð´Ðµ иÑполÑзÑеÑÑÑ Ð¾Ð±ÑÐµÐºÑ Ñ Ñказанием опкодов и
diff --git a/engines/petka/help/cmdline.txt b/engines/petka/help/cmdline.txt
index a0cae8862..9e578f0dd 100644
--- a/engines/petka/help/cmdline.txt
+++ b/engines/petka/help/cmdline.txt
@@ -2,7 +2,7 @@
СинÑакÑÐ¸Ñ Ð²Ñзова пÑогÑÐ°Ð¼Ð¼Ñ Ð¸Ð· коммандной ÑÑÑоки
- p12simtran [пÑÑÑ Ðº даннÑм [оÑкÑÑваемÑе ÑазделÑ]
+ p12explore [-d пÑÑÑ Ðº даннÑм]|[-t пÑÑÑ Ðº пеÑеводÑ]|[оÑкÑÑваемÑй Ñаздел]
ÐÑÑÑ Ðº даннÑм - пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð¸Ð»Ð¸ каÑÐ°Ð»Ð¾Ð³Ñ Ð³Ð´Ðµ наÑ
одиÑÑÑ Ñайл Ñ Ð´Ð°Ð½Ð½Ñми.
@@ -17,5 +17,13 @@
* /msgs - ÑообÑениÑ
* /dlgs - гÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²
-
+Так как поÑле оÑкÑÑÑÐ¸Ñ Ð´Ð°Ð½Ð½ÑÑ
даннÑе о пеÑеводе ÑдалÑÑÑÑÑ Ñо ÑекомендÑеÑÑÑ
+ ÑледÑÑÑий поÑÑдок загÑÑзки:
+
+ p12explore -d . /parts/1.0 -t translate/part_1-en_EN.po /msgs/2492
+
+ * ÐагÑÑаÑÑÑÑ Ð´Ð°Ð½Ð½Ñе из ÑекÑÑего каÑалога
+ * ÐÑкÑÑваеÑÑÑ ÑаÑÑÑ 1, глава 0
+ * ÐагÑÑжаеÑÑÑ Ð¿ÐµÑевод из Ñайла
+ * ÐÑкÑÑваеÑÑÑ ÑообÑение â2492
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 824919cb6..28af58a6e 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -1,6 +1,6 @@
СпÑавка
-ÐеÑÑиÑ: 0.2i 2014-05-16
+ÐеÑÑиÑ: 0.2l 2014-05-20
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
@@ -19,6 +19,7 @@
ÐÑоÑÐ°Ñ Ð¸Ð½ÑоÑмаÑиÑ
+ * <a href="/help/translate">ÐÐ»Ñ Ð¿ÐµÑеводÑика</a>
* <a href="/help/cmdline">ÐÑгÑменÑÑ ÐºÐ¾Ð¼Ð¼Ð°Ð½Ð´Ð½Ð¾Ð¹ ÑÑÑоки</a>
* <a href="/help/support">ÐнÑоÑмаÑÐ¸Ñ Ð´Ð»Ñ Ð¿Ð¾Ð´ÐµÑжки</a>
* <a href="/help/info">СпÑавоÑники</a>
diff --git a/engines/petka/help/list b/engines/petka/help/list
index a43ec9fd3..984865268 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -10,6 +10,7 @@ invntr
casts
msgs
dlgs
+translate
cmdline
support
info
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 05e7dc253..ddb8103e9 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -9,6 +9,7 @@ from tkinter import ttk, font, filedialog, messagebox
from idlelib.WidgetRedirector import WidgetRedirector
import traceback
+# Image processing
try:
from PIL import Image
except ImportError:
@@ -18,16 +19,25 @@ try:
except ImportError:
ImageTk = None
+# Translations
+try:
+ import polib
+except ImportError:
+ polib = None
+
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2k 2014-05-16"
+VERSION = "v0.2l 2014-05-20"
def hlesc(value):
if value is None:
return "None"
return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
+def cesc(value):
+ return value.replace("\\", "\\\\").replace("\"", "\\\"")
+
def fmt_opcode(opcode):
return petka.OPCODES.get(opcode, ["<font color=\"red\">OP{:04X}</font>".\
format(opcode)])[0]
@@ -142,6 +152,9 @@ class App(tkinter.Frame):
self.need_update = False
self.canv_view_fact = 1
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
+ # translation
+ self.tran = None
+ # add on_load handler
self.after_idle(self.on_first_display)
def create_widgets(self):
@@ -230,6 +243,8 @@ class App(tkinter.Frame):
if cmd == "load":
self.open_data_from(arg)
repath = "/"
+ elif cmd == "tran":
+ self.open_tran_from(arg)
elif cmd == "open":
self.open_path(arg)
repath = ""
@@ -301,6 +316,17 @@ class App(tkinter.Frame):
command = lambda: self.open_path("/hist"),
label = "History")
+ if polib:
+ menutran = tkinter.Menu(self.menubar, tearoff = 0)
+ self.menubar.add_cascade(menu = menutran,
+ label = "Translation")
+ menutran.add_command(
+ command = self.on_tran_save,
+ label = "Save template (.pot)")
+ menutran.add_command(
+ command = self.on_tran_load,
+ label = "Load translation (.po)")
+
self.menuhelp = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuhelp,
label = "Help")
@@ -686,28 +712,38 @@ class App(tkinter.Frame):
self.hist.append(np)
self.open_path(np[0], False)
- def fmt_hl_rec(self, lst_idx, pref, rec_id, full = False):
+ def _t(self, value, tp):
+ if not self.tran: return value
+ if tp in self.tran:
+ if value in self.tran[tp]:
+ return self.tran[tp][value]
+ if value in self.tran["_"]:
+ return self.tran["_"][value]
+ return value
+
+ def fmt_hl_rec(self, lst_idx, pref, rec_id, full, tt):
if rec_id in lst_idx:
fmt = fmt_hl("/{}/{}".format(pref, rec_id), str(rec_id))
if full:
try:
fmt += " (0x{:X}) - {}".format(rec_id,
- hlesc(lst_idx[rec_id].name))
+ hlesc(self._t(lst_idx[rec_id].name, tt)))
except:
fmt += " (0x{:X})".format(rec_id)
return fmt
return "{} (0x{:X})".format(rec_id, rec_id)
def fmt_hl_obj(self, obj_id, full = False):
- return self.fmt_hl_rec(self.sim.obj_idx, "objs", obj_id, full)
+ return self.fmt_hl_rec(self.sim.obj_idx, "objs", obj_id, full, "obj")
def fmt_hl_scene(self, scn_id, full = False):
- return self.fmt_hl_rec(self.sim.scn_idx, "scenes", scn_id, full)
+ return self.fmt_hl_rec(self.sim.scn_idx, "scenes", scn_id, full, "scn")
def fmt_hl_obj_scene(self, rec_id, full = False):
if rec_id in self.sim.obj_idx:
- return self.fmt_hl_rec(self.sim.obj_idx, "objs", rec_id, full)
- return self.fmt_hl_rec(self.sim.scn_idx, "scenes", rec_id, full)
+ return self.fmt_hl_rec(self.sim.obj_idx, "objs", rec_id,
+ full, "obj")
+ return self.fmt_hl_rec(self.sim.scn_idx, "scenes", rec_id, full, "scn")
def find_path_name(self, key):
for name_id, name in enumerate(self.sim.namesord):
@@ -731,10 +767,10 @@ class App(tkinter.Frame):
msg_idx = {}
if msg_id < len(self.sim.msgs):
msg_idx[msg_id] = self.sim.msgs[msg_id]
- return self.fmt_hl_rec(msg_idx, "msgs", msg_id, full)
+ return self.fmt_hl_rec(msg_idx, "msgs", msg_id, full, "msg")
def fmt_hl_dlg(self, grp_id, full = False):
- return self.fmt_hl_rec(self.sim.dlg_idx, "dlgs", grp_id, full)
+ return self.fmt_hl_rec(self.sim.dlg_idx, "dlgs", grp_id, full, "dlg")
def path_info_outline(self):
if self.sim is None:
@@ -1054,7 +1090,8 @@ class App(tkinter.Frame):
else:
self.update_gui("Scenes ({})".format(len(lst)))
for rec in lst:
- self.insert_lb_act("{} - {}".format(rec.idx, rec.name), \
+ self.insert_lb_act("{} - {}".format(rec.idx,
+ self._t(rec.name, "obj" if isobj else "scn")),\
[self.curr_path[0], rec.idx], rec.idx)
# change
rec = None
@@ -1078,16 +1115,28 @@ class App(tkinter.Frame):
# record info
self.add_info(("<b>Object</b>" if isobj \
else "<b>Scene</b>") + ":\n")
- self.add_info(" Index: {} (0x{:X})\n Name: {}\n".\
- format(rec.idx, rec.idx, hlesc(rec.name)))
- if rec.name in self.sim.names:
- self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
- "Alias") + ": {}\n".format(
- hlesc(self.sim.names[rec.name])))
- if rec.name in self.sim.invntr:
- self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
- "Invntr") + ": {}\n".format(
- hlesc(self.sim.invntr[rec.name])))
+ self.add_info(" Index: {} (0x{:X})\n".format(rec.idx, rec.idx))
+ self.add_info(" Name: {}\n".format(hlesc(rec.name)))
+ if self.tran:
+ self.add_info(" Name(t): {}\n".\
+ format(hlesc(self._t(rec.name, "obj" if isobj else "scn"))))
+ if rec.name in self.sim.names:
+ self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ "Alias") + "(t): {}\n".format(
+ hlesc(self._t(self.sim.names[rec.name], "obj"))))
+ if rec.name in self.sim.invntr:
+ self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
+ "Invntr") + "(t): {}\n".format(
+ hlesc(self._t(self.sim.invntr[rec.name], "inv"))))
+ else:
+ if rec.name in self.sim.names:
+ self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ "Alias") + ": {}\n".format(
+ hlesc(self.sim.names[rec.name])))
+ if rec.name in self.sim.invntr:
+ self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
+ "Invntr") + ": {}\n".format(
+ hlesc(self.sim.invntr[rec.name])))
if rec.cast:
bg = 0
r = rec.cast[0]
@@ -1096,7 +1145,7 @@ class App(tkinter.Frame):
if (r + g * 2 + b) // 3 < 160:
bg = 255
self.add_info(" " + fmt_hl(self.find_path_cast(rec.name),
- "Cast") + ": <font bg=\"#{bg:02x}{bg:02x}{bg:02x}\">"
+ "Cast") + ": <font bg=\"#{bg:02x}{bg:02x}{bg:02x}\">"
"<font color=\"#{r:02x}{g:02x}{b:02x}\">"\
"<b> #{r:02x}{g:02x}{b:02x} </b></font></font>\n".\
format(bg = bg, r = r, g = g, b = b))
@@ -1225,15 +1274,16 @@ class App(tkinter.Frame):
" #{}".format(hid) + fmt_cmt(" // " +
self.fmt_hl_obj_scene(oid, True)) + "\n")
- def path_std_items(self, path, level, guiname, guiitem, lst, lst_idx,
+ def path_std_items(self, path, level, guiname, guiitem, tt, lst, lst_idx,
lbmode, cb):
self.switch_view(0)
if self.last_path[:level] != path[:level]:
self.update_gui("{} ({})".format(guiname, len(lst)))
for idx, name in enumerate(lst_idx):
- lb = name
+ lb = self._t(name, tt)
if lbmode == 1:
- lb = "{} - {}".format(name, lst[name])
+ print(name, )
+ lb = "{} - {}".format(name, self._t(lst[name], tt))
self.insert_lb_act(lb, path[:level] + tuple([idx]), idx)
# change
name = None
@@ -1258,29 +1308,41 @@ class App(tkinter.Frame):
if self.sim is None:
return self.path_default([])
def info(name):
- self.add_info("<b>Alias</b>: {}\n".format(hlesc(name)))
- self.add_info("Value: {}\n\n".format(self.sim.names[name]))
+ self.add_info("<b>Alias</b>: {}\n".format(hlesc(name)))
+ if self.tran:
+ self.add_info("<b>Alias</b>(t): {}\n".\
+ format(hlesc(self._t(name, "obj"))))
+ self.add_info("Value: {}\n".format(self.sim.names[name]))
+ if self.tran:
+ self.add_info("Value(t): {}\n".\
+ format(hlesc(self._t(self.sim.names[name], "name"))))
# search for objects
- self.add_info("<b>Applied for</b>:\n")
+ self.add_info("\n<b>Applied for</b>:\n")
for obj in self.sim.objects:
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
- return self.path_std_items(path, 1, "Names", "name", self.sim.names,
- self.sim.namesord, 0, info)
+ return self.path_std_items(path, 1, "Names", "name", "obj",
+ self.sim.names, self.sim.namesord, 0, info)
def path_invntr(self, path):
if self.sim is None:
return self.path_default([])
def info(name):
- self.add_info("<b>Invntr</b>: {}\n".format(hlesc(name)))
- self.add_info("{}\n\n".format(self.sim.invntr[name]))
+ self.add_info("<b>Invntr</b>: {}\n".format(hlesc(name)))
+ if self.tran:
+ self.add_info("<b>Invntr</b>(t): {}\n".\
+ format(hlesc(self._t(name, "obj"))))
+ self.add_info("{}\n\n".format(hlesc(self.sim.invntr[name])))
+ if self.tran:
+ self.add_info("<i>Translated</i>\n{}\n\n".\
+ format(hlesc(self._t(self.sim.invntr[name], "inv"))))
# search for objects
self.add_info("<b>Applied for</b>:\n")
for obj in self.sim.objects:
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
- return self.path_std_items(path, 1, "Invntr", "invntr", self.sim.invntr,
- self.sim.invntrord, 0, info)
+ return self.path_std_items(path, 1, "Invntr", "invntr", "obj",
+ self.sim.invntr, self.sim.invntrord, 0, info)
def path_casts(self, path):
@@ -1306,8 +1368,8 @@ class App(tkinter.Frame):
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
- return self.path_std_items(path, 1, "Cast", "cast", self.sim.casts,
- self.sim.castsord, 0, info)
+ return self.path_std_items(path, 1, "Cast", "cast", "obj",
+ self.sim.casts, self.sim.castsord, 0, info)
def path_msgs(self, path):
if self.sim is None:
@@ -1348,7 +1410,9 @@ class App(tkinter.Frame):
self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
self.add_info("\n{}\n".format(hlesc(msg.name)))
-
+ if self.tran:
+ self.add_info("\n<i>Translated:</i>\n{}\n".\
+ format(hlesc(self._t(msg.name, "msg"))))
self.add_info("\n<b>Used by dialog groups</b>:\n")
for grp in self.sim.dlgs:
for act in grp.acts:
@@ -1503,7 +1567,6 @@ class App(tkinter.Frame):
usedby(self.sim.objects)
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
-
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
@@ -1520,34 +1583,6 @@ class App(tkinter.Frame):
self.add_info("Information panel for {}\n".format(path))
for i in range(100):
self.add_info(" Item {}\n".format(i))
- elif path[1] == "translate":
- self.switch_view(0)
- self.clear_info()
- self.add_info("Save translation template\n ")
- def savepot():
- f = open("save_{}.pot".format(self.sim.curr_part), "wb")
- try:
- def saveitem(msgid, msgstr, msgctx):
- if msgctx:
- f.write("msgctx \"{}\"\n".format(hlesc(msgctx)).\
- encode("UTF-8"))
- f.write("msgid \"{}\"\n".format(hlesc(msgid)).\
- encode("UTF-8"))
- f.write("msgstr \"{}\"\n\n".format(hlesc(msgstr)).\
- encode("UTF-8"))
- # objects
- for obj in self.sim.objects:
- saveitem(obj.name, obj.name, "obj_{}".format(obj.idx))
- for scn in self.sim.scenes:
- saveitem(scn.name, scn.name, "scene_{}".format(scn.idx))
-
- finally:
- f.close()
-
- btn = ttk.Button(self.text_view, text = "Save .POT", \
- command = savepot)
- self.text_view.window_create(tkinter.INSERT, window = btn)
-
def path_about(self, path):
self.switch_view(0)
@@ -1572,10 +1607,20 @@ class App(tkinter.Frame):
hlesc(self.app_path)))
self.add_info("<b>Game folder</b>: {}\n".format(
hlesc(self.last_fn)))
+ self.add_info("<b>Translation</b>: ")
+ if not polib:
+ self.add_info("<i><u>polib</u> not found</i>\n")
+ else:
+ if not self.tran:
+ self.add_info("<i>no tranlation file</i>\n")
+ else:
+ self.add_info(hlesc(self.tran_fn) + "\n")
+
+ self.add_info("<b>Engine</b>: ")
if self.sim is None:
- self.add_info("<i>Engine not initialized</i>\n")
+ self.add_info("<i>not initialized</i>\n")
else:
- self.add_info("<i>Engine works</i>\n\n")
+ self.add_info("<i>works</i>\n\n")
self.add_info(" <b>Path</b>: {}\n".format(
hlesc(self.sim.curr_path)))
self.add_info(" <b>Speech</b>: {}\n".format(
@@ -1689,10 +1734,10 @@ class App(tkinter.Frame):
self.open_path("")
self.clear_hist()
-
def open_data_from(self, folder):
self.last_fn = folder
try:
+ self.tran = None
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
self.sim.open_part(0, 0)
@@ -1707,13 +1752,92 @@ class App(tkinter.Frame):
format(hlesc(folder), hlesc(traceback.format_exc())))
self.clear_hist()
+ def on_tran_save(self):
+ # save dialog
+ fn = filedialog.asksaveasfilename(parent = self,
+ title = "Save translate template (.pot)",
+ filetypes = [('PO Template', ".pot"), ('all files', '.*')],
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return # save canceled
+ # save template
+ try:
+ po = polib.POFile()
+ po.metadata = {
+ 'MIME-Version': '1.0',
+ 'Content-Type': 'text/plain; charset=utf-8',
+ 'Content-Transfer-Encoding': '8bit',
+ }
+ used = []
+ def saveitem(text, cmt = None):
+ if text in used: return
+ used.append(text)
+ entry = polib.POEntry(
+ msgid = text, msgstr = text, comment = cmt)
+ po.append(entry)
+ for rec in self.sim.objects:
+ saveitem(rec.name, "obj_{}".format(rec.idx))
+ for rec in self.sim.scenes:
+ saveitem(rec.name, "scn_{}".format(rec.idx))
+ for idx, name in enumerate(self.sim.namesord):
+ saveitem(self.sim.names[name],
+ "name_{}, {}".format(idx, name))
+ for idx, name in enumerate(self.sim.invntrord):
+ saveitem(self.sim.invntr[name],
+ "inv_{}, {}".format(idx, name))
+ for idx, msg in enumerate(self.sim.msgs):
+ saveitem(msg.name,
+ "msg_{}, {} - {}".format(idx, msg.obj.idx, msg.obj.name))
+ po.save(fn)
+ except:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Error saving \"{}\" \n\n{}".\
+ format(hlesc(fn), hlesc(traceback.format_exc())))
+
+ def on_tran_load(self):
+ ft = [\
+ ('PO files', '.po'),
+ ('all files', '.*')]
+ fn = filedialog.askopenfilename(parent = self,
+ title = "Open translation for current part",
+ filetypes = ft,
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return
+ os.chdir(os.path.dirname(fn))
+ self.open_tran_from(fn)
+
+ def open_tran_from(self, fn):
+ self.tran_fn = fn
+ try:
+ po = polib.pofile(fn)
+ self.tran = {"obj": {}, "scn": {}, "name": {}, "inv": {},
+ "msg": {}, "_": {}}
+ for tr in po.translated_entries():
+ if tr.comment:
+ pref = tr.comment.split("_", 1)
+ if pref[0] in self.tran:
+ self.tran[pref[0]][tr.msgid] = tr.msgstr
+ self.tran["_"][tr.msgid] = tr.msgstr
+ except:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Error opening \"{}\" \n\n{}".\
+ format(hlesc(fn), hlesc(traceback.format_exc())))
+
def main():
root = tkinter.Tk()
app = App(master = root)
- if len(sys.argv) > 1:
- app.start_act.append(["load", sys.argv[1]])
- for arg in sys.argv[2:]:
- app.start_act.append(["open", arg])
+ argv = sys.argv[1:]
+ while len(argv) > 0:
+ if argv[0] == "-d": # open data
+ app.start_act.append(["load", argv[1]])
+ argv = argv[2:]
+ elif argv[0] == "-t": # open translation
+ app.start_act.append(["tran", argv[1]])
+ argv = argv[2:]
+ else:
+ app.start_act.append(["open", argv[0]])
+ argv = argv[1:]
app.mainloop()
Commit: 81d2dbbea5d381bb762bfabd064d270858f1732f
https://github.com/scummvm/scummvm-tools/commit/81d2dbbea5d381bb762bfabd064d270858f1732f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: add help file for translations
Changed paths:
A engines/petka/help/translate.txt
diff --git a/engines/petka/help/translate.txt b/engines/petka/help/translate.txt
new file mode 100644
index 000000000..810fc40fc
--- /dev/null
+++ b/engines/petka/help/translate.txt
@@ -0,0 +1,7 @@
+ÐÐ»Ñ Ð¿ÐµÑеводÑиков
+
+ÐÐ»Ñ Ð¿ÐµÑеводÑиков пÑогÑамма можеÑ:
+
+ * СоздаÑÑ Ñаблон Ð´Ð»Ñ Ð¿ÐµÑевода в ÑоÑмаÑе POT (Translation->Save template)
+ * ÐагÑÑзиÑÑ Ð¿ÐµÑевод из Ñайла PO (Translation->Save translation)
+ * ÐÑобÑажение пеÑеводов названий и ÑекÑÑов Ñ Ð²ÑеÑ
обÑекÑов
Commit: ece09a8a911ac3c4fa5c6319b6ed5bca83e52b24
https://github.com/scummvm/scummvm-tools/commit/ece09a8a911ac3c4fa5c6319b6ed5bca83e52b24
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Add license file
Changed paths:
A engines/petka/help/license.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/help/translate.txt
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 28af58a6e..8ae290bd5 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -4,6 +4,7 @@
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
+ * <a href="/help/license">ÐиÑензии</a>
ÐÑобÑажаемÑе ÑазделÑ
diff --git a/engines/petka/help/license.txt b/engines/petka/help/license.txt
new file mode 100644
index 000000000..d836c5edd
--- /dev/null
+++ b/engines/petka/help/license.txt
@@ -0,0 +1,61 @@
+ÐиÑении
+
+ÐÐ°Ð½Ð½Ð°Ñ Ð¿ÑогÑамма поÑÑавлÑеÑÑÑ Ð¿Ð¾Ð´ лиÑензией MIT.
+
+ÐÑаÑко:
+
+ * Ðожно полÑзоваÑÑÑÑ, доÑабаÑÑваÑÑ Ð¸ ÑаÑпÑоÑÑÑанÑÑÑ Ñвободно
+ * ÐÑи ÑаÑпÑоÑÑÑанении надо копиÑоваÑÑ ÑÑÐ¾Ñ Ñайл
+ * ÐикакиÑ
гаÑанÑий
+
+ÐолнÑй ÑекÑÑ Ð¿ÑиведÑн ниже.
+
+ÐÑполÑзÑемÑе библиоÑеки и ÐÐ:
+
+ * Python (https://www.python.org/) - PSF LICENSE AGREEMENT
+ * Pillow (https://pypi.python.org/pypi/Pillow/) - Apache License
+ * polib (https://pypi.python.org/pypi/polib) - MIT
+ * cx_Freeze (http://cx-freeze.sourceforge.net/) - PSF LICENSE AGREEMENT
+
+Copyright (c) 2014 romiq.kh at gmail.com
+
+ÐÐ°Ð½Ð½Ð°Ñ Ð»Ð¸ÑÐµÐ½Ð·Ð¸Ñ ÑазÑеÑаеÑ, безвозмездно, лиÑам, полÑÑивÑим ÐºÐ¾Ð¿Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾
+пÑогÑаммного обеÑпеÑÐµÐ½Ð¸Ñ Ð¸ ÑопÑÑÑÑвÑÑÑей докÑменÑаÑии (в далÑнейÑем именÑемÑми
+"ÐÑогÑаммное ÐбеÑпеÑение"), иÑполÑзоваÑÑ ÐÑогÑаммное ÐбеÑпеÑение без
+огÑаниÑений, вклÑÑÐ°Ñ Ð½ÐµÐ¾Ð³ÑаниÑенное пÑаво на иÑполÑзование, копиÑование,
+изменение, обÑединение, пÑбликаÑиÑ, ÑаÑпÑоÑÑÑанение, ÑÑблиÑензиÑование и/или
+пÑÐ¾Ð´Ð°Ð¶Ñ ÐºÐ¾Ð¿Ð¸Ð¹ ÐÑогÑаммного ÐбеÑпеÑениÑ, Ñакже как и лиÑам, коÑоÑÑм
+пÑедоÑÑавлÑеÑÑÑ Ð´Ð°Ð½Ð½Ð¾Ðµ ÐÑогÑаммное ÐбеÑпеÑение, пÑи ÑоблÑдении ÑледÑÑÑиÑ
+ÑÑловий:
+
+ÐÑÑеÑпомÑнÑÑÑй копиÑÐ°Ð¹Ñ Ð¸ даннÑе ÑÑÐ»Ð¾Ð²Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ Ð²ÐºÐ»ÑÑÐµÐ½Ñ Ð²Ð¾ вÑе копии
+или знаÑимÑе ÑаÑÑи данного ÐÑогÑаммного ÐбеÑпеÑениÑ.
+
+ÐÐÐÐÐÐ ÐÐ ÐÐÐ ÐÐÐÐÐÐ ÐÐÐСÐÐЧÐÐÐÐ ÐÐ ÐÐÐСТÐÐÐЯÐТСЯ «ÐÐÐ ÐСТЬ», ÐÐÐ ÐЮÐÐÐÐ ÐÐÐÐ
+ÐÐÐ ÐÐТÐÐ, ЯÐÐÐ ÐЫРÐÐÐÐÐЫХ ÐÐÐ ÐÐÐÐ ÐÐУÐÐÐÐÐÐЫХ, ÐÐÐЮЧÐЯ, ÐÐ ÐÐ ÐÐÐ ÐÐÐЧÐÐÐЯСЬ
+ÐÐÐ ÐÐТÐЯÐРТÐÐÐÐ ÐÐÐ ÐÐ ÐÐÐÐÐÐСТÐ, СÐÐТÐÐТСТÐÐЯ ÐÐ ÐÐÐ ÐÐÐÐÐ ÐТÐÐÐУ ÐÐÐÐÐЧÐÐÐЮ Ð
+ÐÐÐÐРУШÐÐÐЯ ÐÐ ÐÐ. ÐÐ Ð ÐÐÐÐРСÐУЧÐÐ ÐÐТÐРЫ ÐÐÐ ÐÐ ÐÐÐÐÐÐÐÐÐТÐÐÐ ÐÐ ÐÐСУТ
+ÐТÐÐТСТÐÐÐÐÐСТРÐÐ ÐСÐÐÐ Ð ÐÐÐÐÐЩÐÐÐРУЩÐÐ ÐÐ, УÐЫТÐÐÐ ÐÐÐ ÐРУÐÐÐ¥ ТРÐÐÐÐÐÐÐÐ ÐÐ
+ÐÐÐСТÐУЮЩÐÐ ÐÐÐТРÐÐТÐÐ, ÐÐÐÐÐТÐÐ ÐÐÐ ÐÐÐÐУ, ÐÐÐÐÐÐШÐÐ ÐÐ, ÐÐÐЮЩÐÐ ÐÐ ÐЧÐÐÐÐ ÐÐÐ
+СÐЯÐÐÐÐЫРС ÐÐ ÐÐÐ ÐÐÐÐЫРÐÐÐСÐÐЧÐÐÐÐÐ ÐÐÐ ÐСÐÐÐЬÐÐÐÐÐÐÐÐ ÐÐ ÐÐÐ ÐÐÐÐÐÐÐ
+ÐÐÐСÐÐЧÐÐÐЯ ÐÐÐ ÐÐЫÐÐ ÐÐÐСТÐÐЯÐРС ÐÐ ÐÐÐ ÐÐÐÐЫРÐÐÐСÐÐЧÐÐÐÐÐ.
+
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
diff --git a/engines/petka/help/list b/engines/petka/help/list
index 984865268..dbab18eeb 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -1,6 +1,7 @@
index
changes
faq
+license
parts
res
objs
diff --git a/engines/petka/help/translate.txt b/engines/petka/help/translate.txt
index 810fc40fc..49b98535c 100644
--- a/engines/petka/help/translate.txt
+++ b/engines/petka/help/translate.txt
@@ -4,4 +4,11 @@
* СоздаÑÑ Ñаблон Ð´Ð»Ñ Ð¿ÐµÑевода в ÑоÑмаÑе POT (Translation->Save template)
* ÐагÑÑзиÑÑ Ð¿ÐµÑевод из Ñайла PO (Translation->Save translation)
- * ÐÑобÑажение пеÑеводов названий и ÑекÑÑов Ñ Ð²ÑеÑ
обÑекÑов
+ * ÐокаÑваÑÑ Ð¿ÐµÑевод названий и ÑекÑÑов Ñ Ð²ÑеÑ
обÑекÑов
+
+
+ÐÐ»Ñ ÑабоÑÑ ÑÑиÑ
ÑÑнкÑий необÑ
одима библиоÑека polib.
+
+ * https://pypi.python.org/pypi/polib
+
+ÐÑли библиоÑека не ÑÑÑановлена Ð¼ÐµÐ½Ñ Translate оÑобÑажаÑÑÑÑ Ð½Ðµ бÑдеÑ.
Commit: 2ecdc95048eb9a4f0831ed656bd57c8b15f31643
https://github.com/scummvm/scummvm-tools/commit/2ecdc95048eb9a4f0831ed656bd57c8b15f31643
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ddb8103e9..4d1f0c079 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -52,6 +52,15 @@ def fmt_hl(loc, desc):
def fmt_cmt(cmt):
return "<font color=\"#4d4d4d\">{}</font>".format(cmt)
+def fmt_arg(value):
+ if value < 10:
+ return "{}".format(value)
+ elif value == 0xffff:
+ return "-1"
+ else:
+ return "0x{:X}".format(value)
+
+
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
def __init__(self, text):
@@ -964,15 +973,14 @@ class App(tkinter.Frame):
def usedby(lst):
for idx, rec in enumerate(lst):
ru = False
- for act_id, act_cond, act_arg, ops in rec.acts:
+ for act in rec.acts:
if ru: break
- for op_id, op_code, op_res, op4, op5 in ops:
- if res_id == op_res:
+ for op in ops:
+ if res_id == op.op_arg1:
self.add_info(" " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
ru = True
break
- #print(op_id, op_code, op_res, op4, op5)
self.add_info("\n\n<b>Used by objects</b>:\n")
usedby(self.sim.objects)
@@ -1184,47 +1192,45 @@ class App(tkinter.Frame):
resused = []
dlgused = []
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
- for idx, (act_op, act_status, act_ref, ops) in enumerate(rec.acts):
- msg = fmt_opcode(act_op)
+ for idx, act in enumerate(rec.acts):
+ msg = fmt_opcode(act.act_op)
cmt = ""
- if act_status != 0xff or act_ref != 0xffff:
- if act_ref == rec.idx:
+ if act.act_status != 0xff or act.act_ref != 0xffff:
+ act_ref = act.act_ref
+ if act.act_ref == rec.idx:
act_ref = "THIS"
else:
- if act_ref in self.sim.obj_idx:
- cmt = fmt_cmt(" // " + self.fmt_hl_obj(act_ref,
+ if act.act_ref in self.sim.obj_idx:
+ cmt = fmt_cmt(" // " + self.fmt_hl_obj(act.act_ref,
True))
- act_ref = self.fmt_hl_obj(act_ref)
+ act_ref = self.fmt_hl_obj(act.act_ref)
else:
- act_ref = "0x{:X}".format(act_ref)
- msg += " 0x{:02X} {}".format(act_status, act_ref)
+ act_ref = "0x{:X}".format(act.act_ref)
+ msg += " 0x{:02X} {}".format(act.act_status, act_ref)
self.add_info(" {}) <u>on {}</u>, ops: {}{}\n".format(\
- idx, msg, len(ops), cmt))
- for oidx, op in enumerate(ops):
- self.add_info(" {}) {} ".format(oidx, fmt_opcode(op[1])))
+ idx, msg, len(act.ops), cmt))
+ for oidx, op in enumerate(act.ops):
+ self.add_info(" {}) {} ".format(oidx,
+ fmt_opcode(op.op_code)))
cmt = ""
- if op[0] == rec.idx:
+ if op.op_ref == rec.idx:
self.add_info("THIS")
else:
- self.add_info(self.fmt_hl_obj_scene(op[0]))
- cmt = fmt_cmt(" // " + self.fmt_hl_obj_scene(op[0],
+ self.add_info(self.fmt_hl_obj_scene(op.op_ref))
+ cmt = fmt_cmt(" // " + self.fmt_hl_obj_scene(op.op_ref,
True))
msg = ""
- if op[2] != 0xffff:
- if op[2] not in resused and op[2] in self.sim.res:
- resused.append(op[2])
- for arg in op[2:]:
- msg += " "
- if arg < 10:
- msg += "{}".format(arg)
- elif arg == 0xffff:
- msg += "-1"
- else:
- msg += "0x{:X}".format(arg)
+ if op.op_arg1 != 0xffff:
+ if op.op_arg1 not in resused and \
+ op.op_arg1 in self.sim.res:
+ resused.append(op.op_arg1)
+ msg += " " + fmt_arg(op.op_arg1)
+ msg += " " + fmt_arg(op.op_arg2)
+ msg += " " + fmt_arg(op.op_arg3)
self.add_info("{}{}\n".format(msg, cmt))
- if op[1] == 0x11: # DIALOG
- if op[0] not in dlgused:
- dlgused.append(op[0])
+ if op.op_code == 0x11: # DIALOG
+ if op.op_ref not in dlgused:
+ dlgused.append(op.op_ref)
if len(resused) > 0:
self.add_info("\n<b>Used resources</b>: {}\n".\
@@ -1254,13 +1260,13 @@ class App(tkinter.Frame):
wasmsg = False
for obj2 in self.sim.objects + self.sim.scenes:
if obj2.idx == rec.idx: continue
- for idx, (act_op, act_status, act_ref, ops) in \
+ for idx, act in \
enumerate(obj2.acts):
- for oidx, op in enumerate(ops):
- if op[0] == rec.idx:
- arr = oplst.get(op[1], [])
- arr.append((obj2.idx, act_op, idx))
- oplst[op[1]] = arr
+ for oidx, op in enumerate(act.ops):
+ if op.op_ref == rec.idx:
+ arr = oplst.get(op.op_code, [])
+ arr.append((obj2.idx, act.act_op, idx))
+ oplst[op.op_code] = arr
break
klst = list(petka.OPCODES.keys())
@@ -1553,10 +1559,11 @@ class App(tkinter.Frame):
def usedby(lst):
for idx, rec in enumerate(lst):
ru = False
- for act_id, act_cond, act_arg, ops in rec.acts:
+ for act in rec.acts:
if ru: break
- for op_id, op_code, op_res, op4, op5 in ops:
- if op_code == 0x11 and op_id == grp.idx: # DIALOG
+ for op in act.ops:
+ if op.op_code == 0x11 and \
+ op.op_ref == grp.idx: # DIALOG
self.add_info(" " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
ru = True
@@ -1750,7 +1757,7 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("Error opening \"{}\" \n\n{}".\
format(hlesc(folder), hlesc(traceback.format_exc())))
- self.clear_hist()
+ #self.clear_hist()
def on_tran_save(self):
# save dialog
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 3dd31ef1f..638d5b978 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -84,14 +84,29 @@ class ScrObject:
def __init__(self, idx, name):
self.idx = idx
self.name = name
- self.acts = None
- self.cast = None
+ self.acts = None # action hadlers
+ self.cast = None # object color (CASTS.INI)
+
+class ScrActObject:
+ def __init__(self, act_op, act_status, act_ref):
+ self.act_op = act_op # handler: opcode filter
+ self.act_status = act_status # handler: status filter
+ self.act_ref = act_ref # handler: object idx filter
+ self.ops = None # operations
+
+class ScrOpObject:
+ def __init__(self, op_ref, op_code, op_arg1, op_arg2, op_arg3):
+ self.op_ref = op_ref # object idx
+ self.op_code = op_code # opcode
+ self.op_arg1 = op_arg1 # resource id, etc
+ self.op_arg2 = op_arg2
+ self.op_arg3 = op_arg3
class MsgObject:
def __init__(self, idx, wav, arg1, arg2, arg3):
self.idx = idx
- self.wav = wav
- self.arg1 = arg1
+ self.wav = wav # wav filename
+ self.arg1 = arg1 # reference to object
self.arg2 = arg2
self.arg3 = arg3
self.name = None
@@ -99,34 +114,34 @@ class MsgObject:
class DlgGrpObject:
def __init__(self, idx, num_acts, arg1):
self.idx = idx
- self.num_acts = num_acts
+ self.num_acts = num_acts # store array length while loading
self.arg1 = arg1
- self.acts = None
+ self.acts = None # dialog handlers
class DlgActObject:
def __init__(self, num_dlgs, opcode, ref, arg1, arg2):
- self.num_dlgs = num_dlgs
- self.opcode = opcode
- self.ref = ref
+ self.num_dlgs = num_dlgs # store array length while loading
+ self.opcode = opcode # handler: opcode filter
+ self.ref = ref # handler: object idx filter
self.arg1 = arg1
self.arg2 = arg2
- self.dlgs = None
- self.obj = None
+ self.dlgs = None # dialogs
+ self.obj = None # handler object
class DlgObject:
def __init__(self, op_start, arg1, arg2):
- self.op_start = op_start
+ self.op_start = op_start # start position
self.arg1 = arg1
self.arg2 = arg2
- self.ops = None
+ self.ops = None # operations list
class DlgOpObject:
def __init__(self, opcode, arg, ref, pos):
- self.opcode = opcode
- self.arg = arg
- self.ref = ref
- self.msg = None
- self.pos = pos
+ self.opcode = opcode # dialog opcode
+ self.arg = arg # argument (ref, offset etc.)
+ self.ref = ref # message idx
+ self.msg = None # message
+ self.pos = pos # position in opcodes list
class Engine:
def __init__(self):
@@ -287,15 +302,17 @@ class Engine:
off += 4
acts = []
for i in range(num_act):
- act_id, act_cond, act_arg, num_op = struct.unpack_from(\
+ act_op, act_status, act_ref, num_op = struct.unpack_from(\
"<HBHI", data[off:off + 9])
off += 9
- ops = []
+ act = ScrActObject(act_op, act_status, act_ref)
+ act.ops = []
for j in range(num_op):
op = struct.unpack_from("<5H", data[off:off + 10])
off += 10
- ops.append(op)
- acts.append([act_id, act_cond, act_arg, ops])
+ op = ScrOpObject(*op)
+ act.ops.append(op)
+ acts.append(act)
rec = ScrObject(obj_id, name)
rec.acts = acts
return off, rec
Commit: adc0fdd3ae7ef458aa32c1ac702ca1bf8a9f4af1
https://github.com/scummvm/scummvm-tools/commit/adc0fdd3ae7ef458aa32c1ac702ca1bf8a9f4af1
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix loading BGS.INI, add support info about start scene
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 4d1f0c079..e8eea1732 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -803,6 +803,12 @@ class App(tkinter.Frame):
format(len(self.sim.msgs)))
self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
format(len(self.sim.dlgs)))
+ scn = hlesc(self.sim.start_scene)
+ for scene in self.sim.scenes:
+ if scene.name == self.sim.start_scene:
+ scn = self.fmt_hl_scene(scene.idx, True)
+ break
+ self.add_info(" Start scene: {}\n".format(scn))
def path_default(self, path):
@@ -1628,11 +1634,13 @@ class App(tkinter.Frame):
self.add_info("<i>not initialized</i>\n")
else:
self.add_info("<i>works</i>\n\n")
- self.add_info(" <b>Path</b>: {}\n".format(
+ self.add_info(" <b>Path</b>: {}\n".format(
hlesc(self.sim.curr_path)))
- self.add_info(" <b>Speech</b>: {}\n".format(
+ self.add_info(" <b>Start</b>: {}.{}\n".format(
+ self.sim.start_part, self.sim.start_chap))
+ self.add_info(" <b>Speech</b>: {}\n".format(
hlesc(self.sim.curr_speech)))
- self.add_info(" <b>Disk ID</b>: {}\n\n".format(
+ self.add_info(" <b>Disk ID</b>: {}\n\n".format(
hlesc(self.sim.curr_diskid)))
self.path_info_outline()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 638d5b978..7851b13de 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -257,9 +257,9 @@ class Engine:
# load BGS.INI
self.bgs_ini = {}
self.start_scene = None
- pf = self.fman.find_path(self.curr_path + "bgs.ini")
- if pf:
- f = open(pf, "rb")
+ bgsfn = self.curr_path + "bgs.ini"
+ if self.fman.exists(bgsfn):
+ f = self.fman.read_file_stream(bgsfn)
try:
self.bgs_ini = self.parse_ini(f)
finally:
Commit: 641d9860b56537cf808cff0f865e25e02a7028b2
https://github.com/scummvm/scummvm-tools/commit/641d9860b56537cf808cff0f865e25e02a7028b2
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix loading BGS.INI, add support info about start scene
Changed paths:
engines/petka/petka/engine.py
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 7851b13de..e390a9fa1 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -276,6 +276,11 @@ class Engine:
self.fman.load_store(ini[strf], 1)
# load script.dat, backgrnd.bg and resources.qrc
self.load_script()
+ # parse enter areas
+ for scene in self.scenes:
+ if scene.name in self.bgs_ini:
+ print(self.bgs_ini[scene.name])
+
# load names & invntr
self.load_names()
# load dialogs
Commit: c3fc6f033132a1433f76eb0624a7ebcca25504b0
https://github.com/scummvm/scummvm-tools/commit/c3fc6f033132a1433f76eb0624a7ebcca25504b0
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Add enter areas information
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index e8eea1732..d8b1d4f79 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1286,6 +1286,19 @@ class App(tkinter.Frame):
" #{}".format(hid) + fmt_cmt(" // " +
self.fmt_hl_obj_scene(oid, True)) + "\n")
+ # enter areas
+ if not isobj and rec.entareas:
+ self.add_info("\n<b>Enter areas</b>: {}\n".format(
+ len(rec.entareas)))
+ for sf, oo in rec.entareas:
+ self.add_info(" <i>from</i>: {}\n".format(
+ self.fmt_hl_scene(sf.idx, True)))
+ self.add_info(" <i>on</i>: {}\n".format(
+ self.fmt_hl_obj(oo.idx, True)))
+
+
+
+
def path_std_items(self, path, level, guiname, guiitem, tt, lst, lst_idx,
lbmode, cb):
self.switch_view(0)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index e390a9fa1..4fe0a9af2 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -278,9 +278,25 @@ class Engine:
self.load_script()
# parse enter areas
for scene in self.scenes:
+ scene.entareas = None
if scene.name in self.bgs_ini:
- print(self.bgs_ini[scene.name])
-
+ scene.entareas = []
+ for key in self.bgs_ini["__order__"][scene.name]:
+ # search scene
+ sf = None
+ for scenefrom in self.scenes:
+ if scenefrom.name == key:
+ sf = scenefrom
+ break
+ value = self.bgs_ini[scene.name][key]
+ # search objects
+ oo = None
+ for objon in self.objects:
+ if objon.name == value:
+ oo = objon
+ break
+ if sf and oo:
+ scene.entareas.append((sf, oo))
# load names & invntr
self.load_names()
# load dialogs
Commit: c31c1f8f7d349dd5b77f4ff7ab5fb0e2f369f508
https://github.com/scummvm/scummvm-tools/commit/c31c1f8f7d349dd5b77f4ff7ab5fb0e2f369f508
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: transliterate templates
Changed paths:
engines/petka/help/license.txt
engines/petka/help/translate.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/license.txt b/engines/petka/help/license.txt
index d836c5edd..31af67f0b 100644
--- a/engines/petka/help/license.txt
+++ b/engines/petka/help/license.txt
@@ -15,8 +15,9 @@
* Python (https://www.python.org/) - PSF LICENSE AGREEMENT
* Pillow (https://pypi.python.org/pypi/Pillow/) - Apache License
* polib (https://pypi.python.org/pypi/polib) - MIT
+ * transliterate (https://pypi.python.org/pypi/transliterate) - GPL 2.0/LGPL 2.1
* cx_Freeze (http://cx-freeze.sourceforge.net/) - PSF LICENSE AGREEMENT
-
+
Copyright (c) 2014 romiq.kh at gmail.com
ÐÐ°Ð½Ð½Ð°Ñ Ð»Ð¸ÑÐµÐ½Ð·Ð¸Ñ ÑазÑеÑаеÑ, безвозмездно, лиÑам, полÑÑивÑим ÐºÐ¾Ð¿Ð¸Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾
diff --git a/engines/petka/help/translate.txt b/engines/petka/help/translate.txt
index 49b98535c..bbd2dfed7 100644
--- a/engines/petka/help/translate.txt
+++ b/engines/petka/help/translate.txt
@@ -3,12 +3,21 @@
ÐÐ»Ñ Ð¿ÐµÑеводÑиков пÑогÑамма можеÑ:
* СоздаÑÑ Ñаблон Ð´Ð»Ñ Ð¿ÐµÑевода в ÑоÑмаÑе POT (Translation->Save template)
+ * СоздаÑÑ Ñаблон в ÑÑанÑлиÑе ÑоÑмаÑе POT
+ (Translation->Save transliterate template)
* ÐагÑÑзиÑÑ Ð¿ÐµÑевод из Ñайла PO (Translation->Save translation)
* ÐокаÑваÑÑ Ð¿ÐµÑевод названий и ÑекÑÑов Ñ Ð²ÑеÑ
обÑекÑов
-
ÐÐ»Ñ ÑабоÑÑ ÑÑиÑ
ÑÑнкÑий необÑ
одима библиоÑека polib.
* https://pypi.python.org/pypi/polib
-ÐÑли библиоÑека не ÑÑÑановлена Ð¼ÐµÐ½Ñ Translate оÑобÑажаÑÑÑÑ Ð½Ðµ бÑдеÑ.
+ÐÑли библиоÑека не ÑÑÑановлена Ð¼ÐµÐ½Ñ "Translate" оÑобÑажаÑÑÑÑ Ð½Ðµ бÑдеÑ.
+
+ÐÐ»Ñ Ð¿ÐµÑевода в ÑÑанÑÐ»Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ
одима библиоÑека transliterate.
+
+ * https://pypi.python.org/pypi/transliterate
+
+ÐÑли библиоÑека не ÑÑÑановлена пÑÐ½ÐºÑ Ð¼ÐµÐ½Ñ "Save transliterate template"
+ оÑобÑажаÑÑÑÑ Ð½Ðµ бÑдеÑ.
+
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index d8b1d4f79..ed790030c 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -25,6 +25,11 @@ try:
except ImportError:
polib = None
+try:
+ import transliterate
+except ImportError:
+ transliterate = None
+
import petka
APPNAME = "P1&2 Explorer"
@@ -332,6 +337,10 @@ class App(tkinter.Frame):
menutran.add_command(
command = self.on_tran_save,
label = "Save template (.pot)")
+ if transliterate:
+ menutran.add_command(
+ command = self.on_tran_save_tlt,
+ label = "Save transliterate template (.pot)")
menutran.add_command(
command = self.on_tran_load,
label = "Load translation (.po)")
@@ -1374,8 +1383,11 @@ class App(tkinter.Frame):
if self.sim is None:
return self.path_default([])
def info(name):
- self.add_info("<b>Cast</b>: {}\n".format(hlesc(name)))
- self.add_info("Value: {}\n".format(self.sim.casts[name]))
+ self.add_info("<b>Cast</b>: {}\n".format(hlesc(name)))
+ if self.tran:
+ self.add_info("<b>Cast</b>(t): {}\n".\
+ format(hlesc(self._t(name, "obj"))))
+ self.add_info("Value: {}\n".format(self.sim.casts[name]))
try:
val = self.sim.casts[name].split(" ")
val = [x for x in val if x]
@@ -1781,9 +1793,16 @@ class App(tkinter.Frame):
#self.clear_hist()
def on_tran_save(self):
+ self.on_tran_save_real()
+
+ def on_tran_save_tlt(self):
+ self.on_tran_save_real(True)
+
+ def on_tran_save_real(self, tlt = False):
# save dialog
fn = filedialog.asksaveasfilename(parent = self,
- title = "Save translate template (.pot)",
+ title = "Save translate template (.pot)" +
+ " (transliterate)" if tlt else "",
filetypes = [('PO Template', ".pot"), ('all files', '.*')],
initialdir = os.path.abspath(os.curdir))
if not fn: return # save canceled
@@ -1799,8 +1818,12 @@ class App(tkinter.Frame):
def saveitem(text, cmt = None):
if text in used: return
used.append(text)
+ ts = text
+ if tlt:
+ ts = transliterate.utils.translit(text, "ru", \
+ reversed = True)
entry = polib.POEntry(
- msgid = text, msgstr = text, comment = cmt)
+ msgid = text, msgstr = ts, comment = cmt)
po.append(entry)
for rec in self.sim.objects:
saveitem(rec.name, "obj_{}".format(rec.idx))
Commit: 396efadba749d6d3e13582692a4d74bcdeecc77b
https://github.com/scummvm/scummvm-tools/commit/396efadba749d6d3e13582692a4d74bcdeecc77b
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: release 0.2n; remove tranliterate library
Changed paths:
engines/petka/help/changes.txt
engines/petka/help/license.txt
engines/petka/help/translate.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index b67406c46..92a9d4c2e 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,12 +1,23 @@
ЧÑо нового
==========
+2014-05-21 веÑÑÐ¸Ñ 0.2n
+----------------------
+ФÑнкÑÑÐ¸Ñ ÑÑанÑлиÑеÑаÑии заменена на ÑобÑвеннÑÑ.
+
+2014-05-21 веÑÑÐ¸Ñ 0.2m
+----------------------
+Ðобавлено оÑобÑажение ÑоÑек вÑ
ода на ÑÑÐµÐ½Ñ Ð¸Ð· дÑÑгиÑ
ÑÑен (BGS.INI)
+ÐÑпÑавлена загÑÑзка Ñайла BGS.INI из STR Ñайла
+Ðобавлена ÑÑнкÑÐ¸Ñ ÑоÑ
ÑÐ°Ð½ÐµÐ½Ð¸Ñ Ñаблона пеÑевода в ÑÑанÑлиÑе (ТепеÑÑ Ð¼Ð¾Ð¶Ð½Ð¾ ÑÑазÑ
+оÑениÑÑ Ð³Ð´Ðµ пеÑевод Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²Ñполнен).
+
2014-05-20 веÑÑÐ¸Ñ 0.2l
----------------------
Ðобавлена ÑÑнкÑÐ¸Ñ ÑÐ¾Ð·Ð´Ð°Ð½Ð¸Ñ Ñаблона Ð´Ð»Ñ Ð¿ÐµÑевода (.pot)
Ðобавлена загÑÑзка пеÑевода (.po)
ÐÐ·Ð¼ÐµÐ½ÐµÐ½Ñ Ð²Ñе ÑÐ°Ð·Ð´ÐµÐ»Ñ Ð³Ð´Ðµ Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑобÑажаÑÑÑÑ Ð¿ÐµÑеведÑнна инÑоÑмаÑиÑ
-Ðзменен поÑÑдок загÑÑÐ·ÐºÑ Ð´Ð°Ð½Ð½ÑÑ
из командной ÑÑÑоки
+Ðзменен поÑÑдок загÑÑзки даннÑÑ
из командной ÑÑÑоки
2014-05-16 веÑÑÐ¸Ñ 0.2k
----------------------
diff --git a/engines/petka/help/license.txt b/engines/petka/help/license.txt
index 31af67f0b..fbdb990e3 100644
--- a/engines/petka/help/license.txt
+++ b/engines/petka/help/license.txt
@@ -15,7 +15,6 @@
* Python (https://www.python.org/) - PSF LICENSE AGREEMENT
* Pillow (https://pypi.python.org/pypi/Pillow/) - Apache License
* polib (https://pypi.python.org/pypi/polib) - MIT
- * transliterate (https://pypi.python.org/pypi/transliterate) - GPL 2.0/LGPL 2.1
* cx_Freeze (http://cx-freeze.sourceforge.net/) - PSF LICENSE AGREEMENT
Copyright (c) 2014 romiq.kh at gmail.com
diff --git a/engines/petka/help/translate.txt b/engines/petka/help/translate.txt
index bbd2dfed7..c059d68b3 100644
--- a/engines/petka/help/translate.txt
+++ b/engines/petka/help/translate.txt
@@ -14,10 +14,3 @@
ÐÑли библиоÑека не ÑÑÑановлена Ð¼ÐµÐ½Ñ "Translate" оÑобÑажаÑÑÑÑ Ð½Ðµ бÑдеÑ.
-ÐÐ»Ñ Ð¿ÐµÑевода в ÑÑанÑÐ»Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ
одима библиоÑека transliterate.
-
- * https://pypi.python.org/pypi/transliterate
-
-ÐÑли библиоÑека не ÑÑÑановлена пÑÐ½ÐºÑ Ð¼ÐµÐ½Ñ "Save transliterate template"
- оÑобÑажаÑÑÑÑ Ð½Ðµ бÑдеÑ.
-
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ed790030c..2821de8ba 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -25,15 +25,10 @@ try:
except ImportError:
polib = None
-try:
- import transliterate
-except ImportError:
- transliterate = None
-
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2l 2014-05-20"
+VERSION = "v0.2m 2014-05-21"
def hlesc(value):
if value is None:
@@ -43,19 +38,9 @@ def hlesc(value):
def cesc(value):
return value.replace("\\", "\\\\").replace("\"", "\\\"")
-def fmt_opcode(opcode):
- return petka.OPCODES.get(opcode, ["<font color=\"red\">OP{:04X}</font>".\
- format(opcode)])[0]
-
-def fmt_dlgop(opcode):
- return petka.DLGOPS.get(opcode, ["<font color=\"red\">OP{:02X}</font>".\
- format(opcode)])[0]
-
def fmt_hl(loc, desc):
return "<a href=\"{}\">{}</a>".format(loc, desc)
-def fmt_cmt(cmt):
- return "<font color=\"#4d4d4d\">{}</font>".format(cmt)
def fmt_arg(value):
if value < 10:
@@ -65,7 +50,40 @@ def fmt_arg(value):
else:
return "0x{:X}".format(value)
-
+def translit(text):
+ ru = "абвгдеÑзийклмнопÑÑÑÑÑÑ
ÑÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐРСТУФХЪЫЬÐ"
+ en = "abvgdeezijklmnoprstufh'y'eABVGDEEZIJKLMNOPRSTUFH'Y'Ð"
+ sl = {
+ "ж": "zh",
+ "Ñ": "ts",
+ "Ñ": "ch",
+ "Ñ": "sh",
+ "Ñ": "sch",
+ "Ñ": "yu",
+ "Ñ": "ya",
+ "Ð": "Zh",
+ "Ц": "Ts",
+ "Ч": "Ch",
+ "Ш": "Sh",
+ "Щ": "Sch",
+ "Ю": "Yu",
+ "Я": "Ya"
+ }
+ ret = ""
+ allcaps = True
+ for ch in text:
+ ps = ru.find(ch)
+ if ps > 0:
+ ret += en[ps]
+ elif ch in sl:
+ ret += sl[ch]
+ else:
+ ret += ch
+ allcaps = (allcaps and ch.upper() == ch)
+ if allcaps:
+ ret = ret.upper()
+ return ret
+
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
def __init__(self, text):
@@ -337,10 +355,9 @@ class App(tkinter.Frame):
menutran.add_command(
command = self.on_tran_save,
label = "Save template (.pot)")
- if transliterate:
- menutran.add_command(
- command = self.on_tran_save_tlt,
- label = "Save transliterate template (.pot)")
+ menutran.add_command(
+ command = self.on_tran_save_tlt,
+ label = "Save transliterate template (.pot)")
menutran.add_command(
command = self.on_tran_load,
label = "Load translation (.po)")
@@ -739,6 +756,17 @@ class App(tkinter.Frame):
return self.tran["_"][value]
return value
+ def fmt_opcode(self, opcode):
+ return petka.OPCODES.get(opcode, ["<font color=\"red\">OP{:04X}</font>".\
+ format(opcode)])[0]
+
+ def fmt_dlgop(self, opcode):
+ return petka.DLGOPS.get(opcode, ["<font color=\"red\">OP{:02X}</font>".\
+ format(opcode)])[0]
+
+ def fmt_cmt(self, cmt):
+ return "<font color=\"#4d4d4d\">{}</font>".format(cmt)
+
def fmt_hl_rec(self, lst_idx, pref, rec_id, full, tt):
if rec_id in lst_idx:
fmt = fmt_hl("/{}/{}".format(pref, rec_id), str(rec_id))
@@ -1201,14 +1229,14 @@ class App(tkinter.Frame):
msg += "-1"
else:
msg += "0x{:X}".format(arg)
- self.add_info(msg + fmt_cmt(" // " + self.fmt_hl_obj(
+ self.add_info(msg + self.fmt_cmt(" // " + self.fmt_hl_obj(
ref[0].idx, True)) + "\n")
resused = []
dlgused = []
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
for idx, act in enumerate(rec.acts):
- msg = fmt_opcode(act.act_op)
+ msg = self.fmt_opcode(act.act_op)
cmt = ""
if act.act_status != 0xff or act.act_ref != 0xffff:
act_ref = act.act_ref
@@ -1216,8 +1244,8 @@ class App(tkinter.Frame):
act_ref = "THIS"
else:
if act.act_ref in self.sim.obj_idx:
- cmt = fmt_cmt(" // " + self.fmt_hl_obj(act.act_ref,
- True))
+ cmt = self.fmt_cmt(" // " + self.fmt_hl_obj(
+ act.act_ref, True))
act_ref = self.fmt_hl_obj(act.act_ref)
else:
act_ref = "0x{:X}".format(act.act_ref)
@@ -1226,14 +1254,14 @@ class App(tkinter.Frame):
idx, msg, len(act.ops), cmt))
for oidx, op in enumerate(act.ops):
self.add_info(" {}) {} ".format(oidx,
- fmt_opcode(op.op_code)))
+ self.fmt_opcode(op.op_code)))
cmt = ""
if op.op_ref == rec.idx:
self.add_info("THIS")
else:
self.add_info(self.fmt_hl_obj_scene(op.op_ref))
- cmt = fmt_cmt(" // " + self.fmt_hl_obj_scene(op.op_ref,
- True))
+ cmt = self.fmt_cmt(" // " + self.fmt_hl_obj_scene(
+ op.op_ref, True))
msg = ""
if op.op_arg1 != 0xffff:
if op.op_arg1 not in resused and \
@@ -1288,11 +1316,11 @@ class App(tkinter.Frame):
klst.sort()
for k in klst:
if k not in oplst: continue
- self.add_info("\n<b>Used in " + fmt_opcode(k) + "</b>:\n")
+ self.add_info("\n<b>Used in " + self.fmt_opcode(k) + "</b>:\n")
for oid, htp, hid in oplst[k]:
self.add_info(" " + self.fmt_hl_obj_scene(oid) +
- " on " + fmt_opcode(htp) +
- " #{}".format(hid) + fmt_cmt(" // " +
+ " on " + self.fmt_opcode(htp) +
+ " #{}".format(hid) + self.fmt_cmt(" // " +
self.fmt_hl_obj_scene(oid, True)) + "\n")
# enter areas
@@ -1496,9 +1524,9 @@ class App(tkinter.Frame):
self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.acts)))
for idx, act in enumerate(grp.acts):
self.add_info(" {}) <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: "\
- "{}{}\n".format(idx, fmt_opcode(act.opcode),
+ "{}{}\n".format(idx, self.fmt_opcode(act.opcode),
self.fmt_hl_obj(act.ref), act.arg1, act.arg2, \
- len(act.dlgs), fmt_cmt(" // " +
+ len(act.dlgs), self.fmt_cmt(" // " +
self.fmt_hl_obj(act.ref, True))))
for didx, dlg in enumerate(act.dlgs):
self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
@@ -1517,18 +1545,18 @@ class App(tkinter.Frame):
for oidx, op in enumerate(dlg.ops):
cmt = ""
opref = "0x{:X}".format(op.ref)
- opcode = fmt_dlgop(op.opcode)
+ opcode = self.fmt_dlgop(op.opcode)
if op.pos in usedadr:
self.add_info(" <i>label_{:X}:</i>\n".format(
op.pos))
if op.opcode == 0x1: # BREAK
if op.pos in usedcase:
if len(usedadr) > 0:
- cmt = fmt_cmt(" // end select <i>"\
+ cmt = self.fmt_cmt(" // end select <i>"\
"label_{:X}</i>, case=0x{:}"\
"".format(*usedcase[op.pos]))
else:
- cmt = fmt_cmt(" // end "\
+ cmt = self.fmt_cmt(" // end "\
"select case=0x{:}".\
format(usedcase[op.pos][1]))
elif op.opcode == 0x2 or op.opcode == 0x8: # MENU or CIRCLE
@@ -1553,12 +1581,12 @@ class App(tkinter.Frame):
else:
docurr = ["complex"]
if len(doarr) < sellen:
- cmt = fmt_cmt(" // {} select broken, "\
+ cmt = " // {} select broken, "\
"required={}, got={}".\
- format(opcode, sellen, len(doarr)))
+ format(opcode, sellen, len(doarr))
else:
cmt += ",".join(["+".join(x) for x in doarr])
- cmt = fmt_cmt(cmt)
+ cmt = self.fmt_cmt(cmt)
if menuactstart is not None:
for oidx2, op2 in enumerate(dlg.ops[\
menuactstart:menuactstart + sellen]):
@@ -1567,7 +1595,7 @@ class App(tkinter.Frame):
op.opcode == 0x4: # GOTO or MENURET
opref = "<i>label_{:X}</i>".format(op.ref)
if op.pos in usedmenu:
- cmt = fmt_cmt(" // action menu=<i>"\
+ cmt = self.fmt_cmt(" // action menu=<i>"\
"label_{:X}</i>, case=0x{:}".\
format(*usedmenu[op.pos]))
elif op.opcode == 0x7:
@@ -1575,7 +1603,7 @@ class App(tkinter.Frame):
if op.msg:
opref = self.fmt_hl_msg(op.ref)
objref = self.fmt_hl_obj(op.msg.obj.idx)
- cmt = fmt_cmt(" // obj={}, msg={}".\
+ cmt = self.fmt_cmt(" // obj={}, msg={}".\
format(objref,
self.fmt_hl_msg(op.ref, True)))
@@ -1820,8 +1848,7 @@ class App(tkinter.Frame):
used.append(text)
ts = text
if tlt:
- ts = transliterate.utils.translit(text, "ru", \
- reversed = True)
+ ts = translit(text)
entry = polib.POEntry(
msgid = text, msgstr = ts, comment = cmt)
po.append(entry)
@@ -1876,6 +1903,8 @@ class App(tkinter.Frame):
format(hlesc(fn), hlesc(traceback.format_exc())))
def main():
+ print(translit("ÐÐСÐÐЯ ÐÐÐ ÐÐÐ"))
+ #return
root = tkinter.Tk()
app = App(master = root)
argv = sys.argv[1:]
Commit: 01173a0031a00d6689cf00df1154bd864aa20749
https://github.com/scummvm/scummvm-tools/commit/01173a0031a00d6689cf00df1154bd864aa20749
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: release 0.2n; remove tranliterate library
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 2821de8ba..2a950128e 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1903,8 +1903,6 @@ class App(tkinter.Frame):
format(hlesc(fn), hlesc(traceback.format_exc())))
def main():
- print(translit("ÐÐСÐÐЯ ÐÐÐ ÐÐÐ"))
- #return
root = tkinter.Tk()
app = App(master = root)
argv = sys.argv[1:]
Commit: 740c900e522559f56bf0212ae5470a29f1b90ba6
https://github.com/scummvm/scummvm-tools/commit/740c900e522559f56bf0212ae5470a29f1b90ba6
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: release 0.2l
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 2a950128e..3ae4a3dcf 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2m 2014-05-21"
+VERSION = "v0.2l 2014-05-21"
def hlesc(value):
if value is None:
Commit: f0d14889aa30338d1d8b2ce1b8b3bda5a53b1e74
https://github.com/scummvm/scummvm-tools/commit/f0d14889aa30338d1d8b2ce1b8b3bda5a53b1e74
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix version
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3ae4a3dcf..b1bc41a06 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2l 2014-05-21"
+VERSION = "v0.2n 2014-05-21"
def hlesc(value):
if value is None:
Commit: 80f87766e10e561e05eb4653c29756e9cbca7c01
https://github.com/scummvm/scummvm-tools/commit/80f87766e10e561e05eb4653c29756e9cbca7c01
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix resource opening
Changed paths:
engines/petka/help/changes.txt
engines/petka/help/index.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 92a9d4c2e..81d630548 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,9 +1,13 @@
ЧÑо нового
==========
+2014-05-23 веÑÑÐ¸Ñ 0.2o
+----------------------
+ÐÑпÑавление оÑибки пÑи оÑкÑÑÑии ÑеÑÑÑÑа.
+
2014-05-21 веÑÑÐ¸Ñ 0.2n
----------------------
-ФÑнкÑÑÐ¸Ñ ÑÑанÑлиÑеÑаÑии заменена на ÑобÑвеннÑÑ.
+ФÑнкÑÑÐ¸Ñ ÑÑанÑлиÑеÑаÑии заменена на ÑобÑÑвеннÑÑ.
2014-05-21 веÑÑÐ¸Ñ 0.2m
----------------------
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 8ae290bd5..ee2fe76ec 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -1,6 +1,6 @@
СпÑавка
-ÐеÑÑиÑ: 0.2l 2014-05-20
+ÐеÑÑиÑ: 0.2o 2014-05-20
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index b1bc41a06..a16133823 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2n 2014-05-21"
+VERSION = "v0.2o 2014-05-23"
def hlesc(value):
if value is None:
@@ -1018,7 +1018,7 @@ class App(tkinter.Frame):
ru = False
for act in rec.acts:
if ru: break
- for op in ops:
+ for op in act.ops:
if res_id == op.op_arg1:
self.add_info(" " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
Commit: 73ead29a6469c0a0aebe97e3421f207d362e6a41
https://github.com/scummvm/scummvm-tools/commit/73ead29a6469c0a0aebe97e3421f207d362e6a41
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix translit Capital cyrillic E
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index a16133823..603659665 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -52,7 +52,7 @@ def fmt_arg(value):
def translit(text):
ru = "абвгдеÑзийклмнопÑÑÑÑÑÑ
ÑÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐРСТУФХЪЫЬÐ"
- en = "abvgdeezijklmnoprstufh'y'eABVGDEEZIJKLMNOPRSTUFH'Y'Ð"
+ en = "abvgdeezijklmnoprstufh'y'eABVGDEEZIJKLMNOPRSTUFH'Y'E"
sl = {
"ж": "zh",
"Ñ": "ts",
Commit: d81b65fe32790b0ace4623ae12eeb03596a27543
https://github.com/scummvm/scummvm-tools/commit/d81b65fe32790b0ace4623ae12eeb03596a27543
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Standalone decompiler for SCRIPT.DAT
Changed paths:
A engines/petka/p12script.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
new file mode 100755
index 000000000..380e5cda9
--- /dev/null
+++ b/engines/petka/p12script.py
@@ -0,0 +1,282 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import os, sys
+import traceback
+import argparse
+import io
+import hashlib
+
+import petka
+
+APPNAME = "P1&2 Compiler and decompiler"
+VERSION = "v0.3 2014-06-01"
+
+def find_in_folder(folder, name, ifnot = True):
+ for item in os.listdir(folder):
+ if item.upper() == name.upper():
+ return os.path.join(folder, item)
+ if ifnot:
+ return os.path.join(folder, name)
+ else:
+ return None
+
+# ===========================================================================
+# decompile utils
+# ===========================================================================
+def fmtnum16(num):
+ if num < 10:
+ return "{}".format(num)
+ elif num == 0xffff:
+ return "-1"
+ else:
+ return "0x{:x}".format(num)
+
+def fmtnum32(num):
+ if num < 10:
+ return "{}".format(num)
+ elif num == 0xffffffff:
+ return "-1"
+ else:
+ return "0x{:x}".format(num)
+
+def fmtop(num):
+ if num in petka.OPCODES:
+ return petka.OPCODES[num][0]
+ return "0x{:x}".format(num)
+
+def fmtdlgop(num):
+ if num in petka.DLGOPS:
+ return petka.DLGOPS[num][0]
+ return "0x{:x}".format(num)
+
+def escstr(value):
+ return value.replace("\\", "\\\\").replace("\"", "\\\"")
+
+# ===========================================================================
+# decompile SCRIPT.DAT
+# ===========================================================================
+def pretty_print_scr(pe, name, stream, enc = None, decsort = False):
+ def pprint(msg):
+ if stream is None:
+ print(msg)
+ else:
+ stream.write((msg + "\n").encode(enc or "UTF-8"))
+
+ # define lists of used items
+ used_obj = []
+ used_res = []
+
+ def fmtfor(num, objid):
+ if num == objid:
+ return "THIS"
+ if num in pe.obj_idx:
+ return "obj_{}".format(num)
+ if num in pe.scn_idx:
+ return "scene_{}".format(num)
+ return fmtnum16(num)
+
+ def printres(resid):
+ pprint("RES res_{} 0x{:x} \"{}\"".format(resid, resid,
+ escstr(pe.res[resid])))
+ pprint("")
+
+ def printrescheck(resid, opcode):
+ tp = petka.OPCODES.get(opcode, ("", 0))[1]
+ if tp == 1 and resid in pe.res:
+ if resid in used_res:
+ return
+ used_res.append(resid)
+ printres(resid)
+
+ def printitem(item, itemtype):
+ pprint("{} {}_{} 0x{:x} \"{}\"".format(itemtype.upper(), itemtype,
+ item.idx, item.idx, escstr(item.name)))
+
+ # sub objects
+ if itemtype == "scene":
+ if len(item.refs) == 0:
+ pprint(" ZEROREF")
+ for obj, a1, a2, a3, a4, a5 in item.refs:
+ if obj.idx in pe.obj_idx:
+ ref = "obj_{}".format(obj.idx)
+ elif obj.idx in pe.scn_idx:
+ ref = "scene_".format(obj.idx)
+ else:
+ pprint(" # unknown reference to 0x{:x}".format(
+ obj.idx))
+ ref = "0x{:x}".format(obj.idx)
+ pprint(" REF {} {} {} {} {} {}".format(ref, fmtnum32(a1),
+ fmtnum32(a2), fmtnum32(a3),
+ fmtnum32(a4), fmtnum32(a5)))
+
+ for act in item.acts:
+ actif = ""
+ if act.act_status != 0xff or act.act_ref != 0xffff:
+ actif = " 0x{:02x} ".format(act.act_status)
+ if act.act_ref == item.idx:
+ actif += "THIS"
+ else:
+ actif += fmtnum16(act.act_ref)
+ pprint(" ON {}{}".format(fmtop(act.act_op), actif))
+ # list actions
+ for op in act.ops:
+ if op.op_arg1 in pe.res and \
+ petka.OPCODES.get(op.op_code, ["", 0])[1] == 1:
+ res = "res_{}".format(op.op_arg1)
+ else:
+ res = fmtnum16(op.op_arg1)
+ pprint(" {} {} {} {} {}".format(fmtop(op.op_code),
+ fmtfor(op.op_ref, item.idx), res,
+ fmtnum16(op.op_arg2),
+ fmtnum16(op.op_arg3)))
+ pprint(" ENDON")
+
+ pprint("END{} # {}_{}".format(itemtype.upper(), itemtype, item.idx))
+ pprint("")
+
+ pprint("# Decompile SCRIPT \"{}\"".format(name))
+ pprint("# Version: {}".format(VERSION))
+ pprint("# Encoding: {}".format(enc))
+
+ if decsort:
+ for idx, scene in enumerate(pe.scenes):
+ pprint("# Scene {} / {}".format(idx + 1, len(pe.scenes)))
+ # display used objects
+ if len(scene.idx.refs) > 0:
+ pprint("# referenced objects {}:".format(len(scene.refs)))
+ for ref in scene.refs:
+ if ref[0].idx in used_obj:
+ pprint("# object 0x{:x} already defined".\
+ format(ref[0].idx))
+ continue
+ used_obj.append(ref[0].idx)
+ if ref[0].idx in pe.obj_idx:
+ for act in ref[0].acts_array:
+ for op in act.ops_array:
+ printrescheck(op.op_arg1, op.op_code)
+ printitem(obj, "obj")
+ else:
+ pprint("# No referenced objects")
+ # display res
+ for act in scene.acts:
+ for op in act.ops:
+ printrescheck(op.op_arg1, op.op_code)
+ printitem(scene, "scene")
+ # list unused
+ msg = False
+ for obj in pe.objects:
+ if obj.idx in used_obj: continue
+ if not msg:
+ pprint("# Note: Following objects not listed anywhere")
+ msg = True
+ printitem(obj, "OBJ")
+ msg = False
+ for res in self.res:
+ if res in used_res: continue
+ if not msg:
+ pprint("# Note: Following resources not listed anywhere")
+ msg = True
+ printres(res)
+ else:
+ for obj in pe.objects:
+ printitem(obj, "obj")
+ for scene in pe.scenes:
+ printitem(scene, "scene")
+ for res in pe.resord:
+ printres(res)
+
+# check if file already exists and flag for overwrite not set
+def ckeckoverwrite(fn, args):
+ if os.path.exists(fn) and not args.fo:
+ print("File \"{}\" already exists, use -fo to overwrite".\
+ format(fn))
+ return True
+ return False
+
+# check files are the same
+def checksame(f1, n1, f2, n2):
+ if os.path.abspath(f1) == os.path.abspath(f2):
+ print("Error: {} and {} are the same \"{}\"".\
+ format(f1))
+ return True
+ return False
+
+def action_dec(args):
+ print("Decompile SCRIPT.DAT file")
+ destpath = args.destpath
+ encoding = args.encoding
+
+ if destpath:
+ if ckeckoverwrite(destpath, args): return -1
+ if checksame(args.sourcepath, "source", destpath, "destination"):
+ return -2
+ if not encoding:
+ encoding = "UTF-8"
+
+ print("Input:\t{}".format(args.sourcepath))
+ print("Output:\t{}".format(destpath or "-"))
+ if destpath:
+ print("Enc:\t{}".format(encoding))
+ if args.decompile_sorted:
+ print("Flag decompile_sorted enabled")
+
+ pe = petka.Engine()
+ pe.init_empty("cp1251")
+ bkgname = find_in_folder(os.path.dirname(args.sourcepath), "backgrnd.bg")
+ resname = find_in_folder(os.path.dirname(args.sourcepath), "resource.qrc")
+ pe.load_script(args.sourcepath, bkgname, resname)
+ if destpath:
+ f = open(destpath, "wb")
+ try:
+ pretty_print_scr(pe, args.sourcepath, f, enc = encoding, \
+ decsort = args.decompile_sorted)
+ finally:
+ f.close()
+ else:
+ pretty_print_scr(pe, args.sourcepath, None)
+
+def action_version(args):
+ print("Version: " + VERSION)
+
+def main():
+ print(APPNAME + ", " + VERSION)
+ print("\tRoman Kharin (romiq.kh at gmail.com)")
+ if len(sys.argv) < 2:
+ print("Use -h for help.")
+ return
+
+ if len(sys.argv) >= 3:
+ if sys.argv[1] == "test":
+ internaltest(sys.argv[2])
+ return
+
+ parser = argparse.ArgumentParser(epilog = \
+ "For actions help try: <action> -h")
+ subparsers = parser.add_subparsers(title = 'actions')
+
+ # decompile - <script.dat> [[--enc <encoding>] -o <decompiled.txt>]
+ parser_dec = subparsers.add_parser("decompile", aliases = ['d'], \
+ help = "decompile script.dat")
+ parser_dec.add_argument('-fo', action = 'store_true', \
+ help = "force overwrite existing output file")
+ parser_dec.add_argument('--decompile-sorted', action = 'store_true', \
+ help = "display objects and scenes in sorted way (can change order)")
+ parser_dec.add_argument('-o', action = 'store', dest = "destpath",\
+ help = "output path for decompiled (default: stdout)")
+ parser_dec.add_argument('-e', "--enc", action = 'store', dest = "encoding",\
+ help = "output encoding (default: UTF-8)")
+ parser_dec.add_argument('sourcepath', help = "path to SCRIPT.DAT file")
+ parser_dec.set_defaults(func = action_dec)
+
+ # version
+ parser_version = subparsers.add_parser("version", help = "program version")
+ parser_version.set_defaults(func = action_version)
+
+ args = parser.parse_args()
+ args.func(args)
+
+if __name__ == "__main__":
+ main()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 4fe0a9af2..551b3f243 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -158,6 +158,8 @@ class Engine:
self.curr_speech = None
self.curr_diskid = None
+ def init_empty(self, enc):
+ self.enc = enc
def parse_ini(self, f):
# parse ini settings
@@ -205,8 +207,8 @@ class Engine:
return res, resord
def load_data(self, folder, enc):
+ self.init_empty(enc)
self.fman = FileManager(folder)
- self.enc = enc
# load PARTS.INI
pf = self.fman.find_path("parts.ini")
if pf:
@@ -302,16 +304,26 @@ class Engine:
# load dialogs
self.load_dialogs()
- def load_script(self):
+ def load_script(self, scrname = None, bkgname = None, resname = None):
self.objects = []
self.scenes = []
self.obj_idx = {}
self.scn_idx = {}
-
- try:
- data = self.fman.read_file(self.curr_path + "script.dat")
- except:
- raise EngineError("Can't open SCRIPT.DAT")
+
+ if scrname is None:
+ try:
+ data = self.fman.read_file(self.curr_path + "script.dat")
+ except:
+ raise EngineError("Can't open SCRIPT.DAT")
+ else:
+ try:
+ f = open(scrname, "rb")
+ except:
+ raise EngineError("Can't open SCRIPT.DAT")
+ try:
+ data = f.read()
+ finally:
+ f.close()
num_obj, num_scn = struct.unpack_from("<II", data[:8])
off = 8
def read_rec(off):
@@ -348,8 +360,25 @@ class Engine:
self.scenes.append(scn)
self.scn_idx[scn.idx] = scn
- data = self.fman.read_file(self.curr_path + "backgrnd.bg")
- num_rec = struct.unpack_from("<I", data[:4])[0]
+ if bkgname is None:
+ try:
+ data = self.fman.read_file(self.curr_path + "backgrnd.bg")
+ except:
+ data = None
+ else:
+ try:
+ f = open(bkgname, "rb")
+ except:
+ data = None
+ try:
+ data = f.read()
+ finally:
+ f.close()
+
+ if data:
+ num_rec = struct.unpack_from("<I", data[:4])[0]
+ else:
+ num_rec = 0
off = 4
for i in range(num_rec):
scn_ref, num_ref = struct.unpack_from("<HI", data[off:off + 6])
@@ -371,9 +400,25 @@ class Engine:
raise EngineError("DEBUG: Scene ref 0x{:x} not found".\
format(obj[0]))
- f = self.fman.read_file_stream(self.curr_path + "resource.qrc")
- self.res, self.resord = self.parse_res(f)
- f.close()
+ if resname is None:
+ try:
+ f = self.fman.read_file_stream(self.curr_path + "resource.qrc")
+ except:
+ f = None
+ else:
+ try:
+ f = open(resname, "rb")
+ except:
+ f = None
+ try:
+ if f:
+ self.res, self.resord = self.parse_res(f)
+ else:
+ self.res = {}
+ self.resord = []
+ finally:
+ if f:
+ f.close()
def load_names(self):
self.names = {}
Commit: 668a70651719f24ba4be0bf909aeeaf200349dfd
https://github.com/scummvm/scummvm-tools/commit/668a70651719f24ba4be0bf909aeeaf200349dfd
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Compiler for SCRIPT.DAT
Changed paths:
engines/petka/p12script.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
index 380e5cda9..2325e729b 100755
--- a/engines/petka/p12script.py
+++ b/engines/petka/p12script.py
@@ -10,10 +10,13 @@ import io
import hashlib
import petka
+import petka.engine
APPNAME = "P1&2 Compiler and decompiler"
VERSION = "v0.3 2014-06-01"
+class ScriptSyntaxError(Exception): pass
+
def find_in_folder(folder, name, ifnot = True):
for item in os.listdir(folder):
if item.upper() == name.upper():
@@ -23,170 +26,656 @@ def find_in_folder(folder, name, ifnot = True):
else:
return None
-# ===========================================================================
-# decompile utils
-# ===========================================================================
-def fmtnum16(num):
- if num < 10:
- return "{}".format(num)
- elif num == 0xffff:
- return "-1"
- else:
- return "0x{:x}".format(num)
+class P12Compiler:
+ def __init__(self):
+ pass
+
+ # =======================================================================
+ # compiler utils
+ # =======================================================================
-def fmtnum32(num):
- if num < 10:
- return "{}".format(num)
- elif num == 0xffffffff:
- return "-1"
- else:
- return "0x{:x}".format(num)
+ def tokenizer(self, source, enc):
+ for lineno, line in enumerate(source.readlines(), 1):
+ line = line.decode(enc or "UTF-8").strip()
+ # eliminate comment
+ nline = []
+ nmode = 0 # 0 - common, 2 - in string
+ nitem = ""
+ nitemesc = False
+ for ch in line:
+ if nmode == 1:
+ if nitemesc:
+ nitem += ch
+ nitemesc = False
+ else:
+ if ch == "\\":
+ # esc-sequence
+ nitemesc = True
+ continue
+ elif ch == "\"":
+ nitem += ch
+ nmode = 0
+ if nitem[:1] == nitem[-1:] == "\"":
+ nitem = nitem[1:-1]
+ nline.append(nitem)
+ nitem = ""
+ nitemesc = False
+ continue
+ nitem += ch
+ else:
+ if ch == "\"":
+ nmode = 1
+ elif ch == "#":
+ break
+ elif ch == " " or ch == "\t":
+ if len(nitem) > 0:
+ nline.append(nitem)
+ nitem = ""
+ continue
+ nitem += ch
+
+ if len(nitem) > 0:
+ nline.append(nitem)
+
+ yield lineno, nline
+
+
+ def check8(self, value, name, lineno):
+ if value == -1:
+ return 0xff
+ if value < 0:
+ raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
+ "small - {}".format(lineno, name, value))
+ if value > 0xff:
+ raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
+ "big - {} > 0xff".format(lineno, name, value))
+ return value
+
+ def check16(self, value, name, lineno):
+ if value == -1:
+ return 0xffff
+ if value < 0:
+ raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
+ "small - {}".format(lineno, name, value))
+ if value > 0xffff:
+ raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
+ "big - {} > 0xffff".format(lineno, name, value))
+ return value
-def fmtop(num):
- if num in petka.OPCODES:
- return petka.OPCODES[num][0]
- return "0x{:x}".format(num)
-
-def fmtdlgop(num):
- if num in petka.DLGOPS:
- return petka.DLGOPS[num][0]
- return "0x{:x}".format(num)
-
-def escstr(value):
- return value.replace("\\", "\\\\").replace("\"", "\\\"")
-
-# ===========================================================================
-# decompile SCRIPT.DAT
-# ===========================================================================
-def pretty_print_scr(pe, name, stream, enc = None, decsort = False):
- def pprint(msg):
- if stream is None:
- print(msg)
+ def check32(self, value, name, lineno):
+ if value == -1:
+ return 0xffffffff
+ if value < 0:
+ raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
+ "small - {}".format(lineno, name, value))
+ if value > 0xffffffff:
+ raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
+ "big - {} > 0xffffffff".format(lineno, name, value))
+ return value
+
+ def convertnum(self, value):
+ num = None
+ if value[:2].upper() == "0X":
+ try:
+ num = int(value[2:], 16)
+ except:
+ pass
+ else:
+ try:
+ num = int(value, 10)
+ except:
+ pass
+ return num
+
+ def checkusedid(self, ident, lineno):
+ if ident in self.usedid:
+ raise ScriptSyntaxError("Error at {}: identificator \"{}\" "\
+ "already used at line {}".format(lineno, ident, \
+ self.usedid[ident][0]))
+ self.usedid[ident] = [lineno, None]
+
+ def setidentvalue(self, ident, value):
+ if self.usedid[ident][1] is None:
+ self.usedid[ident][1] = value
else:
- stream.write((msg + "\n").encode(enc or "UTF-8"))
-
- # define lists of used items
- used_obj = []
- used_res = []
-
- def fmtfor(num, objid):
- if num == objid:
- return "THIS"
- if num in pe.obj_idx:
- return "obj_{}".format(num)
- if num in pe.scn_idx:
- return "scene_{}".format(num)
- return fmtnum16(num)
+ raise ScriptSyntaxError("Redefine value for \"{}\" ({}) from "\
+ "\"{}\" to \"{}\"".format(ident, self.usedid[ident][0], \
+ self.usedid[ident][0], value))
- def printres(resid):
- pprint("RES res_{} 0x{:x} \"{}\"".format(resid, resid,
- escstr(pe.res[resid])))
- pprint("")
-
- def printrescheck(resid, opcode):
- tp = petka.OPCODES.get(opcode, ("", 0))[1]
- if tp == 1 and resid in pe.res:
- if resid in used_res:
- return
- used_res.append(resid)
- printres(resid)
+ def getidentvalue(self, ident):
+ return self.usedid[ident][1]
+
+ def checkident(self, ident, name, lineno):
+ if ident.upper() in self.reservedid:
+ raise ScriptSyntaxError("Error at {}: identificator \"{}\" "\
+ "in {} forbidden".format(lineno, ident, name))
+ if ident not in self.usedid:
+ raise ScriptSyntaxError("Error at {}: identificator \"{}\" "\
+ "in {} not found".format(lineno, ident, name))
+ if self.usedid[ident][1] is None:
+ raise ScriptSyntaxError("Error at {}: identificator \"{}\" "\
+ "in {} has no value (internal error)".\
+ format(lineno, ident, name))
- def printitem(item, itemtype):
- pprint("{} {}_{} 0x{:x} \"{}\"".format(itemtype.upper(), itemtype,
- item.idx, item.idx, escstr(item.name)))
-
- # sub objects
- if itemtype == "scene":
- if len(item.refs) == 0:
- pprint(" ZEROREF")
- for obj, a1, a2, a3, a4, a5 in item.refs:
- if obj.idx in pe.obj_idx:
- ref = "obj_{}".format(obj.idx)
- elif obj.idx in pe.scn_idx:
- ref = "scene_".format(obj.idx)
- else:
- pprint(" # unknown reference to 0x{:x}".format(
- obj.idx))
- ref = "0x{:x}".format(obj.idx)
- pprint(" REF {} {} {} {} {} {}".format(ref, fmtnum32(a1),
- fmtnum32(a2), fmtnum32(a3),
- fmtnum32(a4), fmtnum32(a5)))
+ def checkstruct(self, name, struct, data, lineno):
+ try:
+ struct.build(data)
+ except Exception as e:
+ msg = "Internal error {}".format(name)
+ if lineno is not None:
+ msg += ", at line {}".format(lineno)
+ raise ScriptSyntaxError(msg + "\n" + str(e))
+
+ def convertargs(self, fmt, args, lineno):
+ # fmt = [(name1, check1, withident),]
+ pargs = []
+ argnum = [None] * len(args)
+ for i, arg in enumerate(args):
+ argnum[i] = self.convertnum(arg)
+ if argnum[i] is None:
+ if not fmt[i][2]:
+ raise ScriptSyntaxError("Error at {}: bad number for {}".\
+ format(lineno, fmt[i][0]))
+ self.checkident(arg, fmt[i][0], lineno)
+ argnum[i] = self.getidentvalue(arg)
+ argnum[i] = fmt[i][1](argnum[i], fmt[i][0], lineno)
+ return argnum
+
+ # =======================================================================
+ # compile SCRIPT.DAT
+ # =======================================================================
+
+ def compile_script(self, source, destfolder, enc = None, \
+ st_scr = None, st_bkg = None, st_res = None):
+
+ pe = petka.Engine()
+ pe.init_empty("cp1251")
- for act in item.acts:
- actif = ""
- if act.act_status != 0xff or act.act_ref != 0xffff:
- actif = " 0x{:02x} ".format(act.act_status)
- if act.act_ref == item.idx:
- actif += "THIS"
+ mode = 0 # 0 - common, 1 - object/scene, 2 - on
+ mode1tp = None
+
+ # used identificators
+ self.usedid = {}
+ # compiled resources
+ compres = []
+ # compiled obj
+ compobj = []
+ # compled scenes
+ compscene = []
+ # current item
+ compitem = None
+ # obj/scene used numbers
+ compitemused = {}
+ # current action
+ compact = None
+
+ revOPS = {}
+ for ok, ov in petka.OPCODES.items():
+ revOPS[ov[0]] = ok
+ self.reservedid = ["THIS", "OBJ", "ENDOBJ", "SCENE", "ENDSCENE", \
+ "RES", "REF", "ON", "ENDON"] + list(revOPS.keys())
+
+ for lineno, tokens in self.tokenizer(source, enc):
+ if len(tokens) == 0:
+ continue
+ if mode == 0:
+ # accept: RES, OBJ, SCENE
+ cmd = tokens[0].upper()
+ if cmd == "RES":
+ if len(tokens) != 4:
+ raise ScriptSyntaxError("Error at {}: RES syntax "\
+ "error".format(lineno, cmd))
+ self.checkusedid(tokens[1], lineno)
+ compres.append((lineno, tokens[1], \
+ tokens[2], tokens[3]))
+ elif cmd == "OBJ" or cmd == "SCENE":
+ # object / scene
+ mode = 1
+ mode1tp = cmd
+ # check syntax
+ if len(tokens) != 4:
+ raise ScriptSyntaxError("Error at {}: {} syntax "\
+ "error".format(lineno, cmd))
+ self.checkusedid(tokens[1], lineno)
+ num = self.convertnum(tokens[2])
+ if num is not None:
+ if num in compitemused:
+ raise ScriptSyntaxError("Error at {}: {} "\
+ "number {} already used at {}".format(\
+ lineno, cmd.lower(), num, \
+ compitemused[num]))
+ else:
+ compitemused[num] = lineno
+ num = self.check16(num, "{} number".format(cmd.lower()),
+ lineno)
+ self.setidentvalue(tokens[1], num)
+ else:
+ raise ScriptSyntaxError("Error at {}: {} number bad "\
+ "format \"{}\" ".format(lineno, cmd.lower(),
+ tokens[2]))
+ compitem = {"tp": cmd, "lineno": lineno, \
+ "ident": tokens[1], "num": num, \
+ "name": tokens[3], "ref": None, "acts": []}
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown syntax "\
+ "\"{}\"".format(lineno, cmd))
+ elif mode == 1:
+ # accept: REF, ON, ENDOBJ, ENDSCENE
+ cmd = tokens[0].upper()
+ if cmd == "REF" and mode1tp == "SCENE":
+ if compitem["ref"] is None:
+ compitem["ref"] = []
+ # check format
+ if len(tokens) < 4 or len(tokens) > 7:
+ raise ScriptSyntaxError("Error at {}: unknown REF "\
+ "syntax in {}".format(lineno, mode1tp))
+ while len(tokens) < 7:
+ tokens.append("-1")
+ compitem["ref"].append([lineno] + tokens[1:])
+ elif cmd == "ZEROREF" and mode1tp == "SCENE":
+ # zero rererence at all
+ if compitem["ref"] is not None:
+ # can't empty any
+ raise ScriptSyntaxError("Error at {}: ref already "\
+ "specified".format(lineno))
+ compitem["ref"] = []
+ elif cmd == "ON":
+ # on action
+ if len(tokens) != 2 and len(tokens) != 4:
+ raise ScriptSyntaxError("Error at {}: unknown ON "\
+ "syntax in {}".format(lineno, mode1tp))
+ son = self.convertnum(tokens[1])
+ if son is None:
+ if tokens[1].upper() in revOPS:
+ son = revOPS[tokens[1].upper()]
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown ON "\
+ "OPREF \"{}\" in {}".\
+ format(lineno, tokens[1], mode1tp))
+ else:
+ son = self.check16(son, "ON opref", lineno)
+ if len(tokens) == 2:
+ tokens += ["-1", "-1"]
+ status = self.convertnum(tokens[2])
+ if status is None:
+ raise ScriptSyntaxError("Error at {}: unknown ON "\
+ "status \"{}\" in {}".\
+ format(lineno, tokens[2], mode1tp))
+ status = self.check8(status, "ON status", lineno)
+ compact = {"son": son, "ops": [], "status": status, \
+ "sonref": tokens[3], "lineno": lineno}
+ mode = 2
+ elif cmd == "END" + mode1tp and len(tokens) == 1:
+ if mode1tp == "OBJ":
+ compobj.append(compitem)
+ else:
+ compscene.append(compitem)
+ compitem = None
+ # return
+ mode = 0
else:
- actif += fmtnum16(act.act_ref)
- pprint(" ON {}{}".format(fmtop(act.act_op), actif))
- # list actions
- for op in act.ops:
- if op.op_arg1 in pe.res and \
- petka.OPCODES.get(op.op_code, ["", 0])[1] == 1:
- res = "res_{}".format(op.op_arg1)
+ raise ScriptSyntaxError("Error at {}: unknown syntax "\
+ "\"{}\" in {}".\
+ format(lineno, cmd, mode1tp))
+ elif mode == 2:
+ # accept: ENDON, OPCODE, any number
+ cmd = tokens[0].upper()
+ if cmd == "ENDON" and len(tokens) == 1:
+ compitem["acts"].append(compact)
+ compact = None
+ mode = 1
else:
- res = fmtnum16(op.op_arg1)
- pprint(" {} {} {} {} {}".format(fmtop(op.op_code),
- fmtfor(op.op_ref, item.idx), res,
- fmtnum16(op.op_arg2),
- fmtnum16(op.op_arg3)))
- pprint(" ENDON")
+ # check format
+ if len(tokens) < 2 or len(tokens) > 5:
+ raise ScriptSyntaxError("Error at {}: unknown OP "\
+ "syntax in {}".format(lineno, mode1tp))
+ while len(tokens) < 5:
+ tokens.append("-1")
+ op = {}
+ if cmd in revOPS:
+ # opcode
+ opcode = revOPS[cmd]
+ else:
+ opcode = self.convertnum(cmd)
+ if opcode is None:
+ raise ScriptSyntaxError("Error at {}: unknown OP "\
+ "\"{}\" in ON".\
+ format(lineno, cmd))
+ opcode = self.check16(opcode, "opcode", lineno)
+ compact["ops"].append({"opcode": opcode, "lineno": lineno, \
+ "obj_ref": tokens[1], "args": tokens[2:]})
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown parser mode {}".\
+ format(lineno, mode))
+
+ # check unclosed objects
+ if mode != 0:
+ raise ScriptSyntaxError("Error at {}: unfinished structure".\
+ format(lineno))
- pprint("END{} # {}_{}".format(itemtype.upper(), itemtype, item.idx))
- pprint("")
+ # second stage - RES
+ # 1. capture res with numbers
+ resused = {}
+ for lineno, ident, resnum, path in compres:
+ num = self.convertnum(resnum)
+ if num is not None:
+ if num in resused:
+ raise ScriptSyntaxError("Error at {}: RES number {} "\
+ "already used at {}".format(lineno, num, resused[num]))
+ else:
+ resused[num] = lineno
+ num = self.check16(num, "RES id", lineno)
+ self.setidentvalue(ident, num)
+ #elif resnum == "_":
+ # pass
+ else:
+ raise ScriptSyntaxError("Error at {}: RES number bad "\
+ "format \"{}\" ".format(lineno, resnum))
+ # disabled, unsure about valid numbers range
+ # 2. autonumber rest
+ #autoresnum = 0xfffe
+ #for lineno, ident, resnum, path in compres:
+ # if resnum == "_":
+ # while autoresnum > 0:
+ # num = autoresnum
+ # if num in resused:
+ # autoresnum -= 1
+ # continue
+ # else:
+ # self.setidentvalue(ident, num)
+ # resused[num] = lineno
+ # break
+ # if autoresnum <= 0:
+ # raise ScriptSyntaxError("Error at {}: out of resources "\
+ # "number".format(lineno))
+ # 3. compile
+
+ if destfolder is not None:
+ f = open(os.path.join(destfolder, "resource.qrc"), "wb")
+ else:
+ f = st_res
+ try:
+ def writer(msg):
+ f.write((msg + "\r\n").encode("CP1251"))
+ writer("")
+ for lineno, ident, resnum, path in compres:
+ writer("{:d} == {}".format(self.getidentvalue(ident), path))
+ finally:
+ if destfolder is not None:
+ f.close()
+ print("RESOURCE.QRC saved: {} items".format(len(resused)))
+
+ # second stage - OBJ
+ def makerec(citem):
+ item = petka.engine.ScrObject(citem["num"], citem["name"])
+ item.acts = []
+ for act in citem["acts"]:
+ if act["sonref"].upper() == "THIS":
+ sonref = item.idx
+ else:
+ sonref = self.convertnum(act["sonref"])
+ if sonref is not None:
+ # direct number
+ sonref = self.check16(sonref, "ON object ref",
+ act["lineno"])
+ else:
+ # get by ident
+ self.checkident(act["sonref"], "ON object ref", \
+ act["lineno"])
+ sonref = self.getidentvalue(act["sonref"])
+ onrec = petka.engine.ScrActObject(act["son"],
+ act["status"], sonref)
+ onrec.ops = []
+ for op in act["ops"]:
+ # object ref
+ if op["obj_ref"].upper() == "THIS":
+ opref = item.idx
+ else:
+ opref = self.convertnum(op["obj_ref"])
+ if opref is not None:
+ # direct number
+ opref = self.check16(opref, "OP object", op["lineno"])
+ else:
+ # get by ident
+ self.checkident(op["obj_ref"], "OP object", \
+ op["lineno"])
+ opref = self.getidentvalue(op["obj_ref"])
+ # arguments
+ fmt = []
+ for i in range(3):
+ fmt.append(("OP argument {}".format(i + 1), \
+ self.check16, True))
+ argnum = self.convertargs(fmt, op["args"], op["lineno"])
+ oprec = petka.engine.ScrOpObject(opref, op["opcode"],
+ argnum[0], argnum[1], argnum[2])
+ onrec.ops.append(oprec)
+ item.acts.append(onrec)
+ return item
+
+ for citem in compobj:
+ objrec = makerec(citem)
+ pe.objects.append(objrec)
+ pe.obj_idx[objrec.idx] = objrec
+
+ # second stage - SCENE
+ backgrnd = []
+ num_bkg = 0
+ for citem in compscene:
+ scenerec = makerec(citem)
+ pe.scenes.append(scenerec)
+
+ if citem["ref"] is not None:
+ scenerec.refs = []
+ num_bkg += 1
+ for ref in citem["ref"]:
+ fmt = [("REF object", self.check16, True)]
+ for i in range(5):
+ fmt.append(("REF argument {}".format(i + 1), \
+ self.check32, True))
+ argnum = self.convertargs(fmt, ref[1:], ref[0])
+ # build REF
+ if argnum[0] not in pe.obj_idx:
+ raise ScriptSyntaxError("Error at {}: referenced "
+ "object 0x{:x} not found".\
+ format(lineno, argnum[0]))
+ scenerec.refs.append([pe.obj_idx[argnum[0]], argnum[1],
+ argnum[2], argnum[3], argnum[4], argnum[5]])
+
+
+ if destfolder is not None:
+ f = open(os.path.join(destfolder, "backgrnd.bg"), "wb")
+ else:
+ f = st_bkg
+ try:
+ pe.write_backgrnd(f)
+ finally:
+ if destfolder is not None:
+ f.close()
+ print("BACKGRND.BG saved: {} items".format(num_bkg))
+
+ if destfolder is not None:
+ f = open(os.path.join(destfolder, "script.dat"), "wb")
+ else:
+ f = st_scr
+ try:
+ pe.write_script(f)
+ finally:
+ if destfolder is not None:
+ f.close()
+ print("SCRIPT.DAT saved: {} objects, {} scenes".\
+ format(len(pe.objects), len(pe.scenes)))
+
+ # =======================================================================
+ # decompile utils
+ # =======================================================================
+ def fmtnum16(self, num):
+ if num < 10:
+ return "{}".format(num)
+ elif num == 0xffff:
+ return "-1"
+ else:
+ return "0x{:x}".format(num)
+
+ def fmtnum32(self, num):
+ if num < 10:
+ return "{}".format(num)
+ elif num == 0xffffffff:
+ return "-1"
+ else:
+ return "0x{:x}".format(num)
+
+ def fmtop(self, num):
+ if num in petka.OPCODES:
+ return petka.OPCODES[num][0]
+ return "0x{:x}".format(num)
+
+ def fmtdlgop(self, num):
+ if num in petka.DLGOPS:
+ return petka.DLGOPS[num][0]
+ return "0x{:x}".format(num)
+
+ def escstr(self, value):
+ return value.replace("\\", "\\\\").replace("\"", "\\\"")
+
+ # =======================================================================
+ # decompile SCRIPT.DAT
+ # =======================================================================
+ def pretty_print_scr(self, scrname, stream, enc = None, decsort = False):
+ def pprint(msg):
+ if stream is None:
+ print(msg)
+ else:
+ stream.write((msg + "\n").encode(enc or "UTF-8"))
+
+ pe = petka.Engine()
+ pe.init_empty("cp1251")
+ bkgname = find_in_folder(os.path.dirname(scrname), "backgrnd.bg")
+ resname = find_in_folder(os.path.dirname(scrname), "resource.qrc")
+ pe.load_script(scrname, bkgname, resname)
+
+ # define lists of used items
+ used_obj = []
+ used_res = []
+
+ def fmtfor(num, objid):
+ if num == objid:
+ return "THIS"
+ if num in pe.obj_idx:
+ return "obj_{}".format(num)
+ if num in pe.scn_idx:
+ return "scene_{}".format(num)
+ return self.fmtnum16(num)
- pprint("# Decompile SCRIPT \"{}\"".format(name))
- pprint("# Version: {}".format(VERSION))
- pprint("# Encoding: {}".format(enc))
-
- if decsort:
- for idx, scene in enumerate(pe.scenes):
- pprint("# Scene {} / {}".format(idx + 1, len(pe.scenes)))
- # display used objects
- if len(scene.idx.refs) > 0:
- pprint("# referenced objects {}:".format(len(scene.refs)))
- for ref in scene.refs:
- if ref[0].idx in used_obj:
- pprint("# object 0x{:x} already defined".\
- format(ref[0].idx))
- continue
- used_obj.append(ref[0].idx)
- if ref[0].idx in pe.obj_idx:
- for act in ref[0].acts_array:
- for op in act.ops_array:
- printrescheck(op.op_arg1, op.op_code)
- printitem(obj, "obj")
- else:
- pprint("# No referenced objects")
- # display res
- for act in scene.acts:
+ def printres(resid):
+ pprint("RES res_{} 0x{:x} \"{}\"".format(resid, resid,
+ self.escstr(pe.res[resid])))
+ pprint("")
+
+ def printrescheck(resid, opcode):
+ tp = petka.OPCODES.get(opcode, ("", 0))[1]
+ if tp == 1 and resid in pe.res:
+ if resid in used_res:
+ return
+ used_res.append(resid)
+ printres(resid)
+
+ def printitem(item, itemtype):
+ pprint("{} {}_{} 0x{:x} \"{}\"".format(itemtype.upper(), itemtype,
+ item.idx, item.idx, self.escstr(item.name)))
+
+ # sub objects
+ if itemtype == "scene":
+ if len(item.refs) == 0:
+ pprint(" ZEROREF")
+ for obj, a1, a2, a3, a4, a5 in item.refs:
+ if obj.idx in pe.obj_idx:
+ ref = "obj_{}".format(obj.idx)
+ elif obj.idx in pe.scn_idx:
+ ref = "scene_".format(obj.idx)
+ else:
+ pprint(" # unknown reference to 0x{:x}".format(
+ obj.idx))
+ ref = "0x{:x}".format(obj.idx)
+ pprint(" REF {} {} {} {} {} {}".format(ref,
+ self.fmtnum32(a1), self.fmtnum32(a2),
+ self.fmtnum32(a3), self.fmtnum32(a4),
+ self.fmtnum32(a5)))
+
+ for act in item.acts:
+ actif = ""
+ if act.act_status != 0xff or act.act_ref != 0xffff:
+ actif = " 0x{:02x} ".format(act.act_status)
+ if act.act_ref == item.idx:
+ actif += "THIS"
+ else:
+ actif += self.fmtnum16(act.act_ref)
+ pprint(" ON {}{}".format(self.fmtop(act.act_op), actif))
+ # list actions
for op in act.ops:
- printrescheck(op.op_arg1, op.op_code)
- printitem(scene, "scene")
- # list unused
- msg = False
- for obj in pe.objects:
- if obj.idx in used_obj: continue
- if not msg:
- pprint("# Note: Following objects not listed anywhere")
- msg = True
- printitem(obj, "OBJ")
- msg = False
- for res in self.res:
- if res in used_res: continue
- if not msg:
- pprint("# Note: Following resources not listed anywhere")
- msg = True
- printres(res)
- else:
- for obj in pe.objects:
- printitem(obj, "obj")
- for scene in pe.scenes:
- printitem(scene, "scene")
- for res in pe.resord:
- printres(res)
+ if op.op_arg1 in pe.res and \
+ petka.OPCODES.get(op.op_code, ["", 0])[1] == 1:
+ res = "res_{}".format(op.op_arg1)
+ else:
+ res = self.fmtnum16(op.op_arg1)
+ pprint(" {} {} {} {} {}".format(self.fmtop(op.op_code),
+ fmtfor(op.op_ref, item.idx), res,
+ self.fmtnum16(op.op_arg2),
+ self.fmtnum16(op.op_arg3)))
+ pprint(" ENDON")
+
+ pprint("END{} # {}_{}".format(itemtype.upper(), itemtype, item.idx))
+ pprint("")
+
+ pprint("# Decompile SCRIPT \"{}\"".format(scrname))
+ pprint("# Version: {}".format(VERSION))
+ pprint("# Encoding: {}".format(enc))
+
+ if decsort:
+ for idx, scene in enumerate(pe.scenes):
+ pprint("# Scene {} / {}".format(idx + 1, len(pe.scenes)))
+ # display used objects
+ if len(scene.idx.refs) > 0:
+ pprint("# referenced objects {}:".format(len(scene.refs)))
+ for ref in scene.refs:
+ if ref[0].idx in used_obj:
+ pprint("# object 0x{:x} already defined".\
+ format(ref[0].idx))
+ continue
+ used_obj.append(ref[0].idx)
+ if ref[0].idx in pe.obj_idx:
+ for act in ref[0].acts_array:
+ for op in act.ops_array:
+ printrescheck(op.op_arg1, op.op_code)
+ printitem(obj, "obj")
+ else:
+ pprint("# No referenced objects")
+ # display res
+ for act in scene.acts:
+ for op in act.ops:
+ printrescheck(op.op_arg1, op.op_code)
+ printitem(scene, "scene")
+ # list unused
+ msg = False
+ for obj in pe.objects:
+ if obj.idx in used_obj: continue
+ if not msg:
+ pprint("# Note: Following objects not listed anywhere")
+ msg = True
+ printitem(obj, "OBJ")
+ msg = False
+ for res in self.res:
+ if res in used_res: continue
+ if not msg:
+ pprint("# Note: Following resources not listed anywhere")
+ msg = True
+ printres(res)
+ else:
+ for obj in pe.objects:
+ printitem(obj, "obj")
+ for scene in pe.scenes:
+ printitem(scene, "scene")
+ for res in pe.resord:
+ printres(res)
# check if file already exists and flag for overwrite not set
def ckeckoverwrite(fn, args):
@@ -204,6 +693,7 @@ def checksame(f1, n1, f2, n2):
return True
return False
+
def action_dec(args):
print("Decompile SCRIPT.DAT file")
destpath = args.destpath
@@ -223,20 +713,89 @@ def action_dec(args):
if args.decompile_sorted:
print("Flag decompile_sorted enabled")
- pe = petka.Engine()
- pe.init_empty("cp1251")
- bkgname = find_in_folder(os.path.dirname(args.sourcepath), "backgrnd.bg")
- resname = find_in_folder(os.path.dirname(args.sourcepath), "resource.qrc")
- pe.load_script(args.sourcepath, bkgname, resname)
+ dcs = P12Compiler()
if destpath:
f = open(destpath, "wb")
try:
- pretty_print_scr(pe, args.sourcepath, f, enc = encoding, \
+ dcs.pretty_print_scr(args.sourcepath, f, enc = encoding, \
decsort = args.decompile_sorted)
finally:
f.close()
else:
- pretty_print_scr(pe, args.sourcepath, None)
+ dcs.pretty_print_scr(args.sourcepath, None)
+
+def action_comp(args):
+ print("Compile SCRIPT.DAT file")
+ print("Input:\t{}".format(args.sourcepath))
+ print("Output:\t{}".format(args.destfolder))
+ print("Enc:\t{}".format(args.encoding or "UTF-8"))
+
+ dcs = P12Compiler()
+ if os.path.exists(args.destfolder) and not args.fo:
+ cnt = 0
+ lst = ["script.dat", "backgrnd.bg", "resource.qrc"]
+ for item in lst:
+ if find_in_folder(args.destfolder, item, False):
+ print("Error: destination file \"{}\" already "\
+ "exists, use -fo to overwrite".format(item))
+ return
+
+ if not os.path.exists(args.destfolder):
+ os.makedirs(args.destfolder)
+ f = open(args.sourcepath, "rb")
+ try:
+ dcs.compile_script(f, args.destfolder, args.encoding)
+ except ScriptSyntaxError as e:
+ if args.trace_error:
+ traceback.print_exc()
+ print(e, file = sys.stderr)
+ finally:
+ f.close()
+
+def internaltest(folder):
+ # unpack testdata.7z
+ test_arr = [
+ "p1demo",
+ "p1-0", "p1-1", "p1-2", "p1-3",
+ "p2-0", "p2-1", "p2-2"
+ ]
+ def compare(fn, mem):
+ f = open(fn, "rb")
+ hf = hashlib.md5()
+ try:
+ hf.update(f.read())
+ finally:
+ f.close()
+ mem.seek(0)
+ hm = hashlib.md5()
+ hm.update(mem.read())
+ return hm.hexdigest() == hf.hexdigest()
+
+ for test in test_arr:
+ print("=== Test: " + test + " ===")
+ testbase = os.path.join(folder, test)
+ path = find_in_folder(testbase, "script.dat")
+ dcs = P12Compiler()
+ mems = io.BytesIO()
+ dcs.pretty_print_scr(path, mems)
+ print("Decompiled script:", mems.tell())
+ # compile back
+ memscr = io.BytesIO()
+ membkg = io.BytesIO()
+ memres = io.BytesIO()
+ mems.seek(0)
+ ndcs = P12Compiler()
+ ndcs.compile_script(mems, None, None, \
+ memscr, membkg, memres)
+ # compare
+ if not compare(path, memscr):
+ print("SCRIPT.DAT - mismatch")
+ break
+ if not compare(find_in_folder(testbase, "backgrnd.bg"), membkg):
+ print("BACKGRND.BG - mismatch")
+ break
+
+ print("All ok")
def action_version(args):
print("Version: " + VERSION)
@@ -271,6 +830,19 @@ def main():
parser_dec.add_argument('sourcepath', help = "path to SCRIPT.DAT file")
parser_dec.set_defaults(func = action_dec)
+ # compile - <source.txt> <destination folder> [--enc <encoding>]
+ parser_comp = subparsers.add_parser("compile", aliases = ['c'], \
+ help = "compile script.dat")
+ parser_comp.add_argument('-fo', action = 'store_true', \
+ help = "force overwrite existing output files")
+ parser_comp.add_argument('-e', "--enc", action = 'store', \
+ dest = "encoding", help = "output encoding (default: UTF-8)")
+ parser_comp.add_argument('-te', "--trace-error", action = 'store_true', \
+ help = "trace syntax error")
+ parser_comp.add_argument('sourcepath', help = "path to SOURCE.TXT file")
+ parser_comp.add_argument('destfolder', help = "path to output folder")
+ parser_comp.set_defaults(func = action_comp)
+
# version
parser_version = subparsers.add_parser("version", help = "program version")
parser_version.set_defaults(func = action_version)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 551b3f243..5fef532f8 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -160,6 +160,10 @@ class Engine:
def init_empty(self, enc):
self.enc = enc
+ self.objects = []
+ self.scenes = []
+ self.obj_idx = {}
+ self.scn_idx = {}
def parse_ini(self, f):
# parse ini settings
@@ -555,4 +559,32 @@ class Engine:
dlg.ops = oparr
finally:
f.close()
+
+ def write_script(self, f):
+ f.write(struct.pack("<II", len(self.objects), len(self.scenes)))
+
+ def write_rec(rec):
+ ename = rec.name.encode(self.enc)
+ f.write(struct.pack("<HI", rec.idx, len(ename)))
+ f.write(ename)
+ f.write(struct.pack("<I", len(rec.acts)))
+ for act in rec.acts:
+ f.write(struct.pack("<HBHI", act.act_op, act.act_status,
+ act.act_ref, len(act.ops)))
+ for op in act.ops:
+ f.write(struct.pack("<5H", op.op_ref, op.op_code,
+ op.op_arg1, op.op_arg2, op.op_arg3))
+
+ for rec in self.objects + self.scenes:
+ write_rec(rec)
+
+ def write_backgrnd(self, f):
+ lst = [scn for scn in self.scenes if scn.refs is not None]
+ f.write(struct.pack("<I", len(lst)))
+ for scn in lst:
+ f.write(struct.pack("<HI", scn.idx, len(scn.refs)))
+ for ref in scn.refs:
+ f.write(struct.pack("<H5I", ref[0].idx, ref[1], ref[2],
+ ref[3], ref[4], ref[5]))
+
Commit: c4a8a5035025f57e04957161eb6c49922cbd5b01
https://github.com/scummvm/scummvm-tools/commit/c4a8a5035025f57e04957161eb6c49922cbd5b01
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Decompiler for DIALOGUE.FIX and .LOD
Changed paths:
engines/petka/dist/setup.py
engines/petka/p12script.py
engines/petka/petka/engine.py
diff --git a/engines/petka/dist/setup.py b/engines/petka/dist/setup.py
index fb31ef8dc..10d321aa4 100644
--- a/engines/petka/dist/setup.py
+++ b/engines/petka/dist/setup.py
@@ -17,11 +17,14 @@ executables = [
Executable('p12explore.py',
base = 'Win32GUI',
targetName = "p12explore.exe")
+ Executable('p12script.py',
+ base = 'Console',
+ targetName = "p12script.exe")
]
setup(name='p12explore',
- version = '0.2',
- description = 'Petka 1&2 explorer',
+ version = '0.3',
+ description = 'Petka 1&2 utilities',
author = "romiq.kh at gmail.com, https://bitbucket.org/romiq/p12simtran",
options = dict(build_exe = buildOptions),
executables = executables)
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
index 2325e729b..a8f161889 100755
--- a/engines/petka/p12script.py
+++ b/engines/petka/p12script.py
@@ -677,6 +677,133 @@ class P12Compiler:
for res in pe.resord:
printres(res)
+ # =======================================================================
+ # decompile DIALOGUE.FIX
+ # =======================================================================
+ def pretty_print_dlg(self, fixname, stream, enc = None, verbose = False):
+ def pprint(msg):
+ if stream is None:
+ print(msg)
+ else:
+ stream.write((msg + "\n").encode(enc or "UTF-8"))
+
+ pe = petka.Engine()
+ pe.init_empty("cp1251")
+ lodname = find_in_folder(os.path.dirname(fixname), "dialogue.lod")
+ pe.load_dialogs(fixname, lodname, True)
+
+ pprint("# Decompile DIALOGUE \"{}\"".format(fixname))
+ pprint("# Version: {}".format(VERSION))
+ pprint("# Encoding: {}".format(enc))
+
+ for msg in pe.msgs:
+ pprint("# {} = 0x{:x}".format(msg.idx, msg.idx))
+ pprint("MSG msg_{} \"{}\" 0x{:x} 0x{:x} 0x{:x}".format(\
+ msg.idx, msg.wav, msg.arg1, msg.arg2, msg.arg3))
+ pprint(" \"{}\"".format(self.escstr(msg.name)))
+ pprint("")
+
+ for gidx, grp in enumerate(pe.dlgs, 1):
+ pprint("# {} = 0x{:x}".format(gidx, gidx))
+ pprint("DLGGRP 0x{:x} {}".format(grp.idx, \
+ self.fmtnum32(grp.arg1)))
+ for sidx, act in enumerate(grp.acts, 1):
+ pprint(" ON {} 0x{:x} 0x{:x} 0x{:x} # {}".format(\
+ self.fmtop(act.opcode), act.ref, act.arg1,
+ act.arg2, sidx))
+ # print code
+ for didx, dlg in enumerate(act.dlgs, 1):
+ #print(bsrec)
+ pprint(" DLG 0x{:x} 0x{:x} # {}".format(\
+ dlg.arg1, dlg.arg2, didx))
+ # scan used addr
+ usedadr = []
+ for op in dlg.ops:
+ if op.opcode == 0x3 or \
+ op.opcode == 0x4: # GOTO or MENURET
+ if op.ref not in usedadr:
+ usedadr.append(op.ref)
+ if len(usedadr) > 0:
+ usedadr.append(dlg.op_start)
+ usedmenu = {}
+ usedcase = {}
+ for oidx, op in enumerate(dlg.ops):
+ cmt = ""
+ opref = "0x{:X}".format(op.ref)
+ opcode = self.fmtdlgop(op.opcode)
+ if op.pos in usedadr:
+ pprint(" label_{:X}:\n".format(
+ op.pos))
+ if op.opcode == 0x1: # BREAK
+ if op.pos in usedcase:
+ if len(usedadr) > 0:
+ cmt = "# end select "\
+ "label_{:X}, case=0x{:}"\
+ "".format(*usedcase[op.pos])
+ else:
+ cmt = "# end "\
+ "select case=0x{:}".\
+ format(usedcase[op.pos][1])
+ elif op.opcode == 0x2 or op.opcode == 0x8: # MENU or CIRCLE
+ cmt = "# select "
+ doarr = []
+ docurr = []
+ sellen = op.ref % 0x100
+ skiptobrk = False
+ menuactstart = None
+ for oidx2, op2 in enumerate(dlg.ops[oidx + 1:]):
+ if op2.opcode == 0x1: # BREAK
+ usedcase[op2.pos] = (op.pos, len(doarr))
+ doarr.append(docurr)
+ skiptobrk = False
+ if len(doarr) == sellen:
+ if op.opcode == 0x2:
+ menuactstart = oidx2 + oidx + 2
+ break
+ docurr = []
+ elif op2.opcode == 0x7 and not skiptobrk: # PLAY
+ docurr.append("msg_{}".format(op2.ref))
+ else:
+ docurr = ["complex"]
+ if len(doarr) < sellen:
+ cmt = "# {} select broken, "\
+ "required={}, got={}".\
+ format(opcode, sellen, len(doarr))
+ else:
+ cmt += ",".join(["+".join(x) for x in doarr])
+ if menuactstart is not None:
+ for oidx2, op2 in enumerate(dlg.ops[\
+ menuactstart:menuactstart + sellen]):
+ usedmenu[op2.pos] = (op.pos, oidx2)
+ elif op.opcode == 0x3 or \
+ op.opcode == 0x4: # GOTO or MENURET
+ opref = "label_{:X}".format(op.ref)
+ if op.pos in usedmenu:
+ cmt = "# action menu="\
+ "label_{:X}, case=0x{:}".\
+ format(*usedmenu[op.pos])
+ elif op.opcode == 0x7:
+ opcode = "PLAY"
+ if op.msg:
+ opref = "msg_{}".format(op.ref)
+ if op.ref < len(pe.msgs):
+ cmt = "# {}".format(self.escstr(
+ pe.msgs[op.ref].name))
+ oparg = " 0x{:X} ".format(op.arg)
+ if (op.opcode == 0x1 or op.opcode == 0x6) and \
+ op.arg == 0 and op.ref == 0:
+ oparg = ""
+ opref = ""
+ if cmt and verbose:
+ pprint(" " + cmt)
+ pprint(" {}{}{}".\
+ format(opcode, oparg, opref))
+ pprint(" ENDDLG # {}".format(didx))
+ pprint(" ENDON # {}".format(sidx))
+ pprint("ENDDLGGRP # {}".format(gidx))
+ pprint("")
+
+
# check if file already exists and flag for overwrite not set
def ckeckoverwrite(fn, args):
if os.path.exists(fn) and not args.fo:
@@ -752,6 +879,37 @@ def action_comp(args):
finally:
f.close()
+def action_decd(args):
+ print("Decompile DIALOGUE.FIX file")
+ destpath = args.destpath
+ encoding = args.encoding
+
+ if destpath:
+ if ckeckoverwrite(destpath, args): return -1
+ if checksame(args.sourcepath, "source", destpath, "destination"):
+ return -2
+ if not encoding:
+ encoding = "UTF-8"
+
+ print("Input:\t{}".format(args.sourcepath))
+ print("Output:\t{}".format(destpath or "-"))
+ if destpath:
+ print("Enc:\t{}".format(encoding))
+ if args.verbose:
+ print("Flag verbose enabled")
+
+ dcs = P12Compiler()
+ if destpath:
+ f = open(destpath, "wb")
+ try:
+ dcs.pretty_print_dlg(args.sourcepath, f, enc = encoding, \
+ verbose = args.verbose)
+ finally:
+ f.close()
+ else:
+ dcs.pretty_print_dlg(args.sourcepath, None, None, \
+ verbose = args.verbose)
+
def internaltest(folder):
# unpack testdata.7z
test_arr = [
@@ -843,6 +1001,20 @@ def main():
parser_comp.add_argument('destfolder', help = "path to output folder")
parser_comp.set_defaults(func = action_comp)
+ # decompiledialog - <dialogue.fix> [[--enc <encoding>] -o <decompiled.txt>]
+ parser_decd = subparsers.add_parser("decompiledialog", aliases = ['dd'], \
+ help = "decompile dialogue.fix")
+ parser_decd.add_argument('-fo', action = 'store_true', \
+ help = "force overwrite existing output file")
+ parser_decd.add_argument("-v", '--verbose', action = 'store_true', \
+ help = "enable more verbose comments")
+ parser_decd.add_argument('-o', action = 'store', dest = "destpath",\
+ help = "output path for decompiled (default: stdout)")
+ parser_decd.add_argument('-e', "--enc", action = 'store', \
+ dest = "encoding", help = "output encoding (default: UTF-8)")
+ parser_decd.add_argument('sourcepath', help = "path to DIALOGUE.FIX file")
+ parser_decd.set_defaults(func = action_decd)
+
# version
parser_version = subparsers.add_parser("version", help = "program version")
parser_version.set_defaults(func = action_version)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 5fef532f8..286fffc92 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -469,12 +469,22 @@ class Engine:
r, g, b = 255, 255, 255
obj.cast = (r, g, b)
- def load_dialogs(self):
+ def load_dialogs(self, fixname = None, lodname = None, noobjref = False):
self.msgs = []
# DIALOGUES.LOD
- fp = self.curr_path + "dialogue.lod"
- if self.fman.exists(fp):
- f = self.fman.read_file_stream(fp)
+
+ if lodname is None:
+ try:
+ f = self.fman.read_file_stream(self.curr_path + "dialogue.lod")
+ except:
+ f = None
+ else:
+ try:
+ f = open(lodname, "rb")
+ except:
+ f = None
+
+ if f:
try:
temp = f.read(4)
num_msg = struct.unpack_from("<I", temp)[0]
@@ -484,24 +494,35 @@ class Engine:
msg = MsgObject(len(self.msgs), \
wav.decode(self.enc).strip(), arg1, arg2, arg3)
# scan objects
- msg.obj = self.obj_idx.get(arg1, None)
- if not msg.obj:
- raise EngineError("DEBUG: Message ref = 0x{:x} not found".\
- format(obj[0]))
+ if not noobjref:
+ msg.obj = self.obj_idx.get(arg1, None)
+ if not msg.obj:
+ raise EngineError("DEBUG: Message ref = 0x{:x} not found".\
+ format(arg1))
self.msgs.append(msg)
for i, capt in enumerate(f.read().split(b"\x00")):
if i < len(self.msgs):
self.msgs[i].name = capt.decode(self.enc)
finally:
- f.close()
+ if f:
+ f.close()
self.dlgs = []
self.dlg_idx = {}
self.dlgops = []
# DIALOGUES.FIX
- fp = self.curr_path + "dialogue.fix"
- if self.fman.exists(fp):
- f = self.fman.read_file_stream(fp)
+ if fixname is None:
+ try:
+ f = self.fman.read_file_stream(self.curr_path + "dialogue.fix")
+ except:
+ f = None
+ else:
+ try:
+ f = open(fixname, "rb")
+ except:
+ f = None
+
+ if f:
try:
temp = f.read(4)
num_grps = struct.unpack_from("<I", temp)[0]
@@ -519,10 +540,12 @@ class Engine:
opcode, ref, num_dlgs, arg1, arg2 = \
struct.unpack_from("<2H3I", temp)
act = DlgActObject(num_dlgs, opcode, ref, arg1, arg2)
- if ref not in self.obj_idx:
- raise EngineError("Dialog group 0x{:x} refered "\
- "to unexisted object 0x{:x}".format(grp.idx, ref))
- act.obj = self.obj_idx[act.ref]
+ if not noobjref:
+ if ref not in self.obj_idx:
+ raise EngineError("Dialog group 0x{:x} refered "\
+ "to unexisted object 0x{:x}".format(
+ grp.idx, ref))
+ act.obj = self.obj_idx[act.ref]
grp.acts.append(act)
for act in grp.acts:
act.dlgs = []
@@ -558,7 +581,8 @@ class Engine:
if len(oparr) > 0:
dlg.ops = oparr
finally:
- f.close()
+ if f:
+ f.close()
def write_script(self, f):
f.write(struct.pack("<II", len(self.objects), len(self.scenes)))
Commit: 68e2468825a57bd754f244f69bb3329d7c18f4ae
https://github.com/scummvm/scummvm-tools/commit/68e2468825a57bd754f244f69bb3329d7c18f4ae
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Compile dialog - dialogue.lod
Changed paths:
engines/petka/dist/setup.py
engines/petka/p12script.py
engines/petka/petka/engine.py
diff --git a/engines/petka/dist/setup.py b/engines/petka/dist/setup.py
index 10d321aa4..fabaabf85 100644
--- a/engines/petka/dist/setup.py
+++ b/engines/petka/dist/setup.py
@@ -6,7 +6,8 @@ import sys, os, struct
# Dependencies are automatically detected, but it might need
# fine tuning.
-buildOptions = dict(packages = ["re", "io", "PIL", "traceback", "zlib", "gzip", "argparse", "struct", "binascii"], \
+buildOptions = dict(packages = ["re", "io", "PIL", "traceback", "zlib", "gzip",
+ "argparse", "struct", "binascii"], \
excludes = ["_posixsubprocess"],
include_files = ["help"],
compressed = True, silent = True,\
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
index a8f161889..7fc598abb 100755
--- a/engines/petka/p12script.py
+++ b/engines/petka/p12script.py
@@ -505,6 +505,211 @@ class P12Compiler:
print("SCRIPT.DAT saved: {} objects, {} scenes".\
format(len(pe.objects), len(pe.scenes)))
+
+ # =======================================================================
+ # compile DIALOGUE.FIX
+ # =======================================================================
+ def compile_dialog(self, source, destfolder, enc = None, \
+ st_fix = None, st_lod = None):
+
+ pe = petka.Engine()
+ pe.init_empty("cp1251")
+
+ mode = 0 # 0 - common, 1 - grp, 2 - act, 3 - dlg
+ # 10 - msg (autoreset to 0)
+
+ # used identificators
+ self.usedid = {}
+
+ revOPS = {}
+ for ok, ov in petka.OPCODES.items():
+ revOPS[ov[0]] = ok
+ revDLGOPS = {}
+ for ok, ov in petka.DLGOPS.items():
+ revDLGOPS[ov[0]] = ok
+ self.reservedid = ["MSG", "DLG", "DLGGRP", "ON", "ENDDLG", \
+ "ENDDLGGRP", "ENDON"] + list(revDLGOPS.keys())
+
+ # msg array
+ compmsg = []
+ # current msg
+ compmsgitem = None
+ # grp array
+ compgrp = []
+ # current grp
+ compgrpitem = None
+ # current act
+ compactitem = None
+ # current dlg
+ compdlgitem = None
+
+ for lineno, tokens in self.tokenizer(source, enc):
+ if len(tokens) == 0:
+ continue
+ if mode == 0:
+ # accept: MSG, DLGGRP
+ cmd = tokens[0].upper()
+ if cmd == "MSG":
+ if len(tokens) < 3 or len(tokens) > 6:
+ raise ScriptSyntaxError("Error at {}: unknown MSG "\
+ "syntax".format(lineno))
+ while len(tokens) < 6:
+ tokens.append("0")
+ # check ident
+ self.checkusedid(tokens[1], lineno)
+ self.setidentvalue(tokens[1], len(compmsg))
+ # check wavfile name (1..12)
+ if len(tokens[2]) < 1 or len(tokens[2]) > 12:
+ raise ScriptSyntaxError("Error at {}: bad filename "\
+ "in MSG \"{}\"".format(lineno, tokens[2]))
+ mode = 10
+ compmsgitem = {"ident": tokens[1], "wav": tokens[2], \
+ "args": tokens[3:], "lineno": lineno}
+ compmsg.append(compmsgitem)
+ elif cmd == "DLGGRP":
+ # dlggrp
+ mode = 1
+ # check syntax
+ if len(tokens) < 2 or len(tokens) > 3:
+ raise ScriptSyntaxError("Error at {}: unknown DLGGRP "\
+ "syntax".format(lineno))
+ while len(tokens) < 3:
+ tokens.append("0")
+ compgrpitem = {"grp_id": tokens[1], "arg": tokens[2], \
+ "acts": [], "lineno": lineno}
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown syntax "\
+ "\"{}\"".format(lineno, cmd))
+ elif mode == 10:
+ # MSG, 2nd string, one token - msg for subtitle
+ if len(tokens) != 1:
+ raise ScriptSyntaxError("Error at {}: MSG syntax error, "\
+ "message required".format(lineno))
+ compmsgitem["msg"] = tokens[0]
+ compmsgitem = None
+ mode = 0
+ elif mode == 1:
+ # accept: ON, ENDDLGGRP
+ cmd = tokens[0].upper()
+ if cmd == "ON":
+ # on
+ mode = 2
+ # check syntax
+ if len(tokens) < 3 or len(tokens) > 5:
+ raise ScriptSyntaxError("Error at {}: unknown ON "\
+ "syntax".format(lineno))
+ while len(tokens) < 5:
+ tokens.append("0")
+ if tokens[1] in revOPS:
+ # opcode
+ don = revOPS[tokens[1]]
+ else:
+ don = self.convertnum(tokens[1])
+ if don is None:
+ raise ScriptSyntaxError("Error at {}: unknown ON "\
+ "OPREF ""\"{}\" in ON".\
+ format(lineno, tokens[1]))
+ don = self.check16(don, "ON opref", lineno)
+ compactitem = {"don": don, "donref": tokens[2],
+ "args": tokens[3:], "dlgs": [], "lineno": lineno}
+ elif cmd == "ENDDLGGRP" and len(tokens) == 1:
+ mode = 0
+ compgrp.append(compgrpitem)
+ compgrpitem = None
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown DLGGRP "\
+ "syntax \"{}\"".format(lineno, cmd))
+ elif mode == 2:
+ # accept: DLG, ENDON
+ cmd = tokens[0].upper()
+ if cmd == "DLG":
+ # dlg
+ mode = 3
+ # check syntax
+ if len(tokens) < 1 or len(tokens) > 3:
+ raise ScriptSyntaxError("Error at {}: unknown DLG "\
+ "syntax".format(lineno))
+ while len(tokens) < 3:
+ tokens.append("0")
+ compdlgitem = {"args": tokens[1:], "dlgops": [], \
+ "lineno": lineno}
+ elif cmd == "ENDON" and len(tokens) == 1:
+ mode = 1
+ compgrpitem["acts"].append(compactitem)
+ compactitem = None
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown ON "\
+ "syntax \"{}\"".format(lineno, cmd))
+ elif mode == 3:
+ # dlgopcode or ENDDLG
+ cmd = tokens[0].upper()
+ if cmd == "ENDDLG" and len(tokens) == 1:
+ compactitem["dlgs"].append(compdlgitem)
+ compdlgitem = None
+ mode = 2
+ elif cmd[-1:] == ":":
+ # label case
+ label = cmd[:-1]
+ self.checkusedid(cmd[:-1], lineno)
+ self.setidentvalue(cmd[:-1], len(compdlgitem["dlgops"]))
+ else:
+ # check format
+ if len(tokens) < 1 or len(tokens) > 3:
+ raise ScriptSyntaxError("Error at {}: unknown DLGOP "\
+ "syntax in DLG".format(lineno))
+ while len(tokens) < 3:
+ tokens.append("0")
+ op = {}
+ if cmd in revDLGOPS:
+ # opcode
+ opcode = revDLGOPS[cmd]
+ else:
+ opcode = self.convertnum(cmd)
+ if opcode is None:
+ raise ScriptSyntaxError("Error at {}: unknown "\
+ "DLGOP \"{}\" in DLG".\
+ format(lineno, cmd))
+ opcode = self.check8(opcode, "dlgopcode", lineno)
+ compdlgitem["dlgops"].append({"opcode": opcode, \
+ "lineno": lineno, \
+ "msg_ref": tokens[2], "arg": tokens[1]})
+ else:
+ raise ScriptSyntaxError("Error at {}: unknown parser mode {}".\
+ format(lineno, mode))
+
+ # check unclosed objects
+ if mode != 0:
+ raise ScriptSyntaxError("Error at {}: unfinished structure".\
+ format(lineno))
+
+ # second stage - MSG
+ for msg in compmsg:
+ # msg arguments
+ fmt = []
+ for i in range(3):
+ fmt.append(("MSG argument {}".format(i + 1), \
+ self.check32, True))
+ argnum = self.convertargs(fmt, msg["args"], msg["lineno"])
+ # build MSGREC
+ msgrec = petka.engine.MsgObject(
+ len(pe.msgs), msg["wav"], argnum[0], argnum[1], argnum[2])
+ msgrec.name = msg["msg"]
+ pe.msgs.append(msgrec)
+
+ if destfolder is not None:
+ f = open(os.path.join(destfolder, "dialogue.lod"), "wb")
+ else:
+ f = st_lod
+ try:
+ pe.write_lod(f)
+ finally:
+ if destfolder is not None:
+ f.close()
+ print("DALOGUE.LOD saved: {} messages".\
+ format(len(pe.msgs)))
+
+
+
# =======================================================================
# decompile utils
# =======================================================================
@@ -699,7 +904,7 @@ class P12Compiler:
for msg in pe.msgs:
pprint("# {} = 0x{:x}".format(msg.idx, msg.idx))
pprint("MSG msg_{} \"{}\" 0x{:x} 0x{:x} 0x{:x}".format(\
- msg.idx, msg.wav, msg.arg1, msg.arg2, msg.arg3))
+ msg.idx, msg.msg_wav, msg.msg_arg1, msg.msg_arg2, msg.msg_arg3))
pprint(" \"{}\"".format(self.escstr(msg.name)))
pprint("")
@@ -910,8 +1115,35 @@ def action_decd(args):
dcs.pretty_print_dlg(args.sourcepath, None, None, \
verbose = args.verbose)
+def action_compd(args):
+ print("Compile DIALOGUE.FIX file")
+ print("Input:\t{}".format(args.sourcepath))
+ print("Output:\t{}".format(args.destfolder))
+ print("Enc:\t{}".format(args.encoding or "UTF-8"))
+
+ dcs = P12Compiler()
+ if os.path.exists(args.destfolder) and not args.fo:
+ cnt = 0
+ lst = ["dialogue.fix", "dialogue.lod"]
+ for item in lst:
+ if find_in_folder(args.destfolder, item, False):
+ print("Error: destination file \"{}\" already "\
+ "exists, use -fo to overwrite".format(item))
+ return
+
+ if not os.path.exists(args.destfolder):
+ os.makedirs(args.destfolder)
+ f = open(args.sourcepath, "rb")
+ try:
+ dcs.compile_dialog(f, args.destfolder, args.encoding)
+ except ScriptSyntaxError as e:
+ if args.trace_error:
+ traceback.print_exc()
+ print(e, file = sys.stderr)
+ finally:
+ f.close()
+
def internaltest(folder):
- # unpack testdata.7z
test_arr = [
"p1demo",
"p1-0", "p1-1", "p1-2", "p1-3",
@@ -953,6 +1185,31 @@ def internaltest(folder):
print("BACKGRND.BG - mismatch")
break
+ # dialogue
+ dcs = P12Compiler()
+ path = find_in_folder(testbase, "dialogue.fix")
+ if not os.path.exists(path):
+ print("All ok - no dialogue")
+ continue
+
+ mems = io.BytesIO()
+ dcs.pretty_print_dlg(path, mems)
+ print("Decompiled dialogue:", mems.tell())
+ # compile back
+ memfix = io.BytesIO()
+ memlod = io.BytesIO()
+ mems.seek(0)
+ ndcs = P12Compiler()
+ ndcs.compile_dialog(mems, None, None, \
+ memfix, memlod)
+ # compare
+ if not compare(path, memfix):
+ print("DIALOGUE.FIX - mismatch")
+ break
+ if not compare(dcs.find_in_folder(testbase, "dialogue.lod"), memlod):
+ print("DIALOGUE.LOD - mismatch")
+ break
+
print("All ok")
def action_version(args):
@@ -1015,6 +1272,19 @@ def main():
parser_decd.add_argument('sourcepath', help = "path to DIALOGUE.FIX file")
parser_decd.set_defaults(func = action_decd)
+ # compiledialog - <source.txt> <destination folder> [--enc <encoding>]
+ parser_compd = subparsers.add_parser("compiledialog", aliases = ['cd'], \
+ help = "compile dialogue.fix")
+ parser_compd.add_argument('-fo', action = 'store_true', \
+ help = "force overwrite existing output files")
+ parser_compd.add_argument('-e', "--enc", action = 'store', \
+ dest = "encoding", help = "output encoding (default: UTF-8)")
+ parser_compd.add_argument('-te', "--trace-error", action = 'store_true', \
+ help = "trace syntax error")
+ parser_compd.add_argument('sourcepath', help = "path to SOURCE.TXT file")
+ parser_compd.add_argument('destfolder', help = "path to output folder")
+ parser_compd.set_defaults(func = action_compd)
+
# version
parser_version = subparsers.add_parser("version", help = "program version")
parser_version.set_defaults(func = action_version)
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 286fffc92..0f765c207 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -105,10 +105,10 @@ class ScrOpObject:
class MsgObject:
def __init__(self, idx, wav, arg1, arg2, arg3):
self.idx = idx
- self.wav = wav # wav filename
- self.arg1 = arg1 # reference to object
- self.arg2 = arg2
- self.arg3 = arg3
+ self.msg_wav = wav # wav filename
+ self.msg_arg1 = arg1 # reference to object
+ self.msg_arg2 = arg2
+ self.msg_arg3 = arg3
self.name = None
class DlgGrpObject:
@@ -164,7 +164,11 @@ class Engine:
self.scenes = []
self.obj_idx = {}
self.scn_idx = {}
-
+ self.msgs = []
+ self.dlgs = []
+ self.dlg_idx = {}
+ self.dlgops = []
+
def parse_ini(self, f):
# parse ini settings
curr_sect = None
@@ -612,3 +616,15 @@ class Engine:
ref[3], ref[4], ref[5]))
+ def write_lod(self, f):
+ f.write(struct.pack("<I", len(self.msgs)))
+ for msg in self.msgs:
+ wav = msg.msg_wav.encode(self.enc)
+ while len(wav) < 12:
+ wav += b"\0"
+ f.write(struct.pack("<I12sII", msg.msg_arg1, wav, msg.msg_arg2,
+ msg.msg_arg3))
+ for msg in self.msgs:
+ txt = msg.name.encode(self.enc)
+ f.write(txt + b"\0")
+
Commit: 1f1901479cbf5b66caaf4655e0adc8d0bae0879a
https://github.com/scummvm/scummvm-tools/commit/1f1901479cbf5b66caaf4655e0adc8d0bae0879a
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Compiler for dialogs
Changed paths:
A engines/petka/help/comp_dlg.txt
A engines/petka/help/comp_scr.txt
A engines/petka/help/compiler.txt
engines/petka/help/changes.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
engines/petka/p12script.py
engines/petka/petka/engine.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 81d630548..cab09d1e3 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,13 @@
ЧÑо нового
==========
+2014-06-03 веÑÑÐ¸Ñ 0.3
+---------------------
+Ðобавлен конÑолÑнÑй компилÑÑÐ¾Ñ Ð¸ декомпилÑÑÐ¾Ñ Ð´Ð»Ñ Ñайлов SCRIPT.DAT,
+ BACKGRND.BG, DIALOGUE.FIX, DIALOGUE.FIX
+ÐÑполнен ÑеÑакÑоÑинг кода
+Ðбновлена ÑпÑавка
+
2014-05-23 веÑÑÐ¸Ñ 0.2o
----------------------
ÐÑпÑавление оÑибки пÑи оÑкÑÑÑии ÑеÑÑÑÑа.
diff --git a/engines/petka/help/comp_dlg.txt b/engines/petka/help/comp_dlg.txt
new file mode 100644
index 000000000..d9d334bb5
--- /dev/null
+++ b/engines/petka/help/comp_dlg.txt
@@ -0,0 +1,84 @@
+СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии DIALOGUE.FIX
+
+romiq.kh at gmail.com
+v0.3 2014-06-03
+
+<i>СинÑакÑÐ¸Ñ Ñайла</i>
+
+ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑказÑваеÑÑÑÑ Ð¿Ð¾ÑÑÑоÑно, Ñазбиение одной ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° неÑколÑко ÑÑÑок.
+ЧаÑÑÑ ÑÑÑоки поÑле Ñимвола '#' ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием.
+
+ÐбознаÑениÑ:
+ * \<обÑзаÑелÑнÑе паÑамеÑÑÑ\>
+ * [необÑзаÑелÑнÑе]
+ * "ÑÑÑока"
+
+Ð Ñайле могÑÑ Ð±ÑÑÑ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ñ ÑледÑÑÑие запиÑи:
+
+ * MSG - ÑообÑениÑ, попадаÑÑ Ð² DIALOGUE.LOD
+ * DLGGRP - гÑÑÐ¿Ð¿Ñ ÑообÑений, попадаÑÑ Ð² DIALOGUE.FIX
+
+<i>MSG</i>
+
+ÐÐ°Ð¶Ð´Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑ Ð´Ð¾Ð»Ð¶Ð½Ð° ÑоÑÑоÑÑÑ Ð¸Ð· 2Ñ
ÑÑÑок. РвÑоÑой ÑÑÑоке должна бÑÑÑ ÑолÑко
+одна запиÑÑ.
+
+MSG \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> \<"Ð¸Ð¼Ñ Ñайла wav"\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\> [\<аÑгÑÐ¼ÐµÐ½Ñ 3\>]]]
+ \<"ТекÑÑ ÑообÑÐµÐ½Ð¸Ñ Ð´Ð»Ñ ÑÑбÑиÑÑов"\>
+
+ÐÑгÑменÑÑ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
+ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
+
+<i>DLGGRP</i>
+
+DLGGRP \<Ð½Ð¾Ð¼ÐµÑ Ð³ÑÑппÑ\> [\<аÑгÑменÑ\>]
+ [обÑабоÑÑики - ON]
+ENDDLGGRP
+
+ÐÑгÑÐ¼ÐµÐ½Ñ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑÐ¼ÐµÐ½Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
+ÑлÑÑае он бÑÐ´ÐµÑ Ð·Ð°Ð¼ÐµÐ½Ñн 0.
+
+<i>ON</i>
+
+ON \<код опеÑаÑии\> \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\>]]
+ [ÑпиÑок - DLG]
+ENDON
+
+Ðод опеÑаÑии - код опеÑаÑии (Ñм. <a href="/help/comp_scr">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT</a>).
+
+ÐденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа - иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа к коÑоÑÐ¾Ð¼Ñ Ð±Ñла пÑименена
+опеÑаÑиÑ.
+
+ÐÑгÑменÑÑ - ÑиÑла Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
+ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
+
+<i>DLG</i>
+
+DLGSET [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\>]]
+ [опеÑаÑии]
+ [\<меÑка пеÑеÑ
ода\>:]
+ENDDLGSET
+
+ÐÑгÑменÑÑ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
+ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
+
+<i>опеÑаÑии</i>
+
+\<код опеÑаÑии\> [\<аÑгÑменÑ\> [\<ÑÑÑлка на ÑообÑение\>]]
+
+ÐÑгÑÐ¼ÐµÐ½Ñ - ÑиÑло Ð¾Ñ 0 до 0xff. ÐÑгÑÐ¼ÐµÐ½Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
+ÑлÑÑае он бÑÐ´ÐµÑ Ð·Ð°Ð¼ÐµÐ½Ñн 0.
+
+ÐÑÑÑÑÑÑвÑÑÑÐ°Ñ ÑÑÑлка Ñакже бÑÐ´ÐµÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ð° на 0.
+
+ÐпеÑаÑии:
+
+ * BREAK
+ * MENU
+ * GOTO
+ * MENURET
+ * RETURN
+ * PLAY
+ * CIRCLE
+ * ÑиÑло 0..0xff
+
diff --git a/engines/petka/help/comp_scr.txt b/engines/petka/help/comp_scr.txt
new file mode 100644
index 000000000..ccf54f183
--- /dev/null
+++ b/engines/petka/help/comp_scr.txt
@@ -0,0 +1,131 @@
+СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT
+
+romiq.kh at gmail.com
+v0.3 2014-06-03
+
+<i>СинÑакÑÐ¸Ñ Ñайла</i>
+
+ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑказÑваеÑÑÑÑ Ð¿Ð¾ÑÑÑоÑно, Ñазбиение одной ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° неÑколÑко ÑÑÑок.
+ЧаÑÑÑ ÑÑÑоки поÑле Ñимвола '#' ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием.
+
+ÐбознаÑениÑ:
+ * \<обÑзаÑелÑнÑе паÑамеÑÑÑ\>
+ * [необÑзаÑелÑнÑе]
+ * "ÑÑÑока"
+
+Ð Ñайле могÑÑ Ð±ÑÑÑ Ð¾Ð¿ÑÐµÐ´ÐµÐ»ÐµÐ½Ñ ÑледÑÑÑие запиÑи:
+
+ * OBJ - обÑекÑÑ, попадаÑÑ Ð² пеÑвÑÑ Ð¿Ð¾Ð»Ð¾Ð²Ð¸Ð½Ñ SCRIPT.DAT
+ * SCENE - ÑÑенÑ, попадаÑÑ Ð²Ð¾ вÑоÑÑÑ Ð¿Ð¾Ð»Ð¾Ð²Ð¸Ð½Ñ SCRIPT.DAT
+ * RES - ÑеÑÑÑÑÑ, попадаÑÑ Ð² RESOURCE.QRC
+
+<i>OBJ</i>
+
+OBJ \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> \<Ð½Ð¾Ð¼ÐµÑ 0..0xffff\> "\<ÐмÑ\>"
+ [обÑабоÑÑики ÑобÑÑий - ON]
+ENDOBJ
+
+<i>SCENE</i>
+
+SCENE \<иденÑиÑикаÑÐ¾Ñ ÑÑенÑ\> \<Ð½Ð¾Ð¼ÐµÑ 0..0xffff\> "\<ÐмÑ\>"
+ [обÑабоÑÑики ÑобÑÑий - ON]
+ [ÑÑÑлки на дÑÑгие обÑекÑÑ - REF]
+ENDSCENE
+
+<i>RES</i>
+
+RES \<иденÑиÑикаÑÐ¾Ñ ÑеÑÑÑÑа\> \<Ð½Ð¾Ð¼ÐµÑ 0..0xffff\> "\<пÑÑÑ\>"
+
+<i>ON</i>
+
+ÐбÑабоÑÑик ÑобÑÑиÑ. ÐÑзÑваеÑÑÑ Ð¿Ñи пÑименении на обÑекÑе опеÑаÑии.
+ÐÑи загÑÑзке ÑкÑипÑа ко вÑем обÑекÑам и ÑÑенам пÑименÑеÑÑÑ Ð¾Ð¿ÐµÑаÑÐ¸Ñ TOTALINIT.
+
+ON \<опеÑаÑиÑ\>
+ON \<опеÑаÑиÑ\> [\<ÑÑаÑÑÑ 0..0xff\> \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа 0..0xffff\>]
+ON \<опеÑаÑиÑ\> [\<ÑÑаÑÑÑ 0..0xff\> THIS]
+ [опеÑаÑии]
+ENDON
+
+<i>REF</i>
+
+REF \<ÑÑÑлка на обÑекÑ\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\> [\<аÑгÑÐ¼ÐµÐ½Ñ 3\> [\<аÑгÑÐ¼ÐµÐ½Ñ 4\> [\<аÑгÑÐ¼ÐµÐ½Ñ 5\>]]]]]
+
+ÐÑÑÑÑÑÑвÑÑÑие аÑгÑменÑÑ Ð±ÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ Ð½Ð° -1 (0xffffffff).
+
+<i>ZEROREF</i>
+
+ÐÑполÑзÑеÑÑÑ ÐµÑли запиÑÑ Ð² backgrnd.bg необÑ
одима, но ни один из обÑекÑов не
+добавлен к ÑÑене. ÐÑли Ñ ÑÑÐµÐ½Ñ Ñже бÑли ÑÐºÐ°Ð·Ð°Ð½Ñ REF иÑполÑзвание ÑÑого опеÑанда
+невозможно.
+
+<i>опеÑаÑии</i>
+
+\<код опеÑаÑии\> \<ÑÑÑлка на обÑекÑ\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\> [\<аÑгÑÐ¼ÐµÐ½Ñ 3\>]]]
+
+СÑÑлка на обÑÐµÐºÑ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ñказана на ÑекÑÑий обÑекÑа Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ Ñлова THIS.
+
+ÐÑÑÑÑÑÑвÑÑÑие аÑгÑменÑÑ Ð±ÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ Ð½Ð° -1 (0xffff).
+
+ÐпеÑаÑии:
+
+ * USE
+ * SETPOS
+ * GOTO
+ * LOOK
+ * SAY
+ * TAKE
+ * WALK
+ * TALK
+ * END
+ * SET
+ * SHOW
+ * HIDE
+ * DIALOG
+ * ZBUFFER
+ * TOTALINIT
+ * ANIMATE
+ * STATUS
+ * ADDINV
+ * DELINV
+ * STOP
+ * CURSOR
+ * OBJECTUSE
+ * ACTIVE
+ * SAID
+ * SETSEQ
+ * ENDSEQ
+ * CHECK
+ * IF
+ * DESCRIPTION
+ * HALF
+ * WALKTO
+ * WALKVICH
+ * INITBG
+ * USERMSG
+ * SYSTEM
+ * SETZBUFFER
+ * CONTINUE
+ * MAP
+ * PASSIVE
+ * NOMAP
+ * SETINV
+ * BGSFX
+ * MUSIC
+ * IMAGE
+ * STAND
+ * ON
+ * OFF
+ * PLAY
+ * LEAVEBG
+ * SHAKE
+ * SP
+ * RANDOM
+ * JUMP
+ * JUMPVICH
+ * PART
+ * CHAPTER
+ * AVI
+ * TOMAP
+ * ÑиÑло 0..0xffff
+
diff --git a/engines/petka/help/compiler.txt b/engines/petka/help/compiler.txt
new file mode 100644
index 000000000..25e0bce49
--- /dev/null
+++ b/engines/petka/help/compiler.txt
@@ -0,0 +1,92 @@
+ÐонÑолÑнÑй компилÑÑÐ¾Ñ Ð¸ декомпилÑÑоÑ
+
+ÐомандÑ
+-------
+
+ * ÐекомпилÑÑÐ¸Ñ SCRIPT.DAT
+ * ÐомпилÑÑÐ¸Ñ SCRIPT.DAT
+ * ÐекомпилÑÑÐ¸Ñ DIALOGUE.FIX
+ * ÐомпилÑÑÐ¸Ñ DIALOGUE.FIX
+
+ÐекомпилÑÑÐ¸Ñ SCRIPT.DAT
+-----------------------
+
+ÐÑвод в ÑеÑминал
+
+ p12script decompile PART_0/SCRIPT.DAT
+
+ÐÑвод в Ñайл
+
+ p12script decompile PART_0/SCRIPT.DAT -o decomp0.txt
+
+ÐÑвод в Ñайл c дÑÑгой кодиÑовкой
+
+ p12script decompile PART_0/SCRIPT.DAT -o decomp0.txt -e cp1251
+
+ÐÐ»Ñ Ñого ÑÑÐ¾Ð±Ñ Ð¿ÐµÑезапиÑаÑÑ ÑÑÑеÑÑвÑÑÑий Ñайл можно иÑполÑзоваÑÑ ÐºÐ»ÑÑ '-fo'.
+
+ÐÐ»Ñ Ð¿Ð¾Ð»Ð½Ð¾Ð³Ð¾ воÑÑÑÐ°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð½ÐµÐ¾Ð±Ñ
одимо ÑÑÐ¾Ð±Ñ ÑÐ°Ð¹Ð»Ñ BACKGRND.DAT и RESOURCE.QRC
+бÑли в Ñом же каÑалоге ÑÑо и SCRIPT.DAT.
+
+ÐлÑÑ --decompile-sorted позволÑÐµÑ Ð¾ÑобÑажаÑÑ Ð¾Ð±ÑекÑÑ ÑÑдом Ñ ÑÑенами, коÑоÑÑе
+иÑ
иÑполÑзÑÑÑ. ÐÐÐÐÐ: Ñакой поÑÑдок Ð¼Ð¾Ð¶ÐµÑ Ð¿ÑивеÑÑи к дÑÑÐ³Ð¾Ð¼Ñ Ð¿Ð¾ÑÑÐ´ÐºÑ Ð¸Ñ
+наÑ
Ð¾Ð¶Ð´ÐµÐ½Ð¸Ñ Ð² Ñайле. Ð ÑÑом ÑлÑÑае компилиÑованнÑй Ñайл Ð¼Ð¾Ð¶ÐµÑ Ð½Ðµ ÑовпаÑÑÑ Ñ
+оÑигиналом из коÑоÑого Ñделана декомпилÑÑиÑ.
+
+ÐомпилÑÑÐ¸Ñ SCRIPT.DAT
+---------------------
+
+ÐомпилÑÑÐ¸Ñ Ñайла в каÑалог
+
+ p12script compile source.txt folder
+
+ÐомпилÑÑÐ¸Ñ Ñайла c дÑÑгой кодиÑовкой в каÑалог
+
+ p12script compile source.txt folder -e cp1251
+
+ÐомпилÑÑÐ¾Ñ Ð½Ðµ бÑÐ´ÐµÑ Ð·Ð°Ð¿Ð¸ÑÑваÑÑ ÑÐ°Ð¹Ð»Ñ Ð² каÑалог где Ñже еÑÑÑ ÑÐ°Ð¹Ð»Ñ SCRIPT.DAT,
+BACKGRND.DAT или RESOURCE.QRC.
+ÐÐ»Ñ Ñого ÑÑÐ¾Ð±Ñ Ð¾Ð±Ð¾Ð¹Ñи ÑÑо можно иÑполÑзоваÑÑ ÐºÐ»ÑÑ '-fo'.
+
+СинÑакÑÐ¸Ñ Ñайла пÑиведÑн в докÑменÑе <a href="/help/comp_scr">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT</a>.
+
+ÐекомпилÑÑÐ¸Ñ DIALOGUE.FIX
+-------------------------
+
+ÐÑвод в ÑеÑминал
+
+ p12script decompiledialog PART_1/DIALOGUE.FIX
+
+ÐÑвод в Ñайл
+
+ p12script decompiledialog PART_1/DIALOGUE.FIX -o decomp0.txt
+
+ÐÑвод в Ñайл c дÑÑгой кодиÑовкой
+
+ p12script decompiledialog PART_1/DIALOGUE.FIX -o decomp0.txt -e cp1251
+
+ÐÐ»Ñ Ñого ÑÑÐ¾Ð±Ñ Ð¿ÐµÑезапиÑаÑÑ ÑÑÑеÑÑвÑÑÑий Ñайл можно иÑполÑзоваÑÑ ÐºÐ»ÑÑ '-fo'.
+
+ÐÐ»Ñ Ð´ÐµÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии необÑ
одимо ÑÑÐ¾Ð±Ñ Ñайл DIALOGUE.LOD бÑл в Ñом же каÑалоге ÑÑо
+и DIALOGUE.FIX.
+
+ÐлÑÑ --verbose позволÑÐµÑ Ð¾ÑениÑÑ Ð½Ð° какое ÑообÑение ÑÑÑлаеÑÑÑ ÑÐ»ÐµÐ¼ÐµÐ½Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð°.
+
+ÐомпилÑÑÐ¸Ñ DIALOGUE.FIX
+-----------------------
+
+ÐомпилÑÑÐ¸Ñ Ñайла в каÑалог
+
+ p12script compiledialog source.txt folder
+
+ÐомпилÑÑÐ¸Ñ Ñайла c дÑÑгой кодиÑовкой в каÑалог
+
+ p12script compiledialog source.txt folder -e cp1251
+
+ÐомпилÑÑÐ¾Ñ Ð½Ðµ бÑÐ´ÐµÑ Ð·Ð°Ð¿Ð¸ÑÑваÑÑ ÑÐ°Ð¹Ð»Ñ Ð² каÑалог где Ñже еÑÑÑ ÑÐ°Ð¹Ð»Ñ DIALOGUE.FIX
+или DIALOGUE.LOD.
+ÐÐ»Ñ Ñого ÑÑÐ¾Ð±Ñ Ð¾Ð±Ð¾Ð¹Ñи ÑÑо можно иÑполÑзоваÑÑ ÐºÐ»ÑÑ '-fo'.
+
+СинÑакÑÐ¸Ñ Ñайла пÑиведÑн в докÑменÑе <a href="/help/comp_dlg">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии DIALOGUE.FIX</a>.
+
+
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index ee2fe76ec..1b5b8f78c 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -1,6 +1,6 @@
СпÑавка
-ÐеÑÑиÑ: 0.2o 2014-05-20
+ÐеÑÑиÑ: 0.3 2014-06-03
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
@@ -26,3 +26,7 @@
* <a href="/help/info">СпÑавоÑники</a>
* <a href="/help/about">РпÑогÑамме</a>
+УÑилиÑÑ
+
+ * <a href="/help/compiler">ÐонÑолÑнÑй компилÑÑÐ¾Ñ Ð¸ декомпилÑÑоÑ</a>
+
diff --git a/engines/petka/help/list b/engines/petka/help/list
index dbab18eeb..0bc2a2ba0 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -16,4 +16,7 @@ cmdline
support
info
about
+compiler
+comp_scr
+comp_dlg
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 603659665..ce51ef530 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1469,11 +1469,11 @@ class App(tkinter.Frame):
else:
# msg info
self.add_info("<b>Message</b>: {}\n".format(path[1]))
- self.add_info(" wav: {}\n".format(msg.wav))
+ self.add_info(" wav: {}\n".format(msg.msg_wav))
self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx, True) +
"\n")
- self.add_info(" arg2: {} (0x{:X})\n".format(msg.arg2, msg.arg2))
- self.add_info(" arg3: {} (0x{:X})\n".format(msg.arg3, msg.arg3))
+ self.add_info(" arg2: {a} (0x{a:X})\n".format(a = msg.msg_arg2))
+ self.add_info(" arg3: {a} (0x{a:X})\n".format(a = msg.msg_arg3))
self.add_info("\n{}\n".format(hlesc(msg.name)))
if self.tran:
self.add_info("\n<i>Translated:</i>\n{}\n".\
@@ -1520,7 +1520,7 @@ class App(tkinter.Frame):
# grp info
self.add_info("<b>Dialog group</b>: {} (0x{:X})\n".format(\
grp.idx, grp.idx))
- self.add_info(" arg1: {} (0x{:X})\n\n".format(grp.arg1, grp.arg1))
+ self.add_info(" arg1: {a} (0x{a:X})\n\n".format(a = grp.grp_arg1))
self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.acts)))
for idx, act in enumerate(grp.acts):
self.add_info(" {}) <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: "\
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
index 7fc598abb..6ccdce86e 100755
--- a/engines/petka/p12script.py
+++ b/engines/petka/p12script.py
@@ -420,7 +420,7 @@ class P12Compiler:
act["lineno"])
else:
# get by ident
- self.checkident(act["sonref"], "ON object ref", \
+ self.checkident(act["sonref"], "ON object ref",
act["lineno"])
sonref = self.getidentvalue(act["sonref"])
onrec = petka.engine.ScrActObject(act["son"],
@@ -437,13 +437,13 @@ class P12Compiler:
opref = self.check16(opref, "OP object", op["lineno"])
else:
# get by ident
- self.checkident(op["obj_ref"], "OP object", \
+ self.checkident(op["obj_ref"], "OP object",
op["lineno"])
opref = self.getidentvalue(op["obj_ref"])
# arguments
fmt = []
for i in range(3):
- fmt.append(("OP argument {}".format(i + 1), \
+ fmt.append(("OP argument {}".format(i + 1),
self.check16, True))
argnum = self.convertargs(fmt, op["args"], op["lineno"])
oprec = petka.engine.ScrOpObject(opref, op["opcode"],
@@ -509,7 +509,7 @@ class P12Compiler:
# =======================================================================
# compile DIALOGUE.FIX
# =======================================================================
- def compile_dialog(self, source, destfolder, enc = None, \
+ def compile_dialog(self, source, destfolder, enc = None,
st_fix = None, st_lod = None):
pe = petka.Engine()
@@ -527,7 +527,7 @@ class P12Compiler:
revDLGOPS = {}
for ok, ov in petka.DLGOPS.items():
revDLGOPS[ov[0]] = ok
- self.reservedid = ["MSG", "DLG", "DLGGRP", "ON", "ENDDLG", \
+ self.reservedid = ["MSG", "DLG", "DLGGRP", "ON", "ENDDLG",
"ENDDLGGRP", "ENDON"] + list(revDLGOPS.keys())
# msg array
@@ -542,6 +542,8 @@ class P12Compiler:
compactitem = None
# current dlg
compdlgitem = None
+ # dlgop count
+ compdlgops = 0
for lineno, tokens in self.tokenizer(source, enc):
if len(tokens) == 0:
@@ -563,7 +565,7 @@ class P12Compiler:
raise ScriptSyntaxError("Error at {}: bad filename "\
"in MSG \"{}\"".format(lineno, tokens[2]))
mode = 10
- compmsgitem = {"ident": tokens[1], "wav": tokens[2], \
+ compmsgitem = {"ident": tokens[1], "wav": tokens[2],
"args": tokens[3:], "lineno": lineno}
compmsg.append(compmsgitem)
elif cmd == "DLGGRP":
@@ -575,7 +577,7 @@ class P12Compiler:
"syntax".format(lineno))
while len(tokens) < 3:
tokens.append("0")
- compgrpitem = {"grp_id": tokens[1], "arg": tokens[2], \
+ compgrpitem = {"grp_id": tokens[1], "arg": tokens[2],
"acts": [], "lineno": lineno}
else:
raise ScriptSyntaxError("Error at {}: unknown syntax "\
@@ -631,7 +633,7 @@ class P12Compiler:
"syntax".format(lineno))
while len(tokens) < 3:
tokens.append("0")
- compdlgitem = {"args": tokens[1:], "dlgops": [], \
+ compdlgitem = {"args": tokens[1:], "dlgops": [],
"lineno": lineno}
elif cmd == "ENDON" and len(tokens) == 1:
mode = 1
@@ -647,11 +649,11 @@ class P12Compiler:
compactitem["dlgs"].append(compdlgitem)
compdlgitem = None
mode = 2
- elif cmd[-1:] == ":":
+ elif len(tokens) == 1 and cmd[-1:] == ":":
# label case
label = cmd[:-1]
- self.checkusedid(cmd[:-1], lineno)
- self.setidentvalue(cmd[:-1], len(compdlgitem["dlgops"]))
+ self.checkusedid(tokens[0][:-1], lineno)
+ self.setidentvalue(tokens[0][:-1], compdlgops)
else:
# check format
if len(tokens) < 1 or len(tokens) > 3:
@@ -670,7 +672,8 @@ class P12Compiler:
"DLGOP \"{}\" in DLG".\
format(lineno, cmd))
opcode = self.check8(opcode, "dlgopcode", lineno)
- compdlgitem["dlgops"].append({"opcode": opcode, \
+ compdlgops += 1
+ compdlgitem["dlgops"].append({"opcode": opcode,
"lineno": lineno, \
"msg_ref": tokens[2], "arg": tokens[1]})
else:
@@ -708,6 +711,72 @@ class P12Compiler:
print("DALOGUE.LOD saved: {} messages".\
format(len(pe.msgs)))
+ for grp in compgrp:
+ fmt = [("DLGGRP number", self.check32, False),\
+ ("DLGGRP argument", self.check32, True)]
+ argnum = self.convertargs(fmt, [grp["grp_id"], grp["arg"]], \
+ grp["lineno"])
+ # build DLGGRP
+ grprec = petka.engine.DlgGrpObject(argnum[0], argnum[1])
+ grprec.acts = []
+ for act in grp["acts"]:
+ # act objref
+ if act["donref"].upper() == "THIS":
+ donref = grprec.grp_id
+ else:
+ donref = self.convertnum(act["donref"])
+ if donref is not None:
+ # direct number
+ donref = self.check16(donref, "ON object ref",
+ act["lineno"])
+ else:
+ # get by ident
+ self.checkident(act["donref"], "ON object ref",
+ act["lineno"])
+ donref = self.getidentvalue(act["donref"])
+ # act arguments
+ fmt = []
+ for i in range(2):
+ fmt.append(("ON argument {}".format(i + 1),
+ self.check32, True))
+ argnum = self.convertargs(fmt, act["args"], act["lineno"])
+ # build ON
+ actrec = petka.engine.DlgActObject(act["don"], donref,
+ argnum[0], argnum[1])
+ actrec.dlgs = []
+ for dlg in act["dlgs"]:
+ # dlg arguments
+ fmt = []
+ for i in range(2):
+ fmt.append(("DLG argument {}".format(i + 1),
+ self.check32, True))
+ argnum = self.convertargs(fmt, dlg["args"], dlg["lineno"])
+ # build DLG
+ dlgrec = petka.engine.DlgObject(len(pe.dlgops),
+ argnum[0], argnum[1])
+ for op in dlg["dlgops"]:
+ fmt = [("DLGOP argument", self.check8, False),
+ ("DLGOP ref", self.check16, True)]
+ argnum = self.convertargs(fmt, [op["arg"],
+ op["msg_ref"]], op["lineno"])
+ oprec = petka.engine.DlgOpObject(op["opcode"],
+ argnum[0], argnum[1])
+ pe.dlgops.append(oprec)
+ actrec.dlgs.append(dlgrec)
+ grprec.acts.append(actrec)
+ pe.dlgs.append(grprec)
+
+ if destfolder is not None:
+ f = open(os.path.join(destfolder, "dialogue.fix"), "wb")
+ else:
+ f = st_fix
+ try:
+ pe.write_fix(f)
+ finally:
+ if destfolder is not None:
+ f.close()
+ print("DALOGUE.FIX saved: {} groups, {} dialog opcodes".\
+ format(len(pe.dlgs), len(pe.dlgops)))
# =======================================================================
@@ -911,7 +980,7 @@ class P12Compiler:
for gidx, grp in enumerate(pe.dlgs, 1):
pprint("# {} = 0x{:x}".format(gidx, gidx))
pprint("DLGGRP 0x{:x} {}".format(grp.idx, \
- self.fmtnum32(grp.arg1)))
+ self.fmtnum32(grp.grp_arg1)))
for sidx, act in enumerate(grp.acts, 1):
pprint(" ON {} 0x{:x} 0x{:x} 0x{:x} # {}".format(\
self.fmtop(act.opcode), act.ref, act.arg1,
@@ -937,7 +1006,7 @@ class P12Compiler:
opref = "0x{:X}".format(op.ref)
opcode = self.fmtdlgop(op.opcode)
if op.pos in usedadr:
- pprint(" label_{:X}:\n".format(
+ pprint(" label_{:X}:".format(
op.pos))
if op.opcode == 0x1: # BREAK
if op.pos in usedcase:
@@ -1206,7 +1275,7 @@ def internaltest(folder):
if not compare(path, memfix):
print("DIALOGUE.FIX - mismatch")
break
- if not compare(dcs.find_in_folder(testbase, "dialogue.lod"), memlod):
+ if not compare(find_in_folder(testbase, "dialogue.lod"), memlod):
print("DIALOGUE.LOD - mismatch")
break
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 0f765c207..1b6715cbd 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -112,15 +112,13 @@ class MsgObject:
self.name = None
class DlgGrpObject:
- def __init__(self, idx, num_acts, arg1):
+ def __init__(self, idx, arg1):
self.idx = idx
- self.num_acts = num_acts # store array length while loading
- self.arg1 = arg1
+ self.grp_arg1 = arg1
self.acts = None # dialog handlers
class DlgActObject:
- def __init__(self, num_dlgs, opcode, ref, arg1, arg2):
- self.num_dlgs = num_dlgs # store array length while loading
+ def __init__(self, opcode, ref, arg1, arg2):
self.opcode = opcode # handler: opcode filter
self.ref = ref # handler: object idx filter
self.arg1 = arg1
@@ -136,12 +134,11 @@ class DlgObject:
self.ops = None # operations list
class DlgOpObject:
- def __init__(self, opcode, arg, ref, pos):
+ def __init__(self, opcode, arg, ref):
self.opcode = opcode # dialog opcode
self.arg = arg # argument (ref, offset etc.)
self.ref = ref # message idx
self.msg = None # message
- self.pos = pos # position in opcodes list
class Engine:
def __init__(self):
@@ -533,7 +530,8 @@ class Engine:
for i in range(num_grps):
temp = f.read(12)
idx, num_acts, arg1 = struct.unpack_from("<III", temp)
- grp = DlgGrpObject(idx, num_acts, arg1)
+ grp = DlgGrpObject(idx, arg1)
+ grp.num_acts = num_acts
self.dlgs.append(grp)
opref = {}
for grp in self.dlgs:
@@ -543,7 +541,8 @@ class Engine:
temp = f.read(16)
opcode, ref, num_dlgs, arg1, arg2 = \
struct.unpack_from("<2H3I", temp)
- act = DlgActObject(num_dlgs, opcode, ref, arg1, arg2)
+ act = DlgActObject(opcode, ref, arg1, arg2)
+ act.num_dlgs = num_dlgs
if not noobjref:
if ref not in self.obj_idx:
raise EngineError("Dialog group 0x{:x} refered "\
@@ -569,7 +568,8 @@ class Engine:
for oidx, i in enumerate(range(num_ops)):
temp = f.read(4)
ref, arg, code = struct.unpack_from("<HBB", temp)
- dlgop = DlgOpObject(code, arg, ref, oidx)
+ dlgop = DlgOpObject(code, arg, ref)
+ dlgop.pos = oidx
if ref < len(self.msgs):
dlgop.msg = self.msgs[ref]
self.dlgops.append(dlgop)
@@ -628,3 +628,19 @@ class Engine:
txt = msg.name.encode(self.enc)
f.write(txt + b"\0")
+ def write_fix(self, f):
+ f.write(struct.pack("<I", len(self.dlgs)))
+ for grp in self.dlgs:
+ f.write(struct.pack("<3I", grp.idx, len(grp.acts), grp.grp_arg1))
+ for grp in self.dlgs:
+ for act in grp.acts:
+ f.write(struct.pack("<2H3I", act.opcode, act.ref,
+ len(act.dlgs), act.arg1, act.arg2))
+ for act in grp.acts:
+ for dlg in act.dlgs:
+ f.write(struct.pack("<3I", dlg.op_start, dlg.arg1,
+ dlg.arg2))
+ f.write(struct.pack("<I", len(self.dlgops)))
+ for op in self.dlgops:
+ f.write(struct.pack("<H2B", op.ref, op.arg, op.opcode))
+
Commit: bd67cfbdba1cdcf7ae5f7924e57305d81ce69d41
https://github.com/scummvm/scummvm-tools/commit/bd67cfbdba1cdcf7ae5f7924e57305d81ce69d41
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix doc
Changed paths:
engines/petka/help/comp_dlg.txt
engines/petka/help/comp_scr.txt
diff --git a/engines/petka/help/comp_dlg.txt b/engines/petka/help/comp_dlg.txt
index d9d334bb5..84d25bece 100644
--- a/engines/petka/help/comp_dlg.txt
+++ b/engines/petka/help/comp_dlg.txt
@@ -3,10 +3,11 @@
romiq.kh at gmail.com
v0.3 2014-06-03
-<i>СинÑакÑÐ¸Ñ Ñайла</i>
+<u>СинÑакÑÐ¸Ñ Ñайла</u>
+
+ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑказÑваÑÑÑÑ Ð¿Ð¾ÑÑÑоÑно, Ñазбиение одной ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° неÑколÑко ÑÑÑок не
+допÑÑкаеÑÑÑ. ЧаÑÑÑ ÑÑÑоки поÑле Ñимвола '#' ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием.
-ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑказÑваеÑÑÑÑ Ð¿Ð¾ÑÑÑоÑно, Ñазбиение одной ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° неÑколÑко ÑÑÑок.
-ЧаÑÑÑ ÑÑÑоки поÑле Ñимвола '#' ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием.
ÐбознаÑениÑ:
* \<обÑзаÑелÑнÑе паÑамеÑÑÑ\>
@@ -18,7 +19,7 @@ v0.3 2014-06-03
* MSG - ÑообÑениÑ, попадаÑÑ Ð² DIALOGUE.LOD
* DLGGRP - гÑÑÐ¿Ð¿Ñ ÑообÑений, попадаÑÑ Ð² DIALOGUE.FIX
-<i>MSG</i>
+<u>MSG</u>
ÐÐ°Ð¶Ð´Ð°Ñ Ð·Ð°Ð¿Ð¸ÑÑ Ð´Ð¾Ð»Ð¶Ð½Ð° ÑоÑÑоÑÑÑ Ð¸Ð· 2Ñ
ÑÑÑок. РвÑоÑой ÑÑÑоке должна бÑÑÑ ÑолÑко
одна запиÑÑ.
@@ -29,7 +30,7 @@ MSG \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> \<"Ð¸Ð¼Ñ Ñайла wav"\> [\
ÐÑгÑменÑÑ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
-<i>DLGGRP</i>
+<u>DLGGRP</u>
DLGGRP \<Ð½Ð¾Ð¼ÐµÑ Ð³ÑÑппÑ\> [\<аÑгÑменÑ\>]
[обÑабоÑÑики - ON]
@@ -38,7 +39,7 @@ ENDDLGGRP
ÐÑгÑÐ¼ÐµÐ½Ñ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑÐ¼ÐµÐ½Ñ Ð¼Ð¾Ð¶ÐµÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
ÑлÑÑае он бÑÐ´ÐµÑ Ð·Ð°Ð¼ÐµÐ½Ñн 0.
-<i>ON</i>
+<u>ON</u>
ON \<код опеÑаÑии\> \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\>]]
[ÑпиÑок - DLG]
@@ -52,7 +53,7 @@ ENDON
ÐÑгÑменÑÑ - ÑиÑла Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
-<i>DLG</i>
+<u>DLG</u>
DLGSET [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\>]]
[опеÑаÑии]
@@ -62,7 +63,7 @@ ENDDLGSET
ÐÑгÑменÑÑ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
-<i>опеÑаÑии</i>
+<u>опеÑаÑии</u>
\<код опеÑаÑии\> [\<аÑгÑменÑ\> [\<ÑÑÑлка на ÑообÑение\>]]
diff --git a/engines/petka/help/comp_scr.txt b/engines/petka/help/comp_scr.txt
index ccf54f183..f9199f64d 100644
--- a/engines/petka/help/comp_scr.txt
+++ b/engines/petka/help/comp_scr.txt
@@ -3,10 +3,10 @@
romiq.kh at gmail.com
v0.3 2014-06-03
-<i>СинÑакÑÐ¸Ñ Ñайла</i>
+<u>СинÑакÑÐ¸Ñ Ñайла</u>
-ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑказÑваеÑÑÑÑ Ð¿Ð¾ÑÑÑоÑно, Ñазбиение одной ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° неÑколÑко ÑÑÑок.
-ЧаÑÑÑ ÑÑÑоки поÑле Ñимвола '#' ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием.
+ÐÐ¾Ð¼Ð°Ð½Ð´Ñ ÑказÑваÑÑÑÑ Ð¿Ð¾ÑÑÑоÑно, Ñазбиение одной ÐºÐ¾Ð¼Ð°Ð½Ð´Ñ Ð½Ð° неÑколÑко ÑÑÑок не
+допÑÑкаеÑÑÑ. ЧаÑÑÑ ÑÑÑоки поÑле Ñимвола '#' ÑÑиÑаеÑÑÑ ÐºÐ¾Ð¼Ð¼ÐµÐ½ÑаÑием.
ÐбознаÑениÑ:
* \<обÑзаÑелÑнÑе паÑамеÑÑÑ\>
@@ -19,24 +19,24 @@ v0.3 2014-06-03
* SCENE - ÑÑенÑ, попадаÑÑ Ð²Ð¾ вÑоÑÑÑ Ð¿Ð¾Ð»Ð¾Ð²Ð¸Ð½Ñ SCRIPT.DAT
* RES - ÑеÑÑÑÑÑ, попадаÑÑ Ð² RESOURCE.QRC
-<i>OBJ</i>
+<u>OBJ</u>
OBJ \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> \<Ð½Ð¾Ð¼ÐµÑ 0..0xffff\> "\<ÐмÑ\>"
[обÑабоÑÑики ÑобÑÑий - ON]
ENDOBJ
-<i>SCENE</i>
+<u>SCENE</u>
SCENE \<иденÑиÑикаÑÐ¾Ñ ÑÑенÑ\> \<Ð½Ð¾Ð¼ÐµÑ 0..0xffff\> "\<ÐмÑ\>"
[обÑабоÑÑики ÑобÑÑий - ON]
[ÑÑÑлки на дÑÑгие обÑекÑÑ - REF]
ENDSCENE
-<i>RES</i>
+<u>RES</u>
RES \<иденÑиÑикаÑÐ¾Ñ ÑеÑÑÑÑа\> \<Ð½Ð¾Ð¼ÐµÑ 0..0xffff\> "\<пÑÑÑ\>"
-<i>ON</i>
+<u>ON</u>
ÐбÑабоÑÑик ÑобÑÑиÑ. ÐÑзÑваеÑÑÑ Ð¿Ñи пÑименении на обÑекÑе опеÑаÑии.
ÐÑи загÑÑзке ÑкÑипÑа ко вÑем обÑекÑам и ÑÑенам пÑименÑеÑÑÑ Ð¾Ð¿ÐµÑаÑÐ¸Ñ TOTALINIT.
@@ -47,19 +47,19 @@ ON \<опеÑаÑиÑ\> [\<ÑÑаÑÑÑ 0..0xff\> THIS]
[опеÑаÑии]
ENDON
-<i>REF</i>
+<u>REF</u>
REF \<ÑÑÑлка на обÑекÑ\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\> [\<аÑгÑÐ¼ÐµÐ½Ñ 3\> [\<аÑгÑÐ¼ÐµÐ½Ñ 4\> [\<аÑгÑÐ¼ÐµÐ½Ñ 5\>]]]]]
ÐÑÑÑÑÑÑвÑÑÑие аÑгÑменÑÑ Ð±ÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ Ð½Ð° -1 (0xffffffff).
-<i>ZEROREF</i>
+<u>ZEROREF</u>
ÐÑполÑзÑеÑÑÑ ÐµÑли запиÑÑ Ð² backgrnd.bg необÑ
одима, но ни один из обÑекÑов не
добавлен к ÑÑене. ÐÑли Ñ ÑÑÐµÐ½Ñ Ñже бÑли ÑÐºÐ°Ð·Ð°Ð½Ñ REF иÑполÑзвание ÑÑого опеÑанда
невозможно.
-<i>опеÑаÑии</i>
+<u>опеÑаÑии</u>
\<код опеÑаÑии\> \<ÑÑÑлка на обÑекÑ\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\> [\<аÑгÑÐ¼ÐµÐ½Ñ 3\>]]]
Commit: ce8130943deac3b6cb751f3d1c63f09a7b2bfe9e
https://github.com/scummvm/scummvm-tools/commit/ce8130943deac3b6cb751f3d1c63f09a7b2bfe9e
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fixes
Changed paths:
engines/petka/help/changes.txt
engines/petka/help/comp_dlg.txt
engines/petka/help/comp_scr.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index cab09d1e3..f791b8b0f 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -7,6 +7,9 @@
BACKGRND.BG, DIALOGUE.FIX, DIALOGUE.FIX
ÐÑполнен ÑеÑакÑоÑинг кода
Ðбновлена ÑпÑавка
+Ðобавлено ÑоÑ
Ñанение пеÑеведÑннÑÑ
DIALOGUE.LOD (ÑÑбÑиÑÑÑ) и NAMES.INI (надпиÑи)
+ÐÑпÑавлено ÑоÑ
Ñанение Ñаблонов Ð´Ð»Ñ Ð¿ÐµÑевода в ÑÑанÑлиÑе (бÑÐºÐ²Ñ "а" и "Ð")
+ÐÑли пеÑевод загÑÑжен - Ñо ÑообÑÐµÐ½Ð¸Ñ Ð² ÑпиÑке Ñоже бÑдÑÑ Ð¿ÐµÑеведенÑ.
2014-05-23 веÑÑÐ¸Ñ 0.2o
----------------------
@@ -14,7 +17,7 @@
2014-05-21 веÑÑÐ¸Ñ 0.2n
----------------------
-ФÑнкÑÑÐ¸Ñ ÑÑанÑлиÑеÑаÑии заменена на ÑобÑÑвеннÑÑ.
+ФÑнкÑÐ¸Ñ ÑÑанÑлиÑеÑаÑии заменена на ÑобÑÑвеннÑÑ.
2014-05-21 веÑÑÐ¸Ñ 0.2m
----------------------
diff --git a/engines/petka/help/comp_dlg.txt b/engines/petka/help/comp_dlg.txt
index 84d25bece..02c076f40 100644
--- a/engines/petka/help/comp_dlg.txt
+++ b/engines/petka/help/comp_dlg.txt
@@ -45,7 +45,9 @@ ON \<код опеÑаÑии\> \<иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа\> [\<
[ÑпиÑок - DLG]
ENDON
-Ðод опеÑаÑии - код опеÑаÑии (Ñм. <a href="/help/comp_scr">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT</a>).
+Ðод опеÑаÑии - код опеÑаÑии пÑи вÑполнении коÑоÑой бÑÐ´ÐµÑ Ð²Ñполнен обÑабоÑÑик
+ (Ñм. <a href="/help/comp_scr">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT</a>).
+Также еÑÑÑ ÑпеÑиалÑнÑй код 0xFFFE.
ÐденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа - иденÑиÑикаÑÐ¾Ñ Ð¾Ð±ÑекÑа к коÑоÑÐ¾Ð¼Ñ Ð±Ñла пÑименена
опеÑаÑиÑ.
@@ -55,10 +57,10 @@ ENDON
<u>DLG</u>
-DLGSET [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\>]]
+DLG [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\>]]
[опеÑаÑии]
[\<меÑка пеÑеÑ
ода\>:]
-ENDDLGSET
+ENDDLG
ÐÑгÑменÑÑ - ÑиÑло Ð¾Ñ 0 до 0xffffffff. ÐÑгÑменÑÑ Ð¼Ð¾Ð³ÑÑ Ð¾ÑÑÑÑÑвоваÑÑ, в ÑÑом
ÑлÑÑае они бÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ 0.
@@ -74,12 +76,12 @@ ENDDLGSET
ÐпеÑаÑии:
- * BREAK
- * MENU
- * GOTO
- * MENURET
- * RETURN
- * PLAY
- * CIRCLE
+ * 1 - BREAK
+ * 2 - MENU
+ * 3 - GOTO
+ * 4 - MENURET
+ * 6 - RETURN
+ * 7 - PLAY
+ * 8 - CIRCLE
* ÑиÑло 0..0xff
diff --git a/engines/petka/help/comp_scr.txt b/engines/petka/help/comp_scr.txt
index f9199f64d..720de8fac 100644
--- a/engines/petka/help/comp_scr.txt
+++ b/engines/petka/help/comp_scr.txt
@@ -51,11 +51,14 @@ ENDON
REF \<ÑÑÑлка на обÑекÑ\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑÐ¼ÐµÐ½Ñ 2\> [\<аÑгÑÐ¼ÐµÐ½Ñ 3\> [\<аÑгÑÐ¼ÐµÐ½Ñ 4\> [\<аÑгÑÐ¼ÐµÐ½Ñ 5\>]]]]]
+УказÑÐ²Ð°ÐµÑ Ð½Ð° обÑÐµÐºÑ Ð½Ð°Ñ
одÑÑийÑÑ Ð½Ð° ÑÑене. ÐÑи запиÑи попадаÑÑ Ð² Ñайл
+ BACKGRND.BG.
+
ÐÑÑÑÑÑÑвÑÑÑие аÑгÑменÑÑ Ð±ÑдÑÑ Ð·Ð°Ð¼ÐµÐ½ÐµÐ½Ñ Ð½Ð° -1 (0xffffffff).
<u>ZEROREF</u>
-ÐÑполÑзÑеÑÑÑ ÐµÑли запиÑÑ Ð² backgrnd.bg необÑ
одима, но ни один из обÑекÑов не
+ÐÑполÑзÑеÑÑÑ ÐµÑли запиÑÑ Ð² BACKGRND.BG необÑ
одима, но ни один из обÑекÑов не
добавлен к ÑÑене. ÐÑли Ñ ÑÑÐµÐ½Ñ Ñже бÑли ÑÐºÐ°Ð·Ð°Ð½Ñ REF иÑполÑзвание ÑÑого опеÑанда
невозможно.
@@ -69,63 +72,63 @@ REF \<ÑÑÑлка на обÑекÑ\> [\<аÑгÑÐ¼ÐµÐ½Ñ 1\> [\<аÑгÑмен
ÐпеÑаÑии:
- * USE
- * SETPOS
- * GOTO
- * LOOK
- * SAY
- * TAKE
- * WALK
- * TALK
- * END
- * SET
- * SHOW
- * HIDE
- * DIALOG
- * ZBUFFER
- * TOTALINIT
- * ANIMATE
- * STATUS
- * ADDINV
- * DELINV
- * STOP
- * CURSOR
- * OBJECTUSE
- * ACTIVE
- * SAID
- * SETSEQ
- * ENDSEQ
- * CHECK
- * IF
- * DESCRIPTION
- * HALF
- * WALKTO
- * WALKVICH
- * INITBG
- * USERMSG
- * SYSTEM
- * SETZBUFFER
- * CONTINUE
- * MAP
- * PASSIVE
- * NOMAP
- * SETINV
- * BGSFX
- * MUSIC
- * IMAGE
- * STAND
- * ON
- * OFF
- * PLAY
- * LEAVEBG
- * SHAKE
- * SP
- * RANDOM
- * JUMP
- * JUMPVICH
- * PART
- * CHAPTER
- * AVI
- * TOMAP
+ * 1 - USE
+ * 2 - SETPOS
+ * 3 - GOTO
+ * 4 - LOOK
+ * 5 - SAY
+ * 6 - TAKE
+ * 9 - WALK
+ * 10 - TALK
+ * 11 - END
+ * 14 - SET
+ * 15 - SHOW
+ * 16 - HIDE
+ * 17 - DIALOG
+ * 18 - ZBUFFER
+ * 19 - TOTALINIT
+ * 20 - ANIMATE
+ * 21 - STATUS
+ * 22 - ADDINV
+ * 23 - DELINV
+ * 24 - STOP
+ * 25 - CURSOR
+ * 26 - OBJECTUSE
+ * 27 - ACTIVE
+ * 28 - SAID
+ * 29 - SETSEQ
+ * 30 - ENDSEQ
+ * 31 - CHECK
+ * 32 - IF
+ * 33 - DESCRIPTION
+ * 34 - HALF
+ * 36 - WALKTO
+ * 37 - WALKVICH
+ * 38 - INITBG
+ * 39 - USERMSG
+ * 40 - SYSTEM
+ * 41 - SETZBUFFER
+ * 42 - CONTINUE
+ * 43 - MAP
+ * 44 - PASSIVE
+ * 45 - NOMAP
+ * 46 - SETINV
+ * 47 - BGSFX
+ * 48 - MUSIC
+ * 49 - IMAGE
+ * 50 - STAND,
+ * 51 - ON
+ * 52 - OFF
+ * 53 - PLAY
+ * 54 - LEAVEBG
+ * 55 - SHAKE
+ * 56 - SP
+ * 57 - RANDOM
+ * 58 - JUMP
+ * 59 - JUMPVICH
+ * 60 - PART
+ * 61 - CHAPTER
+ * 62 - AVI
+ * 63 - TOMAP
* ÑиÑло 0..0xffff
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ce51ef530..cab797b6b 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.2o 2014-05-23"
+VERSION = "v0.3 2014-06-03"
def hlesc(value):
if value is None:
@@ -73,7 +73,7 @@ def translit(text):
allcaps = True
for ch in text:
ps = ru.find(ch)
- if ps > 0:
+ if ps >= 0:
ret += en[ps]
elif ch in sl:
ret += sl[ch]
@@ -361,6 +361,13 @@ class App(tkinter.Frame):
menutran.add_command(
command = self.on_tran_load,
label = "Load translation (.po)")
+ menutran.add_separator()
+ menutran.add_command(
+ command = self.on_tran_save_lod,
+ label = "Save DIALOGUE.LOD")
+ menutran.add_command(
+ command = self.on_tran_save_names,
+ label = "Save NAMES.INI")
self.menuhelp = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuhelp,
@@ -1444,8 +1451,10 @@ class App(tkinter.Frame):
self.update_gui("Messages ({})".format(len(self.sim.msgs)))
for idx, msg in enumerate(self.sim.msgs):
capt = msg.name
- if len(capt) > 25:
- capt = capt[:25] + "|"
+ if self.tran:
+ capt = self._t(msg.name, "msg")
+ if len(capt) > 40:
+ capt = capt[:40] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt),
["msgs", idx], idx)
# change
@@ -1902,6 +1911,70 @@ class App(tkinter.Frame):
self.add_info("Error opening \"{}\" \n\n{}".\
format(hlesc(fn), hlesc(traceback.format_exc())))
+ def on_tran_save_lod(self):
+ # save dialog
+ if not self.sim: return
+ if len(self.sim.msgs) == 0 or not self.tran:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("No messages or translations loaded")
+ return
+ fn = filedialog.asksaveasfilename(parent = self,
+ title = "Save DIALOGUE.LOD",
+ filetypes = [('DIALOGUE.LOD', ".lod"), ('all files', '.*')],
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return # save canceled
+ # save template
+ try:
+ sim2 = petka.Engine()
+ sim2.init_empty("cp1251")
+ for msg in self.sim.msgs:
+ nmsg = petka.engine.MsgObject(msg.idx, msg.msg_wav,
+ msg.msg_arg1, msg.msg_arg2, msg.msg_arg3)
+ nmsg.name = self._t(msg.name, "msg")
+ sim2.msgs.append(nmsg)
+ f = open(fn, "wb")
+ try:
+ sim2.write_lod(f)
+ finally:
+ f.close()
+ except:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Error saving \"{}\" \n\n{}".\
+ format(hlesc(fn), hlesc(traceback.format_exc())))
+
+ def on_tran_save_names(self):
+ # save dialog
+ if not self.sim: return
+ if len(self.sim.msgs) == 0 or not self.tran:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("No messages or translations loaded")
+ return
+ fn = filedialog.asksaveasfilename(parent = self,
+ title = "Save NAMES.INI",
+ filetypes = [('NAMES.INI', ".ini"), ('all files', '.*')],
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return # save canceled
+ # save template
+ try:
+ f = open(fn, "wb")
+ def write(msg):
+ f.write("{}\n".format(msg).encode("cp1251"))
+ try:
+ write("[all]")
+ for name in self.sim.namesord:
+ write(name + "=" + self._t(self.sim.names[name], "name"))
+ finally:
+ f.close()
+ except:
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Error saving \"{}\" \n\n{}".\
+ format(hlesc(fn), hlesc(traceback.format_exc())))
+
+
def main():
root = tkinter.Tk()
app = App(master = root)
Commit: 2e1f405a36c027a203616b40f61bdb1ad67f1743
https://github.com/scummvm/scummvm-tools/commit/2e1f405a36c027a203616b40f61bdb1ad67f1743
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fixes
Changed paths:
engines/petka/dist/setup.py
engines/petka/help/translate.txt
diff --git a/engines/petka/dist/setup.py b/engines/petka/dist/setup.py
index fabaabf85..f3dd7fcce 100644
--- a/engines/petka/dist/setup.py
+++ b/engines/petka/dist/setup.py
@@ -17,7 +17,7 @@ buildOptions = dict(packages = ["re", "io", "PIL", "traceback", "zlib", "gzip",
executables = [
Executable('p12explore.py',
base = 'Win32GUI',
- targetName = "p12explore.exe")
+ targetName = "p12explore.exe"),
Executable('p12script.py',
base = 'Console',
targetName = "p12script.exe")
diff --git a/engines/petka/help/translate.txt b/engines/petka/help/translate.txt
index c059d68b3..1b883ba26 100644
--- a/engines/petka/help/translate.txt
+++ b/engines/petka/help/translate.txt
@@ -6,8 +6,15 @@
* СоздаÑÑ Ñаблон в ÑÑанÑлиÑе ÑоÑмаÑе POT
(Translation->Save transliterate template)
* ÐагÑÑзиÑÑ Ð¿ÐµÑевод из Ñайла PO (Translation->Save translation)
- * ÐокаÑваÑÑ Ð¿ÐµÑевод названий и ÑекÑÑов Ñ Ð²ÑеÑ
обÑекÑов
-
+ * СоÑ
ÑаниÑÑ Ð¿ÐµÑевод ÑÑбÑиÑÑов (Ñайл DIALOGUE.LOD)
+ * СоÑ
ÑаниÑÑ Ð¿ÐµÑевод названий обÑекÑов (Ñайл NAMES.INI)
+
+ÐÑли пеÑевод загÑÑжен пÑогÑамма бÑÐ´ÐµÑ Ð°Ð²ÑомаÑиÑеÑки показÑваÑÑ Ð¿ÐµÑевод
+ названий и ÑекÑÑов Ñ Ð²ÑеÑ
обÑекÑов.
+
+ÐÑимеÑание: Ð´Ð»Ñ Ñого ÑÑÐ¾Ð±Ñ ÑÐ°Ð¹Ð»Ñ DIALOGUE.LOD и NAMES.INI подгÑÑжалиÑÑ Ð²Ð¾ вÑемÑ
+ ÑабоÑÑ Ð½ÐµÐ¾Ð±Ñ
одимо пÑедваÑиÑелÑно ÑаÑпаковаÑÑ MAIN.STR.
+
ÐÐ»Ñ ÑабоÑÑ ÑÑиÑ
ÑÑнкÑий необÑ
одима библиоÑека polib.
* https://pypi.python.org/pypi/polib
Commit: 75743464dbc7d8a11c8d562f53677e23ff53c0e9
https://github.com/scummvm/scummvm-tools/commit/75743464dbc7d8a11c8d562f53677e23ff53c0e9
Author: romiq (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: license.txt оÑÑедакÑиÑован онлайн на Bitbucket
Changed paths:
engines/petka/help/license.txt
diff --git a/engines/petka/help/license.txt b/engines/petka/help/license.txt
index fbdb990e3..f70526734 100644
--- a/engines/petka/help/license.txt
+++ b/engines/petka/help/license.txt
@@ -1,4 +1,4 @@
-ÐиÑении
+ÐиÑензии
ÐÐ°Ð½Ð½Ð°Ñ Ð¿ÑогÑамма поÑÑавлÑеÑÑÑ Ð¿Ð¾Ð´ лиÑензией MIT.
Commit: 8aa21d6ce28cbedb8d67bfbfa26d620da0176c7d
https://github.com/scummvm/scummvm-tools/commit/8aa21d6ce28cbedb8d67bfbfa26d620da0176c7d
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Add opcodes and dialog opcodes statistic
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index cab797b6b..62e7140e4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -263,6 +263,8 @@ class App(tkinter.Frame):
self.path_handler["msgs"] = self.path_msgs
self.path_handler["dlgs"] = self.path_dlgs
self.path_handler["casts"] = self.path_casts
+ self.path_handler["opcodes"] = self.path_opcodes
+ self.path_handler["dlgops"] = self.path_dlgops
self.path_handler["test"] = self.path_test
self.path_handler["about"] = self.path_about
self.path_handler["support"] = self.path_support
@@ -329,6 +331,12 @@ class App(tkinter.Frame):
self.menuedit.add_command(
command = lambda: self.open_path("/dlgs"),
label = "Dialog groups")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/opcodes"),
+ label = "Opcodes")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/dlgops"),
+ label = "Dialog opcodes")
self.menunav = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menunav,
@@ -763,11 +771,16 @@ class App(tkinter.Frame):
return self.tran["_"][value]
return value
- def fmt_opcode(self, opcode):
+ def fmt_opcode(self, opcode, nofmt = False):
+ if nofmt:
+ return petka.OPCODES.get(opcode, ["OP{:04X}".format(opcode)])[0]
return petka.OPCODES.get(opcode, ["<font color=\"red\">OP{:04X}</font>".\
format(opcode)])[0]
- def fmt_dlgop(self, opcode):
+ def fmt_dlgop(self, opcode, nofmt = False):
+ if nofmt:
+ return petka.DLGOPS.get(opcode, ["OP{:02X}".\
+ format(opcode)])[0]
return petka.DLGOPS.get(opcode, ["<font color=\"red\">OP{:02X}</font>".\
format(opcode)])[0]
@@ -853,6 +866,9 @@ class App(tkinter.Frame):
scn = self.fmt_hl_scene(scene.idx, True)
break
self.add_info(" Start scene: {}\n".format(scn))
+ self.add_info("\n")
+ self.add_info(" <a href=\"/opcodes\">Opcodes</a>\n")
+ self.add_info(" <a href=\"/dlgops\">Dialog opcodes</a>\n")
def path_default(self, path):
@@ -878,6 +894,8 @@ class App(tkinter.Frame):
("Casts ({})".format(len(self.sim.casts)), "/casts"),
("Messages ({})".format(len(self.sim.msgs)), "/msgs"),
("Dialog groups ({})".format(len(self.sim.dlgs)), "/dlgs"),
+ ("Opcodes", "/opcodes"),
+ ("Dialog opcodes", "/dlgops"),
#("-", None),
#("Test image", ["test", "image"]),
#("Test info", ["test","info"]),
@@ -1413,7 +1431,6 @@ class App(tkinter.Frame):
return self.path_std_items(path, 1, "Invntr", "invntr", "obj",
self.sim.invntr, self.sim.invntrord, 0, info)
-
def path_casts(self, path):
if self.sim is None:
return self.path_default([])
@@ -1643,6 +1660,215 @@ class App(tkinter.Frame):
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
+ def path_opcodes(self, path):
+ if self.sim is None:
+ return self.path_default([])
+ self.switch_view(0)
+ keys = None
+ def keyslist():
+ opstat = {} # opcpdes count
+ acstat = {} # handlers count
+ dastat = {} # dialog handlers count
+ keys = list(petka.OPCODES.keys())
+ for rec in self.sim.objects + self.sim.scenes:
+ for act in rec.acts:
+ acstat[act.act_op] = acstat.get(act.act_op, 0) + 1
+ if act.act_op not in keys:
+ keys.append(act.act_op)
+ for op in act.ops:
+ opstat[op.op_code] = opstat.get(op.op_code,
+ 0) + 1
+ if op.op_code not in keys:
+ keys.append(op.op_code)
+ for grp in self.sim.dlgs:
+ for act in grp.acts:
+ dastat[act.opcode] = dastat.get(act.opcode, 0) + 1
+ if act.opcode not in keys:
+ keys.append(act.opcode)
+ keys.sort()
+ return keys, opstat, acstat, dastat
+ if self.last_path[:1] != ("opcodes",):
+ # calc statistics
+ keys, opstat, acstat, dastat = keyslist()
+ self.update_gui("Opcodes ({})".format(len(keys)))
+ for key in keys:
+ self.insert_lb_act("{} - {}".format(key, self.fmt_opcode(key,
+ True)), ["opcodes", key], key)
+ # change
+ opcode = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ opcode = path[1]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ if not opcode:
+ if len(path) > 1:
+ self.add_info("<b>Opcode </b> \"{}\" not found\n\n".format(
+ path[1]))
+ self.add_info("<b>Opcodes</b>\n\n")
+ # display
+ if not keys:
+ keys, opstat, acstat, dastat = keyslist()
+ for key in keys:
+ opname = self.fmt_opcode(key)
+ msg = " {:2} (0x{:02X})".format(key, key,
+ opname)
+ mcnt = len(msg)
+ msg += " - {}".format(fmt_hl("/opcodes/{}".format(
+ key), opname))
+ mcnt += len(self.fmt_opcode(key, True))
+ while mcnt < 23:
+ msg += " "
+ mcnt += 1
+ msg += "{:4d} {:4d} {:4d}".format(
+ opstat.get(key, 0),
+ acstat.get(key, 0),
+ dastat.get(key, 0))
+ self.add_info(msg + "\n")
+ else:
+ # grp info
+ self.add_info("<b>Opcode {}</b>\n\n".format(
+ self.fmt_opcode(opcode)))
+ ops = []
+ acts = []
+ dacts = []
+ for rec in self.sim.objects + self.sim.scenes:
+ for aidx, act in enumerate(rec.acts):
+ if act.act_op == opcode:
+ acts.append([rec.idx, aidx])
+ for oidx, op in enumerate(act.ops):
+ if op.op_code == opcode:
+ ops.append([rec.idx, aidx, oidx])
+ for gidx, grp in enumerate(self.sim.dlgs):
+ for aidx, act in enumerate(grp.acts):
+ if act.opcode == opcode and act.ref not in dacts:
+ dacts.append([act.ref, gidx, aidx])
+ # display
+ if len(ops) == 0:
+ self.add_info("<i>Not used in scripts</i>\n\n")
+ else:
+ self.add_info("<i>Used in scripts</i>: {}\n".format(len(ops)))
+ for idx, (obj_idx, aidx, oidx) in enumerate(ops):
+ self.add_info(" {}) obj={}, act={}, op={} {}\n".format(
+ idx, self.fmt_hl_obj_scene(obj_idx, False), aidx, oidx,
+ self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
+ True))))
+ self.add_info("\n")
+
+ if len(acts) == 0:
+ self.add_info("<i>Not used in handlers</i>\n\n")
+ else:
+ self.add_info("<i>Used in handlers</i>: {}\n".format(len(acts)))
+ for idx, (obj_idx, aidx) in enumerate(acts):
+ self.add_info(" {}) obj={}, act={} {}\n".format(
+ idx, self.fmt_hl_obj_scene(obj_idx, False), aidx,
+ self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
+ True))))
+ self.add_info("\n")
+
+ if len(dacts) == 0:
+ self.add_info("<i>Not used in dialog handlers</i>\n\n")
+ else:
+ self.add_info("<i>Used in dialog handlers</i>: {}\n".format(
+ len(dacts)))
+ for idx, (obj_idx, gidx, aidx) in enumerate(dacts):
+ self.add_info(" {}) obj={}, group=<a href=\"/dlgs/{}\">{}"
+ "</a>, act={} {}\n".format(
+ idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
+ aidx, self.fmt_cmt("// " + self.fmt_hl_obj_scene(
+ obj_idx, True))))
+ self.add_info("\n")
+
+ def path_dlgops(self, path):
+ if self.sim is None:
+ return self.path_default([])
+ self.switch_view(0)
+ keys = None
+ def keyslist():
+ dlstat = {} # dialog opcodes count
+ keys = list(petka.DLGOPS.keys()) + [5, 9]
+ for grp in self.sim.dlgs:
+ for act in grp.acts:
+ for dlg in act.dlgs:
+ for op in dlg.ops:
+ dlstat[op.opcode] = dlstat.get(op.opcode, 0) + 1
+ if op.opcode not in keys:
+ keys.append(op.opcode)
+ keys.sort()
+ return keys, dlstat
+ if self.last_path[:1] != ("dlgops",):
+ # calc statistics
+ keys, dlstat = keyslist()
+ self.update_gui("Dialog opcodes ({})".format(len(keys)))
+ for key in keys:
+ self.insert_lb_act("{} - {}".format(key, self.fmt_dlgop(key,
+ True)), ["dlgops", key], key)
+ # change
+ opcode = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ opcode = path[1]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ if not opcode:
+ if len(path) > 1:
+ self.add_info("<b>Dialog opcode </b> \"{}\" not found\n\n".\
+ format(path[1]))
+ self.add_info("<b>Dialog opcodes</b>\n\n")
+ # display
+ if not keys:
+ keys, dlstat = keyslist()
+ for key in keys:
+ opname = self.fmt_dlgop(key)
+ msg = " {:2} (0x{:02X})".format(key, key, opname)
+ mcnt = len(msg)
+ msg += " - {}".format(fmt_hl("/dlgops/{}".format(
+ key), opname))
+ mcnt += len(self.fmt_dlgop(key, True))
+ while mcnt < 20:
+ msg += " "
+ mcnt += 1
+ msg += "{:4d}".format(dlstat.get(key, 0))
+ self.add_info(msg + "\n")
+ else:
+ # grp info
+ self.add_info("<b>Dialog opcode {}</b>\n\n".format(
+ self.fmt_dlgop(opcode)))
+ dls = []
+ for gidx, grp in enumerate(self.sim.dlgs):
+ for aidx, act in enumerate(grp.acts):
+ for didx, dlg in enumerate(act.dlgs):
+ for oidx, op in enumerate(dlg.ops):
+ if op.opcode == opcode:
+ dls.append([act.ref, gidx, aidx, didx, oidx])
+
+
+ # display
+ if len(dls) == 0:
+ self.add_info("<i>Not used in dialogs</i>\n\n")
+ else:
+ self.add_info("<i>Used in dialogs</i>: {}\n".format(len(dls)))
+ for idx, (obj_idx, gidx, aidx, didx, oidx) in enumerate(dls):
+ self.add_info(" {}) obj={}, group=<a href=\"/dlgs/{}\">{}"
+ "</a>, act={}, dlg={}, op={} {}\n".format(
+ idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
+ aidx, didx, oidx, self.fmt_cmt("// " +
+ self.fmt_hl_obj_scene(obj_idx, True))))
+ self.add_info("\n")
+
+
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
self.insert_lb_act("Outline", [])
Commit: 736358e9a05f0f6fb056abcef51e56731383a2e8
https://github.com/scummvm/scummvm-tools/commit/736358e9a05f0f6fb056abcef51e56731383a2e8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix group display
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 62e7140e4..19c67e03d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1745,10 +1745,10 @@ class App(tkinter.Frame):
for oidx, op in enumerate(act.ops):
if op.op_code == opcode:
ops.append([rec.idx, aidx, oidx])
- for gidx, grp in enumerate(self.sim.dlgs):
+ for grp in self.sim.dlgs:
for aidx, act in enumerate(grp.acts):
if act.opcode == opcode and act.ref not in dacts:
- dacts.append([act.ref, gidx, aidx])
+ dacts.append([act.ref, grp.idx, aidx])
# display
if len(ops) == 0:
self.add_info("<i>Not used in scripts</i>\n\n")
@@ -1847,12 +1847,12 @@ class App(tkinter.Frame):
self.add_info("<b>Dialog opcode {}</b>\n\n".format(
self.fmt_dlgop(opcode)))
dls = []
- for gidx, grp in enumerate(self.sim.dlgs):
+ for grp in self.sim.dlgs:
for aidx, act in enumerate(grp.acts):
for didx, dlg in enumerate(act.dlgs):
for oidx, op in enumerate(dlg.ops):
if op.opcode == opcode:
- dls.append([act.ref, gidx, aidx, didx, oidx])
+ dls.append([act.ref, grp.idx, aidx, didx, oidx])
# display
Commit: a954806273fa8570c43e2246fd587b5d492a8ce0
https://github.com/scummvm/scummvm-tools/commit/a954806273fa8570c43e2246fd587b5d492a8ce0
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix changes
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index f791b8b0f..a5296a752 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,10 @@
ЧÑо нового
==========
+2014-06-06 веÑÑÐ¸Ñ 0.3a
+----------------------
+Ðобавлена ÑÑаÑиÑÑика иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð¿ÐºÐ¾Ð´Ð¾Ð² ÑкÑипÑа и опкодов диалогов.
+
2014-06-03 веÑÑÐ¸Ñ 0.3
---------------------
Ðобавлен конÑолÑнÑй компилÑÑÐ¾Ñ Ð¸ декомпилÑÑÐ¾Ñ Ð´Ð»Ñ Ñайлов SCRIPT.DAT,
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 19c67e03d..9777972b3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3 2014-06-03"
+VERSION = "v0.3a 2014-06-06"
def hlesc(value):
if value is None:
@@ -1853,7 +1853,6 @@ class App(tkinter.Frame):
for oidx, op in enumerate(dlg.ops):
if op.opcode == opcode:
dls.append([act.ref, grp.idx, aidx, didx, oidx])
-
# display
if len(dls) == 0:
Commit: b33be223a70f58db183518c82f7ffc647d3d3f17
https://github.com/scummvm/scummvm-tools/commit/b33be223a70f58db183518c82f7ffc647d3d3f17
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fix loading FLC with Pillow
Changed paths:
engines/petka/petka/imgflc.py
diff --git a/engines/petka/petka/imgflc.py b/engines/petka/petka/imgflc.py
index c692db697..1af7377a2 100644
--- a/engines/petka/petka/imgflc.py
+++ b/engines/petka/petka/imgflc.py
@@ -16,6 +16,34 @@ try:
except ImportError:
pass
+FLC_HEADER = [
+ ["fsize", 1, "I", False],
+ ["ftype", 1, "H", False],
+ ["frames_num", 1, "H", True],
+ ["width", 1, "H", True],
+ ["height", 1, "H", True],
+ ["depth", 1, "H", False],
+ ["flags", 1, "H", True],
+ ["speed", 1, "I", True],
+ ["reserved1", 1, "H", False],
+ ["created", 1, "I", True],
+ ["creator", 1, "I", True],
+ ["updated", 1, "I", True],
+ ["updater", 1, "I", True],
+ ["aspect_dx", 1, "H", True],
+ ["aspect_dy", 1, "H", True],
+ ["ext_flags", 1, "H", False],
+ ["keyframes", 1, "H", False],
+ ["totalframes", 1, "H", False],
+ ["req_memory", 1, "I", False],
+ ["max_regions", 1, "H", False],
+ ["transp_num", 1, "H", False],
+ ["reserved2", 24, "s", False],
+ ["oframe1", 1, "I", False],
+ ["oframe2", 1, "i", False],
+ ["reserved3", 40, "s", False],
+]
+
class FLCLoader:
def __init__(self):
self.rgb = None
@@ -36,6 +64,149 @@ class FLCLoader:
except EOFError:
pass # end of sequence
+
+ def parseflcchunks(self, f, offset, limit, level = 0, maxchunks = None,):
+ def check_hdr(size, delta, name, offset):
+ if delta < size:
+ raise EngineError("Incorrect FLC %s chunk at 0x{:08x}".format(
+ (name, offset)))
+
+ chunks = []
+ while True:
+ if limit is not None:
+ if offset >= limit:
+ break
+ if maxchunks is not None:
+ if len(chunks) >= maxchunks:
+ break
+ chunk = {"offset": offset}
+ temp = f.read(6)
+ sz, tp = struct.unpack_from("<IH", temp)
+ offset += 6
+
+ chunk["size"] = sz
+ chunk["type"] = tp
+ delta = sz - 6
+ if delta < 0:
+ raise EngineError("Incorrect FLC chunk at 0x{:08x}".format(
+ chunk["offset"]))
+
+ raw_chunks = [
+ 0x4, # COLOR_256
+ 0x7, # DELTA_FLC
+ 0xf, # BYTE_RUN
+ 0xF100, # PREFIX_TYPE - mismaked, out destination ignore this
+ ]
+ #print("{}CHUNK 0x{:x}, size = {}".format(" "*level, tp, sz))
+ # do not parse 3rd level 0x12 chunk
+ if tp == 0x12 and level == 2:
+ tp = 0x4
+
+ # parse chunks
+ if tp in raw_chunks:
+ temp = f.read(delta)
+ offset += delta
+ chunk["data"] = temp
+ elif tp == 0x12:
+ # PSTAMP
+ check_hdr(6, delta, "PSTAMP", offset)
+ temp = f.read(6)
+ delta -= 6
+ height, width, xlate = struct.unpack_from("<3H", temp)
+ offset += 6
+ offset, subchunks = self.parseflcchunks(f, offset,
+ offset + delta, level + 1, 1)
+ chunk["chunks"] = subchunks
+ #print(subchunks)
+ elif tp == 0xF1FA:
+ # FRAME_TYPE
+ check_hdr(10, delta, "FRAME_TYPE", offset)
+ temp = f.read(10)
+ delta -= 10
+ sub_num, delay, reserved, width, height = \
+ struct.unpack_from("<5H", temp)
+ offset += 10
+ chunk["delay"] = delay
+ chunk["width"] = width
+ chunk["height"] = height
+ offset, subchunks = self.parseflcchunks(f, offset,
+ offset + delta, level + 1, sub_num)
+ chunk["chunks"] = subchunks
+ else:
+ raise Exception("Unknown FLC chunk type 0x{:04x} at 0x{:x08x}".\
+ format(tp, offset))
+
+ chunks.append(chunk)
+
+ return offset, chunks
+
def load_data(self, f):
- self.image = Image.open(f)
+ # parse header
+ offset = 0
+ hdr_keys = []
+ hdr_struct = "<"
+ for hnam, hsz, htp, hed in FLC_HEADER:
+ hdr_keys.append(hnam)
+ if hsz == 1:
+ hdr_struct += htp
+ else:
+ hdr_struct += "%d" % hsz + htp
+
+ header = {}
+ temp = f.read(128)
+ hdr = struct.unpack_from(hdr_struct, temp)
+
+ offset += 128
+ if len(hdr) != len(hdr_keys):
+ raise EngineError("Incorrect FLC header {} != {}".format(
+ len(hdr), len(hdr_keys)))
+ for hid in range(len(hdr)):
+ header[hdr_keys[hid]] = hdr[hid]
+
+ if header["ftype"] != 0xAF12:
+ raise EngineError("Unsupported FLC type (0x{:04x})".format(
+ header["ftype"]))
+
+ # check if not EGI ext
+ if header["creator"] == 0x45474900:
+ if header["ext_flags"] != 0:
+ raise EngineError("Unsupported FLC EGI extension")
+
+ # NOTE: we recreate FLC to avoid Pilllow bug
+ # 1. remove 0xf100 chunk (PREFIX, implementation specific)
+ # 2. remobe 0x12 subchunk (PSTAMP) from 1st frame
+
+ # read chunks
+ _, chunks = self.parseflcchunks(f, offset, header["fsize"])
+
+ f.seek(0)
+ buf = io.BytesIO()
+ buf.write(f.read(128)) # clone header
+ for chunk in chunks:
+ if chunk["type"] == 0xF100:
+ continue
+ elif chunk["type"] == 0xF1FA:
+ rebuild = False
+ nchunks = []
+ nsz = 16 # I6H - type, size, sub_num, delay,
+ # reserved, width, height
+ for schunk in chunk["chunks"]:
+ if schunk["type"] == 0x12: # detect mailformed PSTAMP
+ rebuild = True
+ elif rebuild:
+ nchunks.append(schunk)
+ nsz += schunk["size"]
+ if rebuild:
+ buf.write(struct.pack("<I6H", nsz, 0xF1FA, len(nchunks),
+ chunk["delay"], 0, chunk["width"], chunk["height"]))
+ for schunk in nchunks:
+ f.seek(schunk["offset"])
+ buf.write(f.read(schunk["size"]))
+ continue
+ # copy chunk
+ buf.write(f.read(chunk["size"]))
+
+ buf.seek(0)
+ self.image = Image.open(buf)
+
Commit: aa0c112ff3edbe9749608ddb255f2c99ced683c1
https://github.com/scummvm/scummvm-tools/commit/aa0c112ff3edbe9749608ddb255f2c99ced683c1
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: changes
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index a5296a752..cf6cbd40b 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,10 @@
ЧÑо нового
==========
+2014-06-10 веÑÑÐ¸Ñ 0.3b
+----------------------
+ÐÑпÑавлена загÑÑзка палиÑÑÑ FLC Ñайлов.
+
2014-06-06 веÑÑÐ¸Ñ 0.3a
----------------------
Ðобавлена ÑÑаÑиÑÑика иÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð¿ÐºÐ¾Ð´Ð¾Ð² ÑкÑипÑа и опкодов диалогов.
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 9777972b3..4dd0d4396 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3a 2014-06-06"
+VERSION = "v0.3b 2014-06-10"
def hlesc(value):
if value is None:
Commit: b380b5dfc8f01819521b25ac591418d9108638cd
https://github.com/scummvm/scummvm-tools/commit/b380b5dfc8f01819521b25ac591418d9108638cd
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: add stores info
Changed paths:
A engines/petka/help/strs.txt
engines/petka/help/changes.txt
engines/petka/help/cmdline.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index cf6cbd40b..c58820cd0 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,9 @@
ЧÑо нового
==========
+2014-12-20 веÑÑÐ¸Ñ 0.3c
+----------------------
+ÐÑобÑажение загÑÑженнÑÑ
Ñ
ÑÐ°Ð½Ð¸Ð»Ð¸Ñ (.str)
+ÐагÑÑзка Ñ
ÑÐ°Ð½Ð¸Ð»Ð¸Ñ Ð¸Ð· оÑделÑнÑÑ
Ñайлов
2014-06-10 веÑÑÐ¸Ñ 0.3b
----------------------
diff --git a/engines/petka/help/cmdline.txt b/engines/petka/help/cmdline.txt
index 9e578f0dd..52d7c8549 100644
--- a/engines/petka/help/cmdline.txt
+++ b/engines/petka/help/cmdline.txt
@@ -2,8 +2,14 @@
СинÑакÑÐ¸Ñ Ð²Ñзова пÑогÑÐ°Ð¼Ð¼Ñ Ð¸Ð· коммандной ÑÑÑоки
+ÐÑкÑÑÑÑ Ð´Ð°Ð½Ð½Ñе
+
p12explore [-d пÑÑÑ Ðº даннÑм]|[-t пÑÑÑ Ðº пеÑеводÑ]|[оÑкÑÑваемÑй Ñаздел]
+ÐÑкÑÑÑÑ Ñ
ÑанилиÑе
+
+ p12explore [-s пÑÑÑ Ðº .str]
+
ÐÑÑÑ Ðº даннÑм - пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð¸Ð»Ð¸ каÑÐ°Ð»Ð¾Ð³Ñ Ð³Ð´Ðµ наÑ
одиÑÑÑ Ñайл Ñ Ð´Ð°Ð½Ð½Ñми.
ÐÑновнÑе ÑазделÑ:
@@ -16,6 +22,7 @@
* /scenes - ÑÑенÑ
* /msgs - ÑообÑениÑ
* /dlgs - гÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²
+ * /strs - Ñ
ÑанилиÑа
Так как поÑле оÑкÑÑÑÐ¸Ñ Ð´Ð°Ð½Ð½ÑÑ
даннÑе о пеÑеводе ÑдалÑÑÑÑÑ Ñо ÑекомендÑеÑÑÑ
ÑледÑÑÑий поÑÑдок загÑÑзки:
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 1b5b8f78c..e159406ec 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -1,6 +1,6 @@
СпÑавка
-ÐеÑÑиÑ: 0.3 2014-06-03
+ÐеÑÑиÑ: 0.3c 2014-12-20
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
@@ -17,6 +17,7 @@
* <a href="/help/casts">ЦвеÑа пÑедмеÑов</a>
* <a href="/help/msgs">СобÑениÑ</a>
* <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
+ * <a href="/help/strs">Ð¥ÑанилиÑа</a>
ÐÑоÑÐ°Ñ Ð¸Ð½ÑоÑмаÑиÑ
diff --git a/engines/petka/help/list b/engines/petka/help/list
index 0bc2a2ba0..c8a65be21 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -11,6 +11,7 @@ invntr
casts
msgs
dlgs
+strs
translate
cmdline
support
diff --git a/engines/petka/help/strs.txt b/engines/petka/help/strs.txt
new file mode 100644
index 000000000..eca1839f6
--- /dev/null
+++ b/engines/petka/help/strs.txt
@@ -0,0 +1,5 @@
+Ð¥ÑанилиÑа
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð²Ñе загÑÑженнÑе Ñ
ÑанилиÑа и иÑ
ÑодеÑжимое.
+
+
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 4dd0d4396..22211bfa4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3b 2014-06-10"
+VERSION = "v0.3c 2014-12-20"
def hlesc(value):
if value is None:
@@ -158,7 +158,7 @@ class App(tkinter.Frame):
master.title(APPNAME)
self.pack(fill = tkinter.BOTH, expand = 1)
self.pad = None
- self.sim = None
+ self.clear_data()
# path
if hasattr(sys, 'frozen'):
self.app_path = sys.executable
@@ -184,13 +184,18 @@ class App(tkinter.Frame):
self.need_update = False
self.canv_view_fact = 1
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
- # translation
- self.tran = None
# add on_load handler
self.after_idle(self.on_first_display)
- def create_widgets(self):
+ def clear_data(self):
+ self.sim = None
+ # store manager
+ self.strfm = None
+ # translation
+ self.tran = None
+
+ def create_widgets(self):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
ttk.Style().configure('Info.TFrame', background = 'white', \
@@ -270,6 +275,7 @@ class App(tkinter.Frame):
self.path_handler["support"] = self.path_support
self.path_handler["help"] = self.path_help
self.path_handler["info"] = self.path_info
+ self.path_handler["strs"] = self.path_stores
self.update_after()
repath = "/about"
@@ -277,6 +283,9 @@ class App(tkinter.Frame):
if cmd == "load":
self.open_data_from(arg)
repath = "/"
+ elif cmd == "str":
+ self.open_str_from(arg)
+ repath = "/"
elif cmd == "tran":
self.open_tran_from(arg)
elif cmd == "open":
@@ -296,6 +305,10 @@ class App(tkinter.Frame):
command = self.on_open_data,
label = "Open data...")
self.menufile.add_separator()
+ self.menufile.add_command(
+ command = self.on_open_str,
+ label = "Open STR...")
+ self.menufile.add_separator()
self.menufile.add_command(
command = self.on_exit,
label = "Quit")
@@ -337,6 +350,9 @@ class App(tkinter.Frame):
self.menuedit.add_command(
command = lambda: self.open_path("/dlgops"),
label = "Dialog opcodes")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/strs"),
+ label = "Stores")
self.menunav = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menunav,
@@ -839,37 +855,42 @@ class App(tkinter.Frame):
return self.fmt_hl_rec(self.sim.dlg_idx, "dlgs", grp_id, full, "dlg")
def path_info_outline(self):
- if self.sim is None:
+ if self.sim is None and self.strfm is None:
self.add_info("No data loaded. Open PARTS.INI or SCRIPT.DAT first.")
return
- self.add_info("Current part {} chapter {}\n\n".\
- format(self.sim.curr_part, self.sim.curr_chap))
- self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
- format(len(self.sim.res)))
- self.add_info(" Objects: <a href=\"/objs\">{}</a>\n".\
- format(len(self.sim.objects)))
- self.add_info(" Scenes: <a href=\"/scenes\">{}</a>\n".\
- format(len(self.sim.scenes)))
- self.add_info(" Names: <a href=\"/names\">{}</a>\n".\
- format(len(self.sim.names)))
- self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
- format(len(self.sim.invntr)))
- self.add_info(" Casts: <a href=\"/casts\">{}</a>\n".\
- format(len(self.sim.casts)))
- self.add_info(" Messages <a href=\"/msgs\">{}</a>\n".\
- format(len(self.sim.msgs)))
- self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
- format(len(self.sim.dlgs)))
- scn = hlesc(self.sim.start_scene)
- for scene in self.sim.scenes:
- if scene.name == self.sim.start_scene:
- scn = self.fmt_hl_scene(scene.idx, True)
- break
- self.add_info(" Start scene: {}\n".format(scn))
- self.add_info("\n")
- self.add_info(" <a href=\"/opcodes\">Opcodes</a>\n")
- self.add_info(" <a href=\"/dlgops\">Dialog opcodes</a>\n")
-
+ if self.sim:
+ self.add_info("Current part {} chapter {}\n\n".\
+ format(self.sim.curr_part, self.sim.curr_chap))
+ self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
+ format(len(self.sim.res)))
+ self.add_info(" Objects: <a href=\"/objs\">{}</a>\n".\
+ format(len(self.sim.objects)))
+ self.add_info(" Scenes: <a href=\"/scenes\">{}</a>\n".\
+ format(len(self.sim.scenes)))
+ self.add_info(" Names: <a href=\"/names\">{}</a>\n".\
+ format(len(self.sim.names)))
+ self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
+ format(len(self.sim.invntr)))
+ self.add_info(" Casts: <a href=\"/casts\">{}</a>\n".\
+ format(len(self.sim.casts)))
+ self.add_info(" Messages <a href=\"/msgs\">{}</a>\n".\
+ format(len(self.sim.msgs)))
+ self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
+ format(len(self.sim.dlgs)))
+ scn = hlesc(self.sim.start_scene)
+ for scene in self.sim.scenes:
+ if scene.name == self.sim.start_scene:
+ scn = self.fmt_hl_scene(scene.idx, True)
+ break
+ self.add_info(" Start scene: {}\n".format(scn))
+ self.add_info("\n")
+ self.add_info(" <a href=\"/opcodes\">Opcodes</a>\n")
+ self.add_info(" <a href=\"/dlgops\">Dialog opcodes</a>\n\n")
+
+ if self.strfm:
+ self.add_info(" Opened stores: <a href=\"/strs\">{}</a>\n".
+ format(len(self.strfm.strfd)))
+
def path_default(self, path):
self.switch_view(0)
@@ -902,6 +923,12 @@ class App(tkinter.Frame):
]
for name, act in acts:
self.insert_lb_act(name, act)
+ if self.strfm is not None:
+ acts = [
+ ("Stores ({})".format(len(self.strfm.strfd)), "/strs"),
+ ]
+ for name, act in acts:
+ self.insert_lb_act(name, act)
def path_parts(self, path):
if self.sim is None:
@@ -1867,6 +1894,39 @@ class App(tkinter.Frame):
self.fmt_hl_obj_scene(obj_idx, True))))
self.add_info("\n")
+ def path_stores(self, path):
+ if self.strfm is None:
+ return self.path_default([])
+ self.switch_view(0)
+ keys = None
+ if self.last_path[:1] != ("strs",):
+ # calc statistics
+ self.update_gui("Stores ({})".format(len(self.strfm.strfd)))
+ for idx, st in enumerate(self.strfm.strfd):
+ self.insert_lb_act("{}".format(st[1]), ["strs", idx], idx)
+ # change
+ stid = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ stid = path[1]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ if not stid:
+ self.add_info("<b>Stores</b>\n\n")
+ for idx, st in enumerate(self.strfm.strfd):
+ self.add_info(" {}) <a href=\"/strs/{}\">{}</a> - {}\n".format(
+ idx + 1, idx, st[1], st[2]))
+ else:
+ self.add_info("<b>Store</b>: {}\n".format(self.strfm.strfd[stid][1]))
+ pass
+
+
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
@@ -2038,15 +2098,16 @@ class App(tkinter.Frame):
def open_data_from(self, folder):
self.last_fn = folder
+ self.clear_data()
try:
- self.tran = None
self.sim = petka.Engine()
self.sim.load_data(folder, "cp1251")
+ self.strfm = self.sim.fman
self.sim.open_part(0, 0)
return True
except:
print("DEBUG: Error opening")
- self.sim = None
+ self.clear_data()
self.switch_view(0)
self.update_gui("")
self.clear_info()
@@ -2054,6 +2115,37 @@ class App(tkinter.Frame):
format(hlesc(folder), hlesc(traceback.format_exc())))
#self.clear_hist()
+ def on_open_str(self):
+ ft = [\
+ ('STR files', '.STR'),
+ ('all files', '.*')]
+ fn = filedialog.askopenfilename(parent = self,
+ title = "Open STR file",
+ filetypes = ft,
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return
+ os.chdir(os.path.dirname(fn))
+ self.clear_hist()
+ if self.open_str_from(fn):
+ self.open_path("")
+ self.clear_hist()
+
+ def open_str_from(self, fn):
+ self.last_fn = fn
+ self.clear_data()
+ try:
+ self.strfm = petka.FileManager(os.path.dirname(fn))
+ self.strfm.load_store(os.path.basename(fn))
+ return True
+ except:
+ print("DEBUG: Error opening")
+ self.clear_data()
+ self.switch_view(0)
+ self.update_gui("")
+ self.clear_info()
+ self.add_info("Error opening \"{}\" \n\n{}".\
+ format(hlesc(fn), hlesc(traceback.format_exc())))
+
def on_tran_save(self):
self.on_tran_save_real()
@@ -2208,6 +2300,9 @@ def main():
if argv[0] == "-d": # open data
app.start_act.append(["load", argv[1]])
argv = argv[2:]
+ elif argv[0] == "-s": # open str file
+ app.start_act.append(["str", argv[1]])
+ argv = argv[2:]
elif argv[0] == "-t": # open translation
app.start_act.append(["tran", argv[1]])
argv = argv[2:]
Commit: f30896d0193816cb44591854f1c779007465d6c2
https://github.com/scummvm/scummvm-tools/commit/f30896d0193816cb44591854f1c779007465d6c2
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Store and file view works
Changed paths:
A engines/petka/help/files.txt
engines/petka/help/changes.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
engines/petka/petka/fman.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index c58820cd0..8d691a52d 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -4,6 +4,9 @@
----------------------
ÐÑобÑажение загÑÑженнÑÑ
Ñ
ÑÐ°Ð½Ð¸Ð»Ð¸Ñ (.str)
ÐагÑÑзка Ñ
ÑÐ°Ð½Ð¸Ð»Ð¸Ñ Ð¸Ð· оÑделÑнÑÑ
Ñайлов
+ÐÑоÑмоÑÑ ÑпиÑка Ñайлов
+ТепеÑÑ ÑообÑение об оÑибке коÑÑекÑно оÑобÑажаеÑÑÑ Ð¿Ñи оÑкÑÑÑии ÑеÑез команднÑÑ
+ ÑÑÑокÑ
2014-06-10 веÑÑÐ¸Ñ 0.3b
----------------------
diff --git a/engines/petka/help/files.txt b/engines/petka/help/files.txt
new file mode 100644
index 000000000..ab776caf5
--- /dev/null
+++ b/engines/petka/help/files.txt
@@ -0,0 +1,5 @@
+ФайлÑ
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¾Ð±Ñий ÑпиÑок загÑÑженнÑÑ
Ñайлов.
+
+
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index e159406ec..cc3f644f0 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -18,6 +18,8 @@
* <a href="/help/msgs">СобÑениÑ</a>
* <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
* <a href="/help/strs">Ð¥ÑанилиÑа</a>
+ * <a href="/help/files">ФайлÑ</a>
+
ÐÑоÑÐ°Ñ Ð¸Ð½ÑоÑмаÑиÑ
diff --git a/engines/petka/help/list b/engines/petka/help/list
index c8a65be21..332e97473 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -12,6 +12,7 @@ casts
msgs
dlgs
strs
+files
translate
cmdline
support
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 22211bfa4..fc2afa0b5 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -276,21 +276,31 @@ class App(tkinter.Frame):
self.path_handler["help"] = self.path_help
self.path_handler["info"] = self.path_info
self.path_handler["strs"] = self.path_stores
+ self.path_handler["files"] = self.path_files
self.update_after()
repath = "/about"
for cmd, arg in self.start_act:
if cmd == "load":
- self.open_data_from(arg)
- repath = "/"
+ if not self.open_data_from(arg):
+ repath = ""
+ break
elif cmd == "str":
- self.open_str_from(arg)
- repath = "/"
+ if not self.open_str_from(arg):
+ repath = ""
+ break
+ else:
+ repath = "/strs"
elif cmd == "tran":
- self.open_tran_from(arg)
+ if not self.open_tran_from(arg):
+ repath = ""
+ break
elif cmd == "open":
- self.open_path(arg)
- repath = ""
+ if not self.open_path(arg):
+ repath = ""
+ break
+ else:
+ repath = "/"
if repath:
self.open_path(repath)
@@ -353,6 +363,9 @@ class App(tkinter.Frame):
self.menuedit.add_command(
command = lambda: self.open_path("/strs"),
label = "Stores")
+ self.menuedit.add_command(
+ command = lambda: self.open_path("/files"),
+ label = "Files")
self.menunav = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menunav,
@@ -877,6 +890,10 @@ class App(tkinter.Frame):
format(len(self.sim.msgs)))
self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
format(len(self.sim.dlgs)))
+ self.add_info(" Opened stores: <a href=\"/strs\">{}</a>\n".
+ format(len(self.strfm.strfd)))
+ self.add_info(" Files: <a href=\"/files\">{}</a>\n".
+ format(len(self.strfm.strtable)))
scn = hlesc(self.sim.start_scene)
for scene in self.sim.scenes:
if scene.name == self.sim.start_scene:
@@ -887,11 +904,13 @@ class App(tkinter.Frame):
self.add_info(" <a href=\"/opcodes\">Opcodes</a>\n")
self.add_info(" <a href=\"/dlgops\">Dialog opcodes</a>\n\n")
- if self.strfm:
+ elif self.strfm:
+ self.add_info("Single store mode\n\n")
self.add_info(" Opened stores: <a href=\"/strs\">{}</a>\n".
format(len(self.strfm.strfd)))
+ self.add_info(" Files: <a href=\"/files\">{}</a>\n".
+ format(len(self.strfm.strtable)))
-
def path_default(self, path):
self.switch_view(0)
self.update_gui("Outline")
@@ -901,7 +920,7 @@ class App(tkinter.Frame):
for item in path:
spath += "/" + str(item)
self.add_info("Path {} not found\n\n".format(spath))
- if self.sim is not None:
+ if self.sim or self.strfm:
self.add_info("Select from <b>outline</b>\n\n")
self.path_info_outline()
if self.sim is not None:
@@ -926,6 +945,7 @@ class App(tkinter.Frame):
if self.strfm is not None:
acts = [
("Stores ({})".format(len(self.strfm.strfd)), "/strs"),
+ ("Files ({})".format(len(self.strfm.strtable)), "/files"),
]
for name, act in acts:
self.insert_lb_act(name, act)
@@ -1917,17 +1937,69 @@ class App(tkinter.Frame):
self.select_lb_item(None)
# display
self.clear_info()
- if not stid:
+ if stid is None:
self.add_info("<b>Stores</b>\n\n")
for idx, st in enumerate(self.strfm.strfd):
self.add_info(" {}) <a href=\"/strs/{}\">{}</a> - {}\n".format(
idx + 1, idx, st[1], st[2]))
else:
- self.add_info("<b>Store</b>: {}\n".format(self.strfm.strfd[stid][1]))
- pass
+ if stid >= len(self.strfm.strfd):
+ self.add_info("<b>Store</b> \"{}\" not found\n\n".\
+ format(path[1]))
+ return
+ _, name, tag, strlst = self.strfm.strfd[stid]
+ self.add_info("<b>Store</b>: {}\n".format(name))
+ self.add_info(" Files: <a href=\"/files\">{}</a>, Tag: {}\n\n".
+ format(len(strlst), tag))
+ for idx, (fname, ford, pos, ln) in enumerate(strlst):
+ self.add_info(" {}) <a href=\"/files/{}\">{}</a> "
+ "(pos={}, len={})\n".format(idx + 1, ford, fname,
+ pos, ln))
+
+ def path_files(self, path):
+ if self.strfm is None:
+ return self.path_default([])
+ self.switch_view(0)
+ keys = None
+ if self.last_path[:1] != ("files",):
+ # calc statistics
+ self.update_gui("Files ({})".format(len(self.strfm.strtable)))
+ for idx, fn in enumerate(self.strfm.strtableord):
+ self.insert_lb_act(fn, ["files", idx], idx)
+ # change
+ fid = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ fid = path[1]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ if fid is None:
+ self.add_info("<b>Files</b>\n\n")
+ for idx, fn in enumerate(self.strfm.strtableord):
+ stid, pos, ln = self.strfm.strtable[fn]
+ self.add_info(" {}) <a href=\"/files/{}\">{}</a>\n".format(
+ idx + 1, idx, fn))
+ else:
+ if fid >= len(self.strfm.strtable):
+ self.add_info("<b>File</b> \"{}\" not found\n\n".\
+ format(path[1]))
+ return
+ fn = self.strfm.strtableord[fid]
+ stid, pos, ln = self.strfm.strtable[fn]
+
+ self.add_info("<b>File</b>: {}\n\n".format(fn))
+ self.add_info(" Store: <a href=\"/strs/{}\">{}</a>\n".format(stid,
+ self.strfm.strfd[stid][1]))
+ self.add_info(" Pos: {} (0x{:x})\n Len: {} (0x{:x})\n".format(
+ pos, pos, ln, ln))
+
-
-
def path_test(self, path):
self.update_gui("Test {}".format(path[1]))
self.insert_lb_act("Outline", [])
@@ -1963,11 +2035,11 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("" + APPNAME + " " + VERSION + "\n")
self.add_info("=" * 40 + "\n")
- self.add_info("<b>App folder</b>: {}\n".format(
+ self.add_info("<b>App folder</b>: {}\n".format(
hlesc(self.app_path)))
- self.add_info("<b>Game folder</b>: {}\n".format(
+ self.add_info("<b>Game folder</b>: {}\n".format(
hlesc(self.last_fn)))
- self.add_info("<b>Translation</b>: ")
+ self.add_info("<b>Translation</b>: ")
if not polib:
self.add_info("<i><u>polib</u> not found</i>\n")
else:
@@ -1976,19 +2048,29 @@ class App(tkinter.Frame):
else:
self.add_info(hlesc(self.tran_fn) + "\n")
- self.add_info("<b>Engine</b>: ")
- if self.sim is None:
+ self.add_info("<b>Engine</b>: ")
+ if not self.sim:
self.add_info("<i>not initialized</i>\n")
else:
self.add_info("<i>works</i>\n\n")
- self.add_info(" <b>Path</b>: {}\n".format(
+ self.add_info(" <b>Path</b>: {}\n".format(
hlesc(self.sim.curr_path)))
- self.add_info(" <b>Start</b>: {}.{}\n".format(
+ self.add_info(" <b>Start</b>: {}.{}\n".format(
self.sim.start_part, self.sim.start_chap))
- self.add_info(" <b>Speech</b>: {}\n".format(
+ self.add_info(" <b>Speech</b>: {}\n".format(
hlesc(self.sim.curr_speech)))
- self.add_info(" <b>Disk ID</b>: {}\n\n".format(
+ self.add_info(" <b>Disk ID</b>: {}\n\n".format(
hlesc(self.sim.curr_diskid)))
+
+ self.add_info("<b>File manager</b>: ")
+ if not self.strfm:
+ self.add_info("<i>not initialized</i>\n")
+ else:
+ self.add_info("<i>works</i>\n\n")
+ self.add_info(" <b>Path</b>: {}\n\n".format(
+ hlesc(self.strfm.root)))
+
+ if self.sim or self.strfm:
self.path_info_outline()
def path_help(self, path):
@@ -2106,14 +2188,13 @@ class App(tkinter.Frame):
self.sim.open_part(0, 0)
return True
except:
- print("DEBUG: Error opening")
+ print("DEBUG: Error opening data")
self.clear_data()
self.switch_view(0)
self.update_gui("")
self.clear_info()
self.add_info("Error opening \"{}\" \n\n{}".\
format(hlesc(folder), hlesc(traceback.format_exc())))
- #self.clear_hist()
def on_open_str(self):
ft = [\
@@ -2138,13 +2219,14 @@ class App(tkinter.Frame):
self.strfm.load_store(os.path.basename(fn))
return True
except:
- print("DEBUG: Error opening")
+ print("DEBUG: Error opening STR")
self.clear_data()
self.switch_view(0)
self.update_gui("")
self.clear_info()
self.add_info("Error opening \"{}\" \n\n{}".\
format(hlesc(fn), hlesc(traceback.format_exc())))
+
def on_tran_save(self):
self.on_tran_save_real()
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index b14ad3eea..427c9a752 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -15,7 +15,8 @@ class FileManager:
self.strfd = []
self.strtable = {}
-
+ self.strtableord = []
+
def find_path(self, path):
# search case insensive from root
dpath = []
@@ -56,17 +57,20 @@ class FileManager:
temp = f.read(12)
data = struct.unpack_from("<III", temp)
index_table.append((data[1], data[2]))
+ strlst = []
data = f.read().decode("latin-1")
for idx, fname in enumerate(data.split("\x00")):
fname = fname.lower().replace("\\", "/")
if idx < index_len and fname not in self.strtable:
self.strtable[fname] = (len(self.strfd),) + index_table[idx]
+ strlst.append((fname, len(self.strtableord)) + index_table[idx])
+ self.strtableord.append(fname)
else:
if len(fname) > 0:
print("DEBUG:Extra file record \"{}\" in \"{}\"".\
format(fname, name))
# add file descriptor
- self.strfd.append((f, name, tag))
+ self.strfd.append((f, name, tag, strlst))
print("DEBUG: Loaded store \"{}\"".format(name))
def read_file(self, fname):
@@ -107,13 +111,15 @@ class FileManager:
def unload_stores(self, flt = None):
strfd = []
strtable = {}
- for idx, (fd, name, tag) in enumerate(self.strfd):
+ strtableord = []
+ for idx, (fd, name, tag, strlst) in enumerate(self.strfd):
if flt is not None:
if tag != flt:
for k, v in self.strtable.items():
if v[0] == idx:
strtable[k] = (len(strfd), v[1], v[2])
- strfd.append((fd, name, tag))
+ strtableord.append(k)
+ strfd.append((fd, name, tag, strlst))
continue
print("DEBUG: Unload store \"{}\"".format(name))
try:
@@ -122,4 +128,6 @@ class FileManager:
print("DEBUG: Can't unload \"{}\":".format(name) + str(e))
self.strfd = strfd
self.strtable = strtable
+ self.strtableord = strtableord
+
Commit: 97f1822092773fdee2b4f8a4ad100c5815eff9bc
https://github.com/scummvm/scummvm-tools/commit/97f1822092773fdee2b4f8a4ad100c5815eff9bc
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Display sorted wav list in messages section
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 8d691a52d..4e70b999d 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,9 @@
ЧÑо нового
==========
+2014-12-20 веÑÑÐ¸Ñ 0.3d
+----------------------
+ÐÑобÑажение оÑÑоÑÑиÑованного ÑпиÑка иÑполÑзÑемÑÑ
wav Ñайлов
+
2014-12-20 веÑÑÐ¸Ñ 0.3c
----------------------
ÐÑобÑажение загÑÑженнÑÑ
Ñ
ÑÐ°Ð½Ð¸Ð»Ð¸Ñ (.str)
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index fc2afa0b5..596973e46 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3c 2014-12-20"
+VERSION = "v0.3d 2014-12-20"
def hlesc(value):
if value is None:
@@ -1539,6 +1539,15 @@ class App(tkinter.Frame):
self.add_info("<b>Message</b> \"{}\" not found\n\n".format(
path[1]))
self.add_info("Select <b>message</b> from list\n")
+ # wav
+ lst = []
+ for idx, msg in enumerate(self.sim.msgs):
+ lst.append((msg.msg_wav, idx, msg.name))
+ lst.sort()
+ self.add_info("\nWav files\n")
+ for wav, idx, capt in lst:
+ self.add_info(" <a href=\"/msgs/{}\">{}</a> - {}\n".format(
+ idx, wav, capt))
else:
# msg info
self.add_info("<b>Message</b>: {}\n".format(path[1]))
Commit: aa4025e708b1ac6faed5aa5eae1cbba88bab9aeb
https://github.com/scummvm/scummvm-tools/commit/aa4025e708b1ac6faed5aa5eae1cbba88bab9aeb
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Extract STR files
Changed paths:
engines/petka/help/changes.txt
engines/petka/help/index.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 4e70b999d..a2c11002b 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,9 @@
ЧÑо нового
==========
+2014-12-20 веÑÑÐ¸Ñ 0.3e
+----------------------
+РаÑпаковка ÑодеÑжимого STR Ñайла
+
2014-12-20 веÑÑÐ¸Ñ 0.3d
----------------------
ÐÑобÑажение оÑÑоÑÑиÑованного ÑпиÑка иÑполÑзÑемÑÑ
wav Ñайлов
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index cc3f644f0..9ba1946ba 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -1,12 +1,22 @@
СпÑавка
-ÐеÑÑиÑ: 0.3c 2014-12-20
+ÐеÑÑиÑ: 0.3e 2014-12-20
+ÐÑÐ¾Ñ Ð½Ð°Ð±Ð¾Ñ Ð¿ÑогÑамм пÑедназнаÑен Ð´Ð»Ñ Ð¿ÑоÑмоÑÑа внÑÑÑенниÑ
ÑÑÑÑкÑÑÑ Ð´Ð²ÑÑ
пеÑвÑÑ
+ÑаÑÑей игÑÑ "ÐеÑÑка и ÐаÑилий ÐвановиÑ", вклÑÑÐ°Ñ Ð´ÐµÐ¼Ð¾-веÑÑиÑ.
+
+ÐозможноÑÑи:
+
+ * ÐÑкÑÑваÑÑ Ð¸ оÑобÑажаÑÑ Ð² Ñдобной ÑоÑме внÑÑÑеннÑÑ ÑÑÑÑкÑÑÑÑ Ð¸Ð³ÑÑ
+ * ÐÑоÑмаÑÑиваÑÑ Ð¸ ÑаÑпаковÑваÑÑ ÑодеÑжимое .STR Ñайлов
+ * РабоÑаÑÑ Ñ Ð¿ÐµÑеводом игÑÑ Ð½Ð° дÑÑгой ÑзÑк (Ñм. <a href="/help/translate">Ð´Ð»Ñ Ð¿ÐµÑеводÑика</a>)
+ * ÐекомпилиÑоваÑÑ ÑÑÑÑкÑÑÑÑ Ð¸ <a href="/help/compiler">компилиÑоваÑÑ</a> обÑаÑно
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
- * <a href="/help/license">ÐиÑензии</a>
-ÐÑобÑажаемÑе ÑазделÑ
+ÐнÑоÑмаÑÐ¸Ñ Ð¾ <a href="/help/license">лиÑензиÑÑ
</a>
+
+ÐÑобÑажаемÑе ÑазделÑ:
* <a href="/help/parts">ÐÑÐ±Ð¾Ñ ÑаÑÑи</a>
* <a href="/help/res">РеÑÑÑÑÑ</a>
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 596973e46..edc091454 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -28,7 +28,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3d 2014-12-20"
+VERSION = "v0.3e 2014-12-20"
def hlesc(value):
if value is None:
@@ -1933,6 +1933,45 @@ class App(tkinter.Frame):
self.update_gui("Stores ({})".format(len(self.strfm.strfd)))
for idx, st in enumerate(self.strfm.strfd):
self.insert_lb_act("{}".format(st[1]), ["strs", idx], idx)
+ def ext_str():
+ stid = None
+ try:
+ print(self.curr_path)
+ stid = self.curr_path[1]
+ except:
+ pass
+ if stid is None:
+ self.clear_info()
+ self.add_info("<b>Select store</b>\n")
+ return
+ # extract to folder
+ sdir = filedialog.askdirectory(parent = self,
+ title = "Select folder for extract",
+ initialdir = self.strfm.root, mustexist = True)
+ if not sdir: return
+ # extract store to sdir
+ fd, _, _, strlst = self.strfm.strfd[stid]
+ self.clear_info()
+ for fname, _, pos, ln in strlst:
+ try:
+ self.add_info(" \"{}\" - {} bytes\n".
+ format(hlesc(fname), ln))
+ np = sdir
+ for elem in fname.split("/"):
+ np = os.path.join(np, elem)
+ # check folder
+ bn = os.path.dirname(np)
+ if not os.path.exists(bn):
+ os.makedirs(bn)
+ f = open(np, "wb")
+ fd.seek(pos)
+ f.write(fd.read(ln))
+ f.close()
+ except:
+ self.add_info("Error extracting \"{}\" \n\n{}".\
+ format(hlesc(fname), hlesc(traceback.format_exc())))
+ return
+ self.add_toolbtn("Extract STR", ext_str)
# change
stid = None
if len(path) > 1:
Commit: 6c2a6061aec439fcdfcd0f707e899f1e3728a366
https://github.com/scummvm/scummvm-tools/commit/6c2a6061aec439fcdfcd0f707e899f1e3728a366
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: testing page modes
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index edc091454..c12d9f1eb 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -173,9 +173,8 @@ class App(tkinter.Frame):
self.curr_help = ""
self.last_path = [None]
self.last_fn = ""
- self.curr_mode = 0
- self.curr_mode_sub = None
self.curr_gui = []
+ self.curr_state = {}
self.curr_lb_acts = None
self.curr_lb_idx = None
self.hist = []
@@ -597,6 +596,7 @@ class App(tkinter.Frame):
for item in self.curr_gui:
item()
self.curr_gui = []
+ self.curr_state = {} # save state across moves
# left listbox
lab = tkinter.Label(self.frm_left, text = text)
lab.pack()
@@ -768,7 +768,9 @@ class App(tkinter.Frame):
btn = ttk.Button(self.toolbar, text = text, \
style = "Tool.TButton", command = cmd)
btn.pack(side = tkinter.LEFT)
- self.curr_gui.append(lambda:btn.pack_forget())
+ self.curr_gui.append(lambda:btn.pack_forget())
+ return btn
+
def clear_hist(self):
self.hist = self.hist[-1:]
@@ -1936,7 +1938,6 @@ class App(tkinter.Frame):
def ext_str():
stid = None
try:
- print(self.curr_path)
stid = self.curr_path[1]
except:
pass
@@ -1968,7 +1969,7 @@ class App(tkinter.Frame):
f.write(fd.read(ln))
f.close()
except:
- self.add_info("Error extracting \"{}\" \n\n{}".\
+ self.add_info("Error extracting \"{}\"\n\n{}".\
format(hlesc(fname), hlesc(traceback.format_exc())))
return
self.add_toolbtn("Extract STR", ext_str)
@@ -2049,20 +2050,63 @@ class App(tkinter.Frame):
def path_test(self, path):
- self.update_gui("Test {}".format(path[1]))
- self.insert_lb_act("Outline", [])
- self.insert_lb_act("-", None)
- for i in range(15):
- self.insert_lb_act("{} #{}".format(path[1], i), path[:2] + (i,))
- if path[1] == "image":
- self.switch_view(1)
- self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
- elif path[1] == "info":
- self.switch_view(0)
+ def display_page():
+ item = None
+ path = self.curr_path
+ if len(path) > 2:
+ item = path[2]
self.clear_info()
- self.add_info("Information panel for {}\n".format(path))
- for i in range(100):
- self.add_info(" Item {}\n".format(i))
+ if item is None:
+ self.switch_view(0)
+ self.add_info("Select item " + path[1])
+ else:
+ if path[1] == "image":
+ self.switch_view(1)
+ self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
+ elif path[1] == "info":
+ self.switch_view(0)
+ self.add_info("Information panel for {}\n".format(path))
+ self.add_info("Current mode {}\n".format(
+ self.curr_state.get("mode", None)))
+ for i in range(100):
+ self.add_info(" Item {}\n".format(i))
+
+ if self.last_path[:1] != ("test",):
+ self.update_gui("Test {}".format(path[1]))
+ self.insert_lb_act("Outline", [])
+ self.insert_lb_act("-", None)
+ for i in range(15):
+ self.insert_lb_act("{} #{}".format(path[1], i),
+ path[:2] + (i,), i)
+ # create mode buttons
+ def sw_mode1():
+ print("Mode 1")
+ self.curr_state["mode"] = 1
+ self.curr_state["btn1"].config(state = tkinter.DISABLED)
+ self.curr_state["btn2"].config(state = tkinter.NORMAL)
+ display_page()
+ def sw_mode2():
+ print("Mode 2")
+ self.curr_state["mode"] = 2
+ self.curr_state["btn1"].config(state = tkinter.NORMAL)
+ self.curr_state["btn2"].config(state = tkinter.DISABLED)
+ display_page()
+ self.curr_state["btn1"] = self.add_toolbtn("Mode 1", sw_mode1)
+ self.curr_state["btn2"] = self.add_toolbtn("Mode 2", sw_mode2)
+
+ # change
+ item = None
+ if len(path) > 2:
+ # index
+ self.select_lb_item(path[2])
+ try:
+ item = path[2]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ display_page()
def path_about(self, path):
self.switch_view(0)
Commit: 0add1b8e92bacb7ba8d06297c000919c7e108097
https://github.com/scummvm/scummvm-tools/commit/0add1b8e92bacb7ba8d06297c000919c7e108097
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: show history path
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c12d9f1eb..8af849dd1 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -174,11 +174,12 @@ class App(tkinter.Frame):
self.last_path = [None]
self.last_fn = ""
self.curr_gui = []
- self.curr_state = {}
+ self.curr_state = {} # local state for location group
self.curr_lb_acts = None
self.curr_lb_idx = None
self.hist = []
self.histf = []
+ self.gl_state = {} # global state until program exit
# canvas
self.need_update = False
self.canv_view_fact = 1
@@ -381,8 +382,7 @@ class App(tkinter.Frame):
label = "Outline")
self.menunav.add_separator()
self.menunav.add_command(
- command = lambda: self.open_path("/hist"),
- label = "History")
+ command = self.show_hist, label = "History")
if polib:
menutran = tkinter.Menu(self.menubar, tearoff = 0)
@@ -912,6 +912,26 @@ class App(tkinter.Frame):
format(len(self.strfm.strfd)))
self.add_info(" Files: <a href=\"/files\">{}</a>\n".
format(len(self.strfm.strtable)))
+
+ def show_hist(self):
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("<b>History</b>\n\n")
+ def phist(h):
+ d = ""
+ for e in h:
+ d += "/{}".format(e)
+ return d
+ for idx, h in enumerate(self.hist[:-1]):
+ self.add_info(" {:5d}) {}\n".format(idx - len(self.hist) + 1,
+ phist(h[0])))
+ self.add_info(" -----> {}\n".format(phist(self.curr_path)))
+
+ for idx, h in enumerate(self.histf):
+ self.add_info(" {:5d}) {}\n".format(idx + 1, phist(h[0])))
+
+
+
def path_default(self, path):
self.switch_view(0)
@@ -2066,8 +2086,10 @@ class App(tkinter.Frame):
elif path[1] == "info":
self.switch_view(0)
self.add_info("Information panel for {}\n".format(path))
- self.add_info("Current mode {}\n".format(
+ self.add_info("Local mode {}\n".format(
self.curr_state.get("mode", None)))
+ self.add_info("Global mode {}\n".format(
+ self.gl_state.get("mode", None)))
for i in range(100):
self.add_info(" Item {}\n".format(i))
@@ -2091,8 +2113,30 @@ class App(tkinter.Frame):
self.curr_state["btn1"].config(state = tkinter.NORMAL)
self.curr_state["btn2"].config(state = tkinter.DISABLED)
display_page()
+ def sw_gmode1():
+ print("Global Mode 1")
+ self.gl_state["test.info.mode"] = 0
+ self.curr_state["gbtn1"].config(state = tkinter.DISABLED)
+ self.curr_state["gbtn2"].config(state = tkinter.NORMAL)
+ display_page()
+ def sw_gmode2():
+ print("Global Mode 2")
+ self.gl_state["test.info.mode"] = 1
+ self.curr_state["gbtn1"].config(state = tkinter.NORMAL)
+ self.curr_state["gbtn2"].config(state = tkinter.DISABLED)
+ display_page()
self.curr_state["btn1"] = self.add_toolbtn("Mode 1", sw_mode1)
self.curr_state["btn2"] = self.add_toolbtn("Mode 2", sw_mode2)
+ # we store buttons in local state
+ st = self.gl_state.get("test.info.mode", 0)
+ b = self.add_toolbtn("Global Mode 1", sw_gmode1)
+ if st == 0:
+ b.config(state = tkinter.DISABLED)
+ self.curr_state["gbtn1"] = b
+ b = self.add_toolbtn("Global Mode 2", sw_gmode2)
+ if st == 1:
+ b.config(state = tkinter.DISABLED)
+ self.curr_state["gbtn2"] = b
# change
item = None
Commit: 9128fae7fa23fbc401be0fb02dfcf53f6f9c7c18
https://github.com/scummvm/scummvm-tools/commit/9128fae7fa23fbc401be0fb02dfcf53f6f9c7c18
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: sort modes for messages
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 8af849dd1..a0e418574 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1533,6 +1533,71 @@ class App(tkinter.Frame):
if self.sim is None:
return self.path_default([])
self.switch_view(0)
+ def upd_msgs():
+ path = self.curr_path
+ msg = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ msg = self.sim.msgs[path[1]]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ sm = self.gl_state.get("msgs.sort", 0)
+ if msg:
+ sm = -1
+ for btn, idx in self.curr_state["btnsort"]:
+ if idx != sm and sm != -1:
+ btn.config(state = tkinter.NORMAL)
+ else:
+ btn.config(state = tkinter.DISABLED)
+ self.clear_info()
+ if not msg:
+ if len(path) > 1:
+ self.add_info("<b>Message</b> \"{}\" not found\n\n".format(
+ path[1]))
+ self.add_info("Select <b>message</b> from list\n\n")
+ # wav
+ lst = []
+ for idx, msg in enumerate(self.sim.msgs):
+ if sm == 0:
+ k = msg.msg_wav
+ elif sm == 1:
+ k = idx
+ else:
+ k = msg.name
+ lst.append((k, msg.msg_wav, idx, msg.name))
+ lst.sort()
+ for _, wav, idx, capt in lst:
+ self.add_info(" <a href=\"/msgs/{}\">{}</a> - {}\n".
+ format(idx, wav, capt))
+ else:
+ # msg info
+ self.add_info("<b>Message</b>: {}\n".format(path[1]))
+ self.add_info(" wav: {}\n".format(msg.msg_wav))
+ self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx,
+ True) + "\n")
+ self.add_info(" arg2: {a} (0x{a:X})\n".format(
+ a = msg.msg_arg2))
+ self.add_info(" arg3: {a} (0x{a:X})\n".format(
+ a = msg.msg_arg3))
+ self.add_info("\n{}\n".format(hlesc(msg.name)))
+ if self.tran:
+ self.add_info("\n<i>Translated:</i>\n{}\n".\
+ format(hlesc(self._t(msg.name, "msg"))))
+ self.add_info("\n<b>Used by dialog groups</b>:\n")
+ for grp in self.sim.dlgs:
+ for act in grp.acts:
+ for dlg in act.dlgs:
+ for op in dlg.ops:
+ if not op.msg: continue
+ if op.msg.idx == msg.idx and op.opcode == 7:
+ self.add_info(" " +
+ self.fmt_hl_dlg(grp.idx, True) + "\n")
+
if self.last_path[:1] != ("msgs",):
self.update_gui("Messages ({})".format(len(self.sim.msgs)))
for idx, msg in enumerate(self.sim.msgs):
@@ -1543,54 +1608,21 @@ class App(tkinter.Frame):
capt = capt[:40] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt),
["msgs", idx], idx)
+ def sfn():
+ self.gl_state["msgs.sort"] = 0
+ upd_msgs()
+ def sidx():
+ self.gl_state["msgs.sort"] = 1
+ upd_msgs()
+ def stxt():
+ self.gl_state["msgs.sort"] = 2
+ upd_msgs()
+ b1 = self.add_toolbtn("Sort by wav", sfn)
+ b2 = self.add_toolbtn("Sort by order", sidx)
+ b3 = self.add_toolbtn("Sort by text", stxt)
+ self.curr_state["btnsort"] = [[b1, 0], [b2, 1], [b3, 2]]
# change
- msg = None
- if len(path) > 1:
- # index
- self.select_lb_item(path[1])
- try:
- msg = self.sim.msgs[path[1]]
- except:
- pass
- else:
- self.select_lb_item(None)
- # display
- self.clear_info()
- if not msg:
- if len(path) > 1:
- self.add_info("<b>Message</b> \"{}\" not found\n\n".format(
- path[1]))
- self.add_info("Select <b>message</b> from list\n")
- # wav
- lst = []
- for idx, msg in enumerate(self.sim.msgs):
- lst.append((msg.msg_wav, idx, msg.name))
- lst.sort()
- self.add_info("\nWav files\n")
- for wav, idx, capt in lst:
- self.add_info(" <a href=\"/msgs/{}\">{}</a> - {}\n".format(
- idx, wav, capt))
- else:
- # msg info
- self.add_info("<b>Message</b>: {}\n".format(path[1]))
- self.add_info(" wav: {}\n".format(msg.msg_wav))
- self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx, True) +
- "\n")
- self.add_info(" arg2: {a} (0x{a:X})\n".format(a = msg.msg_arg2))
- self.add_info(" arg3: {a} (0x{a:X})\n".format(a = msg.msg_arg3))
- self.add_info("\n{}\n".format(hlesc(msg.name)))
- if self.tran:
- self.add_info("\n<i>Translated:</i>\n{}\n".\
- format(hlesc(self._t(msg.name, "msg"))))
- self.add_info("\n<b>Used by dialog groups</b>:\n")
- for grp in self.sim.dlgs:
- for act in grp.acts:
- for dlg in act.dlgs:
- for op in dlg.ops:
- if not op.msg: continue
- if op.msg.idx == msg.idx and op.opcode == 7:
- self.add_info(" " +
- self.fmt_hl_dlg(grp.idx, True) + "\n")
+ upd_msgs()
def path_dlgs(self, path):
if self.sim is None:
@@ -1992,7 +2024,7 @@ class App(tkinter.Frame):
self.add_info("Error extracting \"{}\"\n\n{}".\
format(hlesc(fname), hlesc(traceback.format_exc())))
return
- self.add_toolbtn("Extract STR", ext_str)
+ self.curr_state["btnext"] = self.add_toolbtn("Extract STR", ext_str)
# change
stid = None
if len(path) > 1:
@@ -2006,6 +2038,7 @@ class App(tkinter.Frame):
self.select_lb_item(None)
# display
self.clear_info()
+ self.curr_state["btnext"].config(state = tkinter.DISABLED)
if stid is None:
self.add_info("<b>Stores</b>\n\n")
for idx, st in enumerate(self.strfm.strfd):
@@ -2016,6 +2049,7 @@ class App(tkinter.Frame):
self.add_info("<b>Store</b> \"{}\" not found\n\n".\
format(path[1]))
return
+ self.curr_state["btnext"].config(state = tkinter.NORMAL)
_, name, tag, strlst = self.strfm.strfd[stid]
self.add_info("<b>Store</b>: {}\n".format(name))
self.add_info(" Files: <a href=\"/files\">{}</a>, Tag: {}\n\n".
Commit: 1e024eabb3128f52b869209b56dc729691caeef8
https://github.com/scummvm/scummvm-tools/commit/1e024eabb3128f52b869209b56dc729691caeef8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: add label to toolbar
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index a0e418574..b7ef4362f 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -771,6 +771,11 @@ class App(tkinter.Frame):
self.curr_gui.append(lambda:btn.pack_forget())
return btn
+ def add_toollabel(self, text):
+ lab = ttk.Label(self.toolbar, text = text)
+ lab.pack(side = tkinter.LEFT)
+ self.curr_gui.append(lambda:lab.pack_forget())
+ return lab
def clear_hist(self):
self.hist = self.hist[-1:]
@@ -1617,13 +1622,14 @@ class App(tkinter.Frame):
def stxt():
self.gl_state["msgs.sort"] = 2
upd_msgs()
- b1 = self.add_toolbtn("Sort by wav", sfn)
- b2 = self.add_toolbtn("Sort by order", sidx)
- b3 = self.add_toolbtn("Sort by text", stxt)
+ self.add_toollabel("Sort by")
+ b1 = self.add_toolbtn("wav", sfn)
+ b2 = self.add_toolbtn("order", sidx)
+ b3 = self.add_toolbtn("text", stxt)
self.curr_state["btnsort"] = [[b1, 0], [b2, 1], [b3, 2]]
# change
upd_msgs()
-
+
def path_dlgs(self, path):
if self.sim is None:
return self.path_default([])
@@ -1731,7 +1737,7 @@ class App(tkinter.Frame):
op.opcode == 0x4: # GOTO or MENURET
opref = "<i>label_{:X}</i>".format(op.ref)
if op.pos in usedmenu:
- cmt = self.fmt_cmt(" // action menu=<i>"\
+ cmt = self.fmt_cmt(" // action menu=<i> "\
"label_{:X}</i>, case=0x{:}".\
format(*usedmenu[op.pos]))
elif op.opcode == 0x7:
Commit: d87373a2bfd5792d940dd35447440c250045c35a
https://github.com/scummvm/scummvm-tools/commit/d87373a2bfd5792d940dd35447440c250045c35a
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: files related info
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index b7ef4362f..c3c5c4009 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -213,7 +213,8 @@ class App(tkinter.Frame):
]
for text, cmd in btns:
if text is None:
- frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
+ frm = ttk.Frame(self.toolbar, width = self.pad,
+ height = self.pad)
frm.pack(side = tkinter.LEFT)
continue
btn = ttk.Button(self.toolbar, text = text, \
@@ -2068,6 +2069,85 @@ class App(tkinter.Frame):
def path_files(self, path):
if self.strfm is None:
return self.path_default([])
+ def upd_files():
+ path = self.curr_path
+ fid = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ fid = path[1]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ self.clear_info()
+ if fid is None:
+ self.add_info("<b>Files</b>\n\n")
+ for idx, fn in enumerate(self.strfm.strtableord):
+ stid, pos, ln = self.strfm.strtable[fn]
+ self.add_info(" {}) <a href=\"/files/{}\">{}</a>\n".format(
+ idx + 1, idx, hlesc(fn)))
+ else:
+ if fid >= len(self.strfm.strtable):
+ self.add_info("<b>File</b> \"{}\" not found\n\n".\
+ format(path[1]))
+ return
+ fn = self.strfm.strtableord[fid]
+ stid, pos, ln = self.strfm.strtable[fn]
+
+ self.add_info("<b>File</b>: {}\n\n".format(fn))
+ self.add_info(" Store: <a href=\"/strs/{}\">{}</a>\n".format(
+ stid, self.strfm.strfd[stid][1]))
+ self.add_info(" Pos: {} (0x{:x})\n Len: {} (0x{:x})\n".format(
+ pos, pos, ln, ln))
+ fnl = fn.lower().replace("\\", "/")
+ if self.sim:
+ self.add_info("\n<b>Used in resources</b>:\n")
+ for resid in self.sim.resord:
+ resfn = self.sim.res[resid].lower().replace("\\", "/")
+ if resfn == fnl:
+ self.add_info(" {} - <a href=\"/res/all/{}\">"\
+ "{}</a>\n".format(resid, resid,
+ hlesc(self.sim.res[resid])))
+ grp = [
+ [".leg", ".off", ".msk", ".flc"],
+ [".bmp", "cvx"]
+ ]
+ sg = None
+ for g in grp:
+ if fnl[-4:] in g:
+ sg = g
+ if sg:
+ self.add_info("\n<b>Related file</b>:\n")
+ rel = []
+ for idx, fnm in enumerate(self.strfm.strtableord):
+ fnml = fnm.lower().replace("\\", "/")
+ if idx == fid: continue
+ if fnml[:-4] == fnl[:-4] and fnml[-4:] in sg:
+ self.add_info(" <a href=\"/files/{}\">{}</a>\n".
+ format(idx, hlesc(fnm)))
+ # spec files
+ sfils = {
+ "script.dat": ["/objs", "/scenes", "/opcodes"],
+ "background.bg": ["/objs", "/scenes", "/opcodes"],
+ "cast.ini": ["/casts"],
+ "invntr.txt": ["/invntr"],
+ "names.ini": ["/names"],
+ "bgs.ini": ["/bgs"],
+ "dialogue.fix": ["/dlgs", "/msgs", "/dlgops"],
+ "dialogue.lod": ["/dlgs", "/msgs", "/dlgops"],
+ "resource.qrc": ["/res"],
+ }
+ for k, v in sfils.items():
+ if fnl.endswith(k):
+ self.add_info("\n<b>Related info</b>:\n")
+ for p in v:
+ self.add_info(" {}\n".format(p))
+
+
+
+
self.switch_view(0)
keys = None
if self.last_path[:1] != ("files",):
@@ -2075,38 +2155,7 @@ class App(tkinter.Frame):
self.update_gui("Files ({})".format(len(self.strfm.strtable)))
for idx, fn in enumerate(self.strfm.strtableord):
self.insert_lb_act(fn, ["files", idx], idx)
- # change
- fid = None
- if len(path) > 1:
- # index
- self.select_lb_item(path[1])
- try:
- fid = path[1]
- except:
- pass
- else:
- self.select_lb_item(None)
- # display
- self.clear_info()
- if fid is None:
- self.add_info("<b>Files</b>\n\n")
- for idx, fn in enumerate(self.strfm.strtableord):
- stid, pos, ln = self.strfm.strtable[fn]
- self.add_info(" {}) <a href=\"/files/{}\">{}</a>\n".format(
- idx + 1, idx, fn))
- else:
- if fid >= len(self.strfm.strtable):
- self.add_info("<b>File</b> \"{}\" not found\n\n".\
- format(path[1]))
- return
- fn = self.strfm.strtableord[fid]
- stid, pos, ln = self.strfm.strtable[fn]
-
- self.add_info("<b>File</b>: {}\n\n".format(fn))
- self.add_info(" Store: <a href=\"/strs/{}\">{}</a>\n".format(stid,
- self.strfm.strfd[stid][1]))
- self.add_info(" Pos: {} (0x{:x})\n Len: {} (0x{:x})\n".format(
- pos, pos, ln, ln))
+ upd_files()
def path_test(self, path):
Commit: 98b6710ceb85856e90e1af6ac911a9e420bf7cbc
https://github.com/scummvm/scummvm-tools/commit/98b6710ceb85856e90e1af6ac911a9e420bf7cbc
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix bunch of error. improvements
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index a2c11002b..f74e2cb16 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,18 @@
ЧÑо нового
==========
+2014-12-27 веÑÑÐ¸Ñ 0.3f
+----------------------
+СоÑÑиÑовка ÑообÑений по имени Ñайла, по поÑÑдкÑ, по ÑекÑÑÑ
+ÐнÑоÑмаÑÐ¸Ñ Ð¾ ÑвÑзаннÑÑ
ÑайлаÑ
(FLC, MSG, LEF, OFF и BMP, CVX)
+ÐÑпÑавлена оÑибка пÑи пеÑеÑ
оде из Ñ
ÑанилиÑа к ÑайлÑ
+Ðобавлен пеÑеÑ
од Ð¾Ñ ÑеÑÑÑÑа к ÑайлÑ
+ÐÑкÑÑÑие Ñайлов оÑÑÑеÑÑвлÑеÑÑÑ Ð¿Ð¾ имени а не номеÑÑ
+ÐÑобÑажение иÑÑоÑии пеÑеÑ
одов
+ÐоÑÑекÑное опиÑание ÑекÑÑего Ñаздела
+Ðзменено оÑобÑажение ÑпиÑка ÑообÑений, добавлен пеÑеÑ
од на wav Ñайл
+Ðвижок: авÑомаÑиÑеÑÐºÐ°Ñ Ð·Ð°Ð³ÑÑзка Ñайлов speech из Ñ
ÑанилиÑ
+ÐÑпÑавлена поÑледоваÑелÑÐ½Ð°Ñ Ð·Ð°Ð³ÑÑзка Ñазделов
+
2014-12-20 веÑÑÐ¸Ñ 0.3e
----------------------
РаÑпаковка ÑодеÑжимого STR Ñайла
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index c3c5c4009..ee372fb6d 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -8,6 +8,7 @@ import tkinter
from tkinter import ttk, font, filedialog, messagebox
from idlelib.WidgetRedirector import WidgetRedirector
import traceback
+import urllib.parse
# Image processing
try:
@@ -192,8 +193,7 @@ class App(tkinter.Frame):
# store manager
self.strfm = None
# translation
- self.tran = None
-
+ self.tran = None
def create_widgets(self):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
@@ -259,28 +259,51 @@ class App(tkinter.Frame):
self.text_hl = HyperlinkManager(self.text_view)
self.text_view.bind('<Configure>', self.on_resize_view)
- # bind path handlers
- self.path_handler["parts"] = self.path_parts
- self.path_handler["res"] = self.path_res
- self.path_handler["objs"] = self.path_objs_scenes
- self.path_handler["scenes"] = self.path_objs_scenes
- self.path_handler["names"] = self.path_names
- self.path_handler["invntr"] = self.path_invntr
- self.path_handler["msgs"] = self.path_msgs
- self.path_handler["dlgs"] = self.path_dlgs
- self.path_handler["casts"] = self.path_casts
- self.path_handler["opcodes"] = self.path_opcodes
- self.path_handler["dlgops"] = self.path_dlgops
- self.path_handler["test"] = self.path_test
- self.path_handler["about"] = self.path_about
- self.path_handler["support"] = self.path_support
- self.path_handler["help"] = self.path_help
- self.path_handler["info"] = self.path_info
- self.path_handler["strs"] = self.path_stores
- self.path_handler["files"] = self.path_files
+ def desc_def(aname, name, lst = {}):
+ def desc(path):
+ if len(path) > 1:
+ return "{} {}".format(name, lst.get(path[1],
+ "#{}".format(path[1])))
+ else:
+ return aname
+ return desc
+
+ # bind path handlers
+ self.path_handler["parts"] = [self.path_parts, self.desc_parts]
+ self.path_handler["res"] = [self.path_res, None] # TODO:
+ self.path_handler["objs"] = [self.path_objs_scenes,
+ desc_def("Objects", "Object")]
+ self.path_handler["scenes"] = [self.path_objs_scenes,
+ desc_def("Scenes", "Scene")]
+ self.path_handler["names"] = [self.path_names,
+ desc_def("Names", "Name")]
+ self.path_handler["invntr"] = [self.path_invntr,
+ desc_def("Invntrs", "Invntr")]
+ self.path_handler["msgs"] = [self.path_msgs,
+ desc_def("Messages", "Message")]
+ self.path_handler["dlgs"] = [self.path_dlgs,
+ desc_def("Dialog groups", "Dialog group")]
+ self.path_handler["casts"] = [self.path_casts,
+ desc_def("Casts", "Cast")]
+ self.path_handler["opcodes"] = [self.path_opcodes,
+ desc_def("Opcodes", "Opcode",
+ {k:v[0] for k, v in petka.engine.OPCODES.items()})]
+ self.path_handler["dlgops"] = [self.path_dlgops,
+ desc_def("Dialog opcodes", "Dialog opcode",
+ {k:v[0] for k, v in petka.engine.DLGOPS.items()})]
+ self.path_handler["strs"] = [self.path_stores,
+ desc_def("Stores", "Store")]
+ self.path_handler["files"] = [self.path_files, self.desc_files]
+ self.path_handler["test"] = [self.path_test, "Tests"]
+ self.path_handler["about"] = [self.path_about, "About"]
+ self.path_handler["support"] = [self.path_support, "Support"]
+ self.path_handler["help"] = [self.path_help, self.desc_help]
+ self.path_handler["info"] = [self.path_info, "Information"]
+
self.update_after()
repath = "/about"
+ print(self.start_act)
for cmd, arg in self.start_act:
if cmd == "load":
if not self.open_data_from(arg):
@@ -297,15 +320,27 @@ class App(tkinter.Frame):
repath = ""
break
elif cmd == "open":
+ repath = ""
if not self.open_path(arg):
+ print("DEBUG: stop opening after " + arg)
repath = ""
break
- else:
- repath = "/"
+ print("Loading end", repath)
if repath:
self.open_path(repath)
def create_menu(self):
+ def mkmenupaths(parent, items):
+ for n in items:
+ if n is None:
+ parent.add_separator()
+ else:
+ def cmd(n):
+ return lambda: self.open_path(n)
+ parent.add_command(
+ command = cmd(n),
+ label = self.desc_path(n))
+
self.menubar = tkinter.Menu(self.master)
self.master.configure(menu = self.menubar)
@@ -327,47 +362,12 @@ class App(tkinter.Frame):
self.menuedit = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuedit,
label = "Edit")
- self.menuedit.add_command(
- command = lambda: self.open_path("/parts"),
- label = "Select part")
- self.menuedit.add_separator()
- self.menuedit.add_command(
- command = lambda: self.open_path("/res"),
- label = "Resources")
- self.menuedit.add_command(
- command = lambda: self.open_path("/objs"),
- label = "Objects")
- self.menuedit.add_command(
- command = lambda: self.open_path("/scenes"),
- label = "Scenes")
- self.menuedit.add_command(
- command = lambda: self.open_path("/names"),
- label = "Names")
- self.menuedit.add_command(
- command = lambda: self.open_path("/invntr"),
- label = "Invntr")
- self.menuedit.add_command(
- command = lambda: self.open_path("/casts"),
- label = "Casts")
- self.menuedit.add_command(
- command = lambda: self.open_path("/msgs"),
- label = "Messages")
- self.menuedit.add_command(
- command = lambda: self.open_path("/dlgs"),
- label = "Dialog groups")
- self.menuedit.add_command(
- command = lambda: self.open_path("/opcodes"),
- label = "Opcodes")
- self.menuedit.add_command(
- command = lambda: self.open_path("/dlgops"),
- label = "Dialog opcodes")
- self.menuedit.add_command(
- command = lambda: self.open_path("/strs"),
- label = "Stores")
- self.menuedit.add_command(
- command = lambda: self.open_path("/files"),
- label = "Files")
-
+
+ editnav = ["/parts", None, "/res", "/objs", "/scenes", "/names",
+ "/invntr", "/casts", "/msgs", "/dlgs", "/opcodes", "/dlgops",
+ "/strs", "/files"]
+ mkmenupaths(self.menuedit, editnav)
+
self.menunav = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menunav,
label = "Navigation")
@@ -409,19 +409,8 @@ class App(tkinter.Frame):
self.menuhelp = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuhelp,
label = "Help")
- self.menuhelp.add_command(
- command = lambda: self.open_path("/help/index"),
- label = "Contents")
- self.menuhelp.add_separator()
- self.menuhelp.add_command(
- command = lambda: self.open_path("/support"),
- label = "Support")
- self.menuhelp.add_command(
- command = lambda: self.open_path("/info"),
- label = "Info")
- self.menuhelp.add_command(
- command = lambda: self.open_path("/about"),
- label = "About")
+ helpnav = ["/help/index", None, "/support", "/info", "/about"]
+ mkmenupaths(self.menuhelp, helpnav)
def update_after(self):
if not self.need_update:
@@ -450,7 +439,7 @@ class App(tkinter.Frame):
def on_resize_view(self, event):
self.update_after()
- def open_path(self, loc, withhist = True):
+ def parse_path(self, loc):
if isinstance(loc, str):
path = []
if loc[:1] == "/":
@@ -466,11 +455,13 @@ class App(tkinter.Frame):
path = tuple(path)
while path[-1:] == ("",):
path = path[:-1]
-
+ return path
+
+ def open_path(self, loc, withhist = True):
+ path = self.parse_path(loc)
if withhist:
self.hist.append([path])
self.histf = []
-
print("DEBUG: Open", path)
self.curr_path = path
if len(path) > 0:
@@ -479,9 +470,20 @@ class App(tkinter.Frame):
self.curr_help = ""
if len(path) > 0:
if path[0] in self.path_handler:
- return self.path_handler[path[0]](path)
+ return self.path_handler[path[0]][0](path)
return self.path_default(path)
+ def desc_path(self, loc):
+ path = self.parse_path(loc)
+ if len(path) > 0:
+ if path[0] in self.path_handler:
+ desc = self.path_handler[path[0]][1]
+ if callable(desc):
+ return desc(path)
+ elif desc:
+ return desc
+ return self.desc_default(path)
+
def update_canvas(self):
if self.curr_main == 0:
return
@@ -923,22 +925,22 @@ class App(tkinter.Frame):
self.switch_view(0)
self.clear_info()
self.add_info("<b>History</b>\n\n")
- def phist(h):
- d = ""
- for e in h:
- d += "/{}".format(e)
- return d
for idx, h in enumerate(self.hist[:-1]):
self.add_info(" {:5d}) {}\n".format(idx - len(self.hist) + 1,
- phist(h[0])))
- self.add_info(" -----> {}\n".format(phist(self.curr_path)))
+ self.desc_path(h[0])))
+ self.add_info(" -----> {}\n".format(self.desc_path(self.curr_path)))
for idx, h in enumerate(self.histf):
- self.add_info(" {:5d}) {}\n".format(idx + 1, phist(h[0])))
-
+ self.add_info(" {:5d}) {}\n".format(idx + 1, self.desc_path(h[0])))
+ def desc_default(self, path):
+ desc = ""
+ for item in path:
+ desc += "/{}".format(item)
+ if not desc:
+ desc = "Outline"
+ return desc
-
def path_default(self, path):
self.switch_view(0)
self.update_gui("Outline")
@@ -977,6 +979,22 @@ class App(tkinter.Frame):
]
for name, act in acts:
self.insert_lb_act(name, act)
+ return True
+
+ def desc_parts(self, path):
+ # this part can be internationalized
+ if len(path) > 1:
+ try:
+ part = path[1]
+ part = part.split(".", 1)
+ part[0] = int(part[0])
+ part[1] = int(part[1])
+ except:
+ part = None
+ pass
+ return "Goto to unknown part {}".format(path[1])
+ return "Select part {} chapter {}".format(part[0], part[1])
+ return "Select part"
def path_parts(self, path):
if self.sim is None:
@@ -1037,6 +1055,8 @@ class App(tkinter.Frame):
except:
self.add_info("Error open part {} chapter {} - \n\n{}".\
format(part[0], part[1], hlesc(traceback.format_exc())))
+ return False
+ return True
def path_res(self, path):
@@ -1108,7 +1128,6 @@ class App(tkinter.Frame):
flc.frame_num, flc.delay))
else:
self.add_info("No information availiable")
-
except:
self.add_info("Error loading {} - \"{}\" \n\n{}".\
format(res_id, hlesc(fn), hlesc(traceback.format_exc())))
@@ -1129,9 +1148,12 @@ class App(tkinter.Frame):
usedby(self.sim.objects)
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
+ self.add_info("\nFile: {}\n".format(self.fmt_hl_file(fn)))
+
elif mode[0] == "view":
self.path_res_view(res_id)
+ return True
def path_res_view(self, res_id):
fn = self.sim.res[res_id]
@@ -1166,6 +1188,7 @@ class App(tkinter.Frame):
finally:
if dataf:
dataf.close()
+ return True
def path_res_status(self):
self.switch_view(0)
@@ -1184,6 +1207,7 @@ class App(tkinter.Frame):
self.add_info(" <a href=\"/res/flt/{}\">{}</a>: {}\n".format(
ft, ft, fts[ft]))
self.select_lb_item(None)
+ return True
def on_path_res_info(self):
self.switch_view(0)
@@ -1201,9 +1225,9 @@ class App(tkinter.Frame):
res_id, self.sim.res[res_id]), ["res", "all", res_id], res_id)
# change
if len(path) > 2:
- self.path_res_open(path[:3], path[2], path[3:])
+ return self.path_res_open(path[:3], path[2], path[3:])
else:
- self.path_res_status()
+ return self.path_res_status()
def path_res_flt(self, path):
lst = []
@@ -1220,9 +1244,9 @@ class App(tkinter.Frame):
res_id)
# change
if len(path) > 3:
- self.path_res_open(path[:4], path[3], path[4:])
+ return self.path_res_open(path[:4], path[3], path[4:])
else:
- self.path_res_status()
+ return self.path_res_status()
def path_objs_scenes(self, path):
if self.sim is None:
@@ -1432,10 +1456,8 @@ class App(tkinter.Frame):
self.fmt_hl_scene(sf.idx, True)))
self.add_info(" <i>on</i>: {}\n".format(
self.fmt_hl_obj(oo.idx, True)))
+ return True
-
-
-
def path_std_items(self, path, level, guiname, guiitem, tt, lst, lst_idx,
lbmode, cb):
self.switch_view(0)
@@ -1444,7 +1466,6 @@ class App(tkinter.Frame):
for idx, name in enumerate(lst_idx):
lb = self._t(name, tt)
if lbmode == 1:
- print(name, )
lb = "{} - {}".format(name, self._t(lst[name], tt))
self.insert_lb_act(lb, path[:level] + tuple([idx]), idx)
# change
@@ -1465,6 +1486,7 @@ class App(tkinter.Frame):
else:
# info
cb(name)
+ return True
def path_names(self, path):
if self.sim is None:
@@ -1578,12 +1600,15 @@ class App(tkinter.Frame):
lst.append((k, msg.msg_wav, idx, msg.name))
lst.sort()
for _, wav, idx, capt in lst:
- self.add_info(" <a href=\"/msgs/{}\">{}</a> - {}\n".
- format(idx, wav, capt))
+ self.add_info(" <a href=\"/msgs/{}\">{}</a> - {} - {}\n".
+ format(idx, idx, self.fmt_hl_file("speech{}/{}".format(
+ self.sim.curr_part, wav), wav), capt))
else:
# msg info
self.add_info("<b>Message</b>: {}\n".format(path[1]))
- self.add_info(" wav: {}\n".format(msg.msg_wav))
+ self.add_info(" wav: {}\n".
+ format(self.fmt_hl_file("speech{}/{}".format(
+ self.sim.curr_part, msg.msg_wav), msg.msg_wav)))
self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx,
True) + "\n")
self.add_info(" arg2: {a} (0x{a:X})\n".format(
@@ -1630,6 +1655,7 @@ class App(tkinter.Frame):
self.curr_state["btnsort"] = [[b1, 0], [b2, 1], [b3, 2]]
# change
upd_msgs()
+ return True
def path_dlgs(self, path):
if self.sim is None:
@@ -1776,6 +1802,7 @@ class App(tkinter.Frame):
usedby(self.sim.objects)
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
+ return True
def path_opcodes(self, path):
if self.sim is None:
@@ -1901,6 +1928,7 @@ class App(tkinter.Frame):
aidx, self.fmt_cmt("// " + self.fmt_hl_obj_scene(
obj_idx, True))))
self.add_info("\n")
+ return True
def path_dlgops(self, path):
if self.sim is None:
@@ -1970,7 +1998,6 @@ class App(tkinter.Frame):
for oidx, op in enumerate(dlg.ops):
if op.opcode == opcode:
dls.append([act.ref, grp.idx, aidx, didx, oidx])
-
# display
if len(dls) == 0:
self.add_info("<i>Not used in dialogs</i>\n\n")
@@ -1983,7 +2010,14 @@ class App(tkinter.Frame):
aidx, didx, oidx, self.fmt_cmt("// " +
self.fmt_hl_obj_scene(obj_idx, True))))
self.add_info("\n")
+ return True
+ def fmt_hl_file(self, fn, capt = None):
+ fnl = fn.lower().replace("\\", "/")
+ capt = capt or fn
+ fid = urllib.parse.quote_plus(fnl)
+ return "<a href=\"/files/{}\">{}</a>".format(fid, hlesc(capt))
+
def path_stores(self, path):
if self.strfm is None:
return self.path_default([])
@@ -2049,8 +2083,8 @@ class App(tkinter.Frame):
if stid is None:
self.add_info("<b>Stores</b>\n\n")
for idx, st in enumerate(self.strfm.strfd):
- self.add_info(" {}) <a href=\"/strs/{}\">{}</a> - {}\n".format(
- idx + 1, idx, st[1], st[2]))
+ self.add_info(" {}) <a href=\"/strs/{}\">{}</a> (tag={})\n".
+ format(idx + 1, idx, st[1], st[2]))
else:
if stid >= len(self.strfm.strfd):
self.add_info("<b>Store</b> \"{}\" not found\n\n".\
@@ -2061,10 +2095,17 @@ class App(tkinter.Frame):
self.add_info("<b>Store</b>: {}\n".format(name))
self.add_info(" Files: <a href=\"/files\">{}</a>, Tag: {}\n\n".
format(len(strlst), tag))
- for idx, (fname, ford, pos, ln) in enumerate(strlst):
- self.add_info(" {}) <a href=\"/files/{}\">{}</a> "
- "(pos={}, len={})\n".format(idx + 1, ford, fname,
- pos, ln))
+ for idx, (fname, _, _, _) in enumerate(strlst):
+ self.add_info(" {}) {}\n".format(idx + 1,
+ self.fmt_hl_file(fname)))
+ return True
+
+ def desc_files(self, path):
+ # this part can be internationalized
+ if len(path) > 1:
+ fnl = urllib.parse.unquote(path[1])
+ return "File \"{}\"".format(fnl)
+ return "Files"
def path_files(self, path):
if self.strfm is None:
@@ -2073,89 +2114,124 @@ class App(tkinter.Frame):
path = self.curr_path
fid = None
if len(path) > 1:
+ # normalize fn
+ fnl = urllib.parse.unquote(path[1]).replace("\\","/").lower()
+ fid = urllib.parse.quote_plus(fnl)
# index
- self.select_lb_item(path[1])
- try:
- fid = path[1]
- except:
- pass
+ self.select_lb_item(fid)
else:
self.select_lb_item(None)
self.clear_info()
if fid is None:
- self.add_info("<b>Files</b>\n\n")
+ self.add_info("<b>Files in all stores</b>\n\n")
for idx, fn in enumerate(self.strfm.strtableord):
- stid, pos, ln = self.strfm.strtable[fn]
- self.add_info(" {}) <a href=\"/files/{}\">{}</a>\n".format(
- idx + 1, idx, hlesc(fn)))
+ stid, _, _ = self.strfm.strtable[fn]
+ self.add_info(" {}) {}\n".format(
+ idx + 1, self.fmt_hl_file(fn)))
else:
- if fid >= len(self.strfm.strtable):
+ try:
+ self.strfm.read_file(fnl)
+ except:
self.add_info("<b>File</b> \"{}\" not found\n\n".\
- format(path[1]))
+ format(hlesc(fnl)))
return
- fn = self.strfm.strtableord[fid]
- stid, pos, ln = self.strfm.strtable[fn]
-
- self.add_info("<b>File</b>: {}\n\n".format(fn))
- self.add_info(" Store: <a href=\"/strs/{}\">{}</a>\n".format(
- stid, self.strfm.strfd[stid][1]))
- self.add_info(" Pos: {} (0x{:x})\n Len: {} (0x{:x})\n".format(
- pos, pos, ln, ln))
- fnl = fn.lower().replace("\\", "/")
+ self.add_info("<b>File</b>: {}\n\n".format(fnl))
+
+ # search in loaded stores
+ if fnl in self.strfm.strtable:
+ # in store
+ stid, pos, ln = self.strfm.strtable[fnl]
+ self.add_info(" Store: <a href=\"/strs/{}\">{}</a>\n".format(
+ stid, self.strfm.strfd[stid][1]))
+ self.add_info(" Pos: {} (0x{:x}), Len: {} (0x{:x})\n".format(
+ pos, pos, ln, ln))
+ else:
+ # on disk
+ self.add_info(" Loaded from disk\n")
+
if self.sim:
- self.add_info("\n<b>Used in resources</b>:\n")
+ wascapt = False
for resid in self.sim.resord:
resfn = self.sim.res[resid].lower().replace("\\", "/")
if resfn == fnl:
+ if not wascapt:
+ self.add_info("\n<b>Used in resources</b>:\n")
+ wascapt = True
self.add_info(" {} - <a href=\"/res/all/{}\">"\
"{}</a>\n".format(resid, resid,
hlesc(self.sim.res[resid])))
+ wavpref = "speech{}/".format(self.sim.curr_part)
+ if fnl[-4:] == ".wav" and fnl.startswith(wavpref):
+ wascapt = False
+ for idx, msg in enumerate(self.sim.msgs):
+ if fnl == wavpref + msg.msg_wav.lower():
+ if not wascapt:
+ self.add_info("\n<b>Used in messages</b>:"
+ "\n")
+ wascapt = True
+ self.add_info(" {}\n".format(
+ self.fmt_hl_msg(idx, True)))
+
grp = [
[".leg", ".off", ".msk", ".flc"],
- [".bmp", "cvx"]
+ [".bmp", ".cvx"]
]
sg = None
for g in grp:
if fnl[-4:] in g:
sg = g
if sg:
- self.add_info("\n<b>Related file</b>:\n")
+ self.add_info("\n<b>Related file(s)</b>:\n")
rel = []
- for idx, fnm in enumerate(self.strfm.strtableord):
- fnml = fnm.lower().replace("\\", "/")
- if idx == fid: continue
- if fnml[:-4] == fnl[:-4] and fnml[-4:] in sg:
- self.add_info(" <a href=\"/files/{}\">{}</a>\n".
- format(idx, hlesc(fnm)))
- # spec files
- sfils = {
- "script.dat": ["/objs", "/scenes", "/opcodes"],
- "background.bg": ["/objs", "/scenes", "/opcodes"],
- "cast.ini": ["/casts"],
- "invntr.txt": ["/invntr"],
- "names.ini": ["/names"],
- "bgs.ini": ["/bgs"],
- "dialogue.fix": ["/dlgs", "/msgs", "/dlgops"],
- "dialogue.lod": ["/dlgs", "/msgs", "/dlgops"],
- "resource.qrc": ["/res"],
- }
- for k, v in sfils.items():
- if fnl.endswith(k):
- self.add_info("\n<b>Related info</b>:\n")
- for p in v:
- self.add_info(" {}\n".format(p))
+ for ext in sg:
+ if ext == fnl[-4:]: continue
+ if self.strfm.exists(fnl[:-4] + ext):
+ self.add_info(" {}\n".format(self.fmt_hl_file(
+ fnl[:-4] + ext)))
+ # special files
+ fns = fnl.split("/")
+ last = ""
+ while len(fns) > 0:
+ if fns[-1:] == [""]:
+ continue
+ last = fns[-1:][0]
+ break
+ sa = None
+ if last in ["script.dat", "backgrnd.bg", "bgdata.dat", "bgedit.bg"]:
+ sa = ["/objs", "/scenes", "/opcodes"]
+ if last == "cast.ini":
+ sa = ["/objs", "/casts"]
+ if last == "names.ini":
+ sa = ["/objs", "/names"]
+ if last == "invntr.txt":
+ sa = ["/objs", "/invntr"]
+ if last == "bgs.ini":
+ sa = ["/scenes", "/bgs"]
+ if last in ["dialogue.fix", "dialogue.lod"]:
+ sa = ["/dlgs", "/msgs", "/dlgops"]
+ if last == "resource.qrc":
+ sa = ["/res", "/files"]
+ if last == "parts.ini":
+ sa = ["/parts"]
+ if last[:4] == "disk" and last[-3:] == ".id":
+ sa = ["/parts"]
+ if sa:
+ self.add_info("\n<b>See also</b>:\n")
+ for p in sa:
+ self.add_info(" <a href=\"{}\">{}</a>\n".format(p,
+ self.desc_path(p)))
-
-
-
self.switch_view(0)
keys = None
if self.last_path[:1] != ("files",):
# calc statistics
self.update_gui("Files ({})".format(len(self.strfm.strtable)))
for idx, fn in enumerate(self.strfm.strtableord):
- self.insert_lb_act(fn, ["files", idx], idx)
+ fnl = fn.lower().replace("\\", "/")
+ fnl = urllib.parse.quote_plus(fnl)
+ self.insert_lb_act(fn, ["files", fnl], fnl)
upd_files()
+ return True
def path_test(self, path):
@@ -2240,6 +2316,7 @@ class App(tkinter.Frame):
self.select_lb_item(None)
# display
display_page()
+ return True
def path_about(self, path):
self.switch_view(0)
@@ -2252,6 +2329,7 @@ class App(tkinter.Frame):
self.add_info(" https://bitbucket.org/romiq/p12simtran\n")
self.add_info("\n")
self.path_info_outline()
+ return True
def path_support(self, path):
self.switch_view(0)
@@ -2297,6 +2375,15 @@ class App(tkinter.Frame):
if self.sim or self.strfm:
self.path_info_outline()
+
+ return True
+
+ def desc_help(self, path):
+ if path == ("help",):
+ path = ("help", "index")
+ if path == ("help", "index"):
+ return "Index"
+ return "Help for " + self.desc_path(path[1])
def path_help(self, path):
self.switch_view(0)
@@ -2351,6 +2438,8 @@ class App(tkinter.Frame):
format(hlesc(hfn), hlesc(traceback.format_exc())))
else:
self.select_lb_item(None)
+
+ return True
def path_info(self, path):
self.switch_view(0)
@@ -2389,6 +2478,8 @@ class App(tkinter.Frame):
else:
self.add_info("Unknown data type \"{}\"\n".format(hlesc(name)))
+ return True
+
def on_open_data(self):
ft = [\
('all files', '.*')]
@@ -2529,6 +2620,7 @@ class App(tkinter.Frame):
if pref[0] in self.tran:
self.tran[pref[0]][tr.msgid] = tr.msgstr
self.tran["_"][tr.msgid] = tr.msgstr
+ return True
except:
self.switch_view(0)
self.clear_info()
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 1b6715cbd..b5a9685f0 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -275,7 +275,7 @@ class Engine:
if "StartRoom" in self.bgs_ini["Settings"]:
self.start_scene = self.bgs_ini["Settings"]["StartRoom"]
# load .STR
- strs = ["Flics", "Background", "Wav", "Music", "SFX"]
+ strs = ["Flics", "Background", "Wav", "Music", "SFX", "Speech"]
for strf in strs:
#pf = self.fman.find_path(self.curr_path + "bgs.ini")
#if not pf: continue
Commit: f5c4aa3cdc75499e97617bf5d9f3cedd6c8d3ec8
https://github.com/scummvm/scummvm-tools/commit/f5c4aa3cdc75499e97617bf5d9f3cedd6c8d3ec8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: sort files, files in stores
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index f74e2cb16..742bbac07 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -12,6 +12,9 @@
Ðзменено оÑобÑажение ÑпиÑка ÑообÑений, добавлен пеÑеÑ
од на wav Ñайл
Ðвижок: авÑомаÑиÑеÑÐºÐ°Ñ Ð·Ð°Ð³ÑÑзка Ñайлов speech из Ñ
ÑанилиÑ
ÐÑпÑавлена поÑледоваÑелÑÐ½Ð°Ñ Ð·Ð°Ð³ÑÑзка Ñазделов
+СоÑÑиÑовка ÑпиÑка вÑеÑ
Ñайлов
+ÐеÑеÑ
од Ð¾Ñ Ñ
ÑанилиÑа к пеÑÐ²Ð¾Ð¼Ñ ÑÐ°Ð¹Ð»Ñ Ð² обÑем ÑпиÑке
+СоÑÑиÑовка ÑпиÑка Ñайлов в Ñ
ÑанилиÑе
2014-12-20 веÑÑÐ¸Ñ 0.3e
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ee372fb6d..1d910d3de 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -780,6 +780,30 @@ class App(tkinter.Frame):
self.curr_gui.append(lambda:lab.pack_forget())
return lab
+ def add_toolgrp(self, label, glkey, items, cbupd):
+ def makecb(v, g):
+ def btncb():
+ self.gl_state[g] = v
+ cbupd()
+ return btncb
+ if label:
+ self.add_toollabel(label)
+ kl = list(items.keys())
+ kl.sort()
+ res = []
+ for k in kl:
+ b = self.add_toolbtn(items[k], makecb(k, glkey))
+ res.append([b, k])
+ return res
+
+ def upd_toolgrp(self, btns, state):
+ for btn, idx in btns:
+ if idx != state and state != -1:
+ btn.config(state = tkinter.NORMAL)
+ else:
+ btn.config(state = tkinter.DISABLED)
+
+
def clear_hist(self):
self.hist = self.hist[-1:]
self.histf = []
@@ -1577,11 +1601,7 @@ class App(tkinter.Frame):
sm = self.gl_state.get("msgs.sort", 0)
if msg:
sm = -1
- for btn, idx in self.curr_state["btnsort"]:
- if idx != sm and sm != -1:
- btn.config(state = tkinter.NORMAL)
- else:
- btn.config(state = tkinter.DISABLED)
+ self.upd_toolgrp(self.curr_state["btnsort"], sm)
self.clear_info()
if not msg:
if len(path) > 1:
@@ -1639,20 +1659,8 @@ class App(tkinter.Frame):
capt = capt[:40] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt),
["msgs", idx], idx)
- def sfn():
- self.gl_state["msgs.sort"] = 0
- upd_msgs()
- def sidx():
- self.gl_state["msgs.sort"] = 1
- upd_msgs()
- def stxt():
- self.gl_state["msgs.sort"] = 2
- upd_msgs()
- self.add_toollabel("Sort by")
- b1 = self.add_toolbtn("wav", sfn)
- b2 = self.add_toolbtn("order", sidx)
- b3 = self.add_toolbtn("text", stxt)
- self.curr_state["btnsort"] = [[b1, 0], [b2, 1], [b3, 2]]
+ self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
+ "msgs.sort", {0: "wav", 1: "order", 2: "text"}, upd_msgs)
# change
upd_msgs()
return True
@@ -2021,6 +2029,57 @@ class App(tkinter.Frame):
def path_stores(self, path):
if self.strfm is None:
return self.path_default([])
+ def upd_strs():
+ path = self.curr_path
+ # change
+ stid = None
+ if len(path) > 1:
+ # index
+ self.select_lb_item(path[1])
+ try:
+ stid = path[1]
+ except:
+ pass
+ else:
+ self.select_lb_item(None)
+ # display
+ self.clear_info()
+ sm = self.gl_state.get("strs.sortfiles", 0)
+ if stid is None:
+ sm = -1
+ self.upd_toolgrp(self.curr_state["btnsort"], sm)
+ self.curr_state["btnext"].config(state = tkinter.DISABLED)
+ if stid is None:
+ self.add_info("<b>Stores</b>\n\n")
+ for idx, st in enumerate(self.strfm.strfd):
+ self.add_info(" {}) <a href=\"/strs/{}\">{}</a>"
+ " (tag={})\n".
+ format(idx + 1, idx, st[1], st[2]))
+ else:
+ if stid >= len(self.strfm.strfd):
+ self.add_info("<b>Store</b> \"{}\" not found\n\n".\
+ format(path[1]))
+ return
+ self.curr_state["btnext"].config(state = tkinter.NORMAL)
+ _, name, tag, strlst = self.strfm.strfd[stid]
+ self.add_info("<b>Store</b>: {}\n".format(name))
+ flnk = "{}".format(len(strlst))
+ if len(strlst):
+ flnk = self.fmt_hl_file(strlst[0][0], flnk)
+ self.add_info(" Files: {}, Tag: {}\n\n".format(flnk, tag))
+
+ lst = []
+ for idx, (fname, _, _, _) in enumerate(strlst):
+ if sm == 0:
+ k = idx
+ else:
+ k = fname.lower().replace("\\", "/")
+ lst.append((k, idx, fname))
+ lst.sort()
+ for _, idx, fname in lst:
+ self.add_info(" {:5}) {}\n".format(idx + 1,
+ self.fmt_hl_file(fname)))
+
self.switch_view(0)
keys = None
if self.last_path[:1] != ("strs",):
@@ -2066,38 +2125,9 @@ class App(tkinter.Frame):
format(hlesc(fname), hlesc(traceback.format_exc())))
return
self.curr_state["btnext"] = self.add_toolbtn("Extract STR", ext_str)
- # change
- stid = None
- if len(path) > 1:
- # index
- self.select_lb_item(path[1])
- try:
- stid = path[1]
- except:
- pass
- else:
- self.select_lb_item(None)
- # display
- self.clear_info()
- self.curr_state["btnext"].config(state = tkinter.DISABLED)
- if stid is None:
- self.add_info("<b>Stores</b>\n\n")
- for idx, st in enumerate(self.strfm.strfd):
- self.add_info(" {}) <a href=\"/strs/{}\">{}</a> (tag={})\n".
- format(idx + 1, idx, st[1], st[2]))
- else:
- if stid >= len(self.strfm.strfd):
- self.add_info("<b>Store</b> \"{}\" not found\n\n".\
- format(path[1]))
- return
- self.curr_state["btnext"].config(state = tkinter.NORMAL)
- _, name, tag, strlst = self.strfm.strfd[stid]
- self.add_info("<b>Store</b>: {}\n".format(name))
- self.add_info(" Files: <a href=\"/files\">{}</a>, Tag: {}\n\n".
- format(len(strlst), tag))
- for idx, (fname, _, _, _) in enumerate(strlst):
- self.add_info(" {}) {}\n".format(idx + 1,
- self.fmt_hl_file(fname)))
+ self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
+ "strs.sortfiles", {0: "order", 1: "filename"}, upd_strs)
+ upd_strs()
return True
def desc_files(self, path):
@@ -2122,11 +2152,23 @@ class App(tkinter.Frame):
else:
self.select_lb_item(None)
self.clear_info()
+ sm = self.gl_state.get("files.sort", 0)
+ if fid is not None:
+ sm = -1
+ self.upd_toolgrp(self.curr_state["btnsort"], sm)
if fid is None:
self.add_info("<b>Files in all stores</b>\n\n")
+ lst = []
for idx, fn in enumerate(self.strfm.strtableord):
- stid, _, _ = self.strfm.strtable[fn]
- self.add_info(" {}) {}\n".format(
+ if sm == 0:
+ k = idx
+ else:
+ k = fn.lower().replace("\\", "/")
+ lst.append((k, idx, fn))
+ lst.sort()
+ for _, idx, fn in lst:
+ #stid, _, _ = self.strfm.strtable[fn]
+ self.add_info(" {:5}) {}\n".format(
idx + 1, self.fmt_hl_file(fn)))
else:
try:
@@ -2230,6 +2272,8 @@ class App(tkinter.Frame):
fnl = fn.lower().replace("\\", "/")
fnl = urllib.parse.quote_plus(fnl)
self.insert_lb_act(fn, ["files", fnl], fnl)
+ self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
+ "files.sort", {0: "order", 1: "filename"}, upd_files)
upd_files()
return True
@@ -2241,6 +2285,10 @@ class App(tkinter.Frame):
if len(path) > 2:
item = path[2]
self.clear_info()
+ sm = self.gl_state.get("test.info.mode", 0)
+ if item is None:
+ sm = -1
+ self.upd_toolgrp(self.curr_state["gbtns"], sm)
if item is None:
self.switch_view(0)
self.add_info("Select item " + path[1])
@@ -2254,7 +2302,7 @@ class App(tkinter.Frame):
self.add_info("Local mode {}\n".format(
self.curr_state.get("mode", None)))
self.add_info("Global mode {}\n".format(
- self.gl_state.get("mode", None)))
+ self.gl_state.get("test.info.mode", None)))
for i in range(100):
self.add_info(" Item {}\n".format(i))
@@ -2278,30 +2326,11 @@ class App(tkinter.Frame):
self.curr_state["btn1"].config(state = tkinter.NORMAL)
self.curr_state["btn2"].config(state = tkinter.DISABLED)
display_page()
- def sw_gmode1():
- print("Global Mode 1")
- self.gl_state["test.info.mode"] = 0
- self.curr_state["gbtn1"].config(state = tkinter.DISABLED)
- self.curr_state["gbtn2"].config(state = tkinter.NORMAL)
- display_page()
- def sw_gmode2():
- print("Global Mode 2")
- self.gl_state["test.info.mode"] = 1
- self.curr_state["gbtn1"].config(state = tkinter.NORMAL)
- self.curr_state["gbtn2"].config(state = tkinter.DISABLED)
- display_page()
self.curr_state["btn1"] = self.add_toolbtn("Mode 1", sw_mode1)
self.curr_state["btn2"] = self.add_toolbtn("Mode 2", sw_mode2)
# we store buttons in local state
- st = self.gl_state.get("test.info.mode", 0)
- b = self.add_toolbtn("Global Mode 1", sw_gmode1)
- if st == 0:
- b.config(state = tkinter.DISABLED)
- self.curr_state["gbtn1"] = b
- b = self.add_toolbtn("Global Mode 2", sw_gmode2)
- if st == 1:
- b.config(state = tkinter.DISABLED)
- self.curr_state["gbtn2"] = b
+ self.curr_state["gbtns"] = self.add_toolgrp(None, "test.info.mode",
+ {0: "mode 1", 1: "mode 2", 2: "mode 3"}, display_page)
# change
item = None
Commit: 65bbf7768e940ae3799735c32e8a25dcf1fb35aa
https://github.com/scummvm/scummvm-tools/commit/65bbf7768e940ae3799735c32e8a25dcf1fb35aa
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix long lists
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 742bbac07..81f89ee8c 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -15,6 +15,7 @@
СоÑÑиÑовка ÑпиÑка вÑеÑ
Ñайлов
ÐеÑеÑ
од Ð¾Ñ Ñ
ÑанилиÑа к пеÑÐ²Ð¾Ð¼Ñ ÑÐ°Ð¹Ð»Ñ Ð² обÑем ÑпиÑке
СоÑÑиÑовка ÑпиÑка Ñайлов в Ñ
ÑанилиÑе
+ÐÑÑÑÑп Ð¾Ñ Ð¿Ñавого кÑÐ°Ñ Ð´Ð»Ñ Ð±Ð¾Ð»ÑÑиÑ
ÑпиÑков вÑбиÑаеÑÑÑ Ð°Ð²ÑомаÑиÑеÑки
2014-12-20 веÑÑÐ¸Ñ 0.3e
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 1d910d3de..7e43ec3a5 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -9,6 +9,7 @@ from tkinter import ttk, font, filedialog, messagebox
from idlelib.WidgetRedirector import WidgetRedirector
import traceback
import urllib.parse
+import math
# Image processing
try:
@@ -51,6 +52,17 @@ def fmt_arg(value):
else:
return "0x{:X}".format(value)
+def fmt_dec(value, add = 0):
+ return "{{:{}}}".format(fmt_dec_len(value, add))
+
+def fmt_dec_len(value, add = 0):
+ if value == 0:
+ d = 1
+ else:
+ d = int(math.log10(value)) + 1
+ d += add
+ return d
+
def translit(text):
ru = "абвгдеÑзийклмнопÑÑÑÑÑÑ
ÑÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐРСТУФХЪЫЬÐ"
en = "abvgdeezijklmnoprstufh'y'eABVGDEEZIJKLMNOPRSTUFH'Y'E"
@@ -949,14 +961,17 @@ class App(tkinter.Frame):
self.switch_view(0)
self.clear_info()
self.add_info("<b>History</b>\n\n")
+ sz = max(len(self.hist[:-1]), len(self.histf))
+ fmt = fmt_dec(sz, 1)
+ fmt = " " + fmt + ") {}\n"
for idx, h in enumerate(self.hist[:-1]):
- self.add_info(" {:5d}) {}\n".format(idx - len(self.hist) + 1,
+ self.add_info(fmt.format(idx - len(self.hist) + 1,
self.desc_path(h[0])))
- self.add_info(" -----> {}\n".format(self.desc_path(self.curr_path)))
-
+ self.add_info(" {} {}\n".format("=" * fmt_dec_len(sz, 2) + ">",
+ self.desc_path(self.curr_path)))
for idx, h in enumerate(self.histf):
- self.add_info(" {:5d}) {}\n".format(idx + 1, self.desc_path(h[0])))
-
+ self.add_info(fmt.format(idx + 1, self.desc_path(h[0])))
+
def desc_default(self, path):
desc = ""
for item in path:
@@ -1365,8 +1380,9 @@ class App(tkinter.Frame):
else:
self.add_info("\n<b>References</b>: {}\n".\
format(len(rec.refs)))
+ fmtd = " " + fmt_dec(len(rec.refs)) + ") "
for idx, ref in enumerate(rec.refs):
- self.add_info(" {}) ".format(idx) +
+ self.add_info(fmtd.format(idx) +
self.fmt_hl_obj(ref[0].idx))
msg = ""
for arg in ref[1:]:
@@ -1383,6 +1399,8 @@ class App(tkinter.Frame):
resused = []
dlgused = []
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
+ fmtra = " " + fmt_dec(len(rec.acts)) + \
+ ") <u>on {}</u>, ops: {}{}\n"
for idx, act in enumerate(rec.acts):
msg = self.fmt_opcode(act.act_op)
cmt = ""
@@ -1398,10 +1416,10 @@ class App(tkinter.Frame):
else:
act_ref = "0x{:X}".format(act.act_ref)
msg += " 0x{:02X} {}".format(act.act_status, act_ref)
- self.add_info(" {}) <u>on {}</u>, ops: {}{}\n".format(\
- idx, msg, len(act.ops), cmt))
+ self.add_info(fmtra.format(idx, msg, len(act.ops), cmt))
+ fmtao = " " + fmt_dec(len(act.ops)) + " {} "
for oidx, op in enumerate(act.ops):
- self.add_info(" {}) {} ".format(oidx,
+ self.add_info(fmtao.format(oidx,
self.fmt_opcode(op.op_code)))
cmt = ""
if op.op_ref == rec.idx:
@@ -1699,15 +1717,18 @@ class App(tkinter.Frame):
grp.idx, grp.idx))
self.add_info(" arg1: {a} (0x{a:X})\n\n".format(a = grp.grp_arg1))
self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.acts)))
+ fmtga = " " + fmt_dec(len(grp.acts)) + \
+ ") <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: {}{}\n"
for idx, act in enumerate(grp.acts):
- self.add_info(" {}) <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: "\
- "{}{}\n".format(idx, self.fmt_opcode(act.opcode),
+ self.add_info(fmtga.format(idx, self.fmt_opcode(act.opcode),
self.fmt_hl_obj(act.ref), act.arg1, act.arg2, \
len(act.dlgs), self.fmt_cmt(" // " +
self.fmt_hl_obj(act.ref, True))))
+ fmtad = " " + fmt_dec(len(act.dlgs)) + \
+ ") <i>0x{:X} 0x{:X}</i>, ops: {}\n"
for didx, dlg in enumerate(act.dlgs):
- self.add_info(" {}) <i>0x{:X} 0x{:X}</i>, ops: {}\n".\
- format(didx, dlg.arg1, dlg.arg2, len(dlg.ops)))
+ self.add_info(fmtad.format(didx, dlg.arg1, dlg.arg2,
+ len(dlg.ops)))
# scan for used adreses
usedadr = []
for op in dlg.ops:
@@ -1906,8 +1927,10 @@ class App(tkinter.Frame):
self.add_info("<i>Not used in scripts</i>\n\n")
else:
self.add_info("<i>Used in scripts</i>: {}\n".format(len(ops)))
+ fmtops = " " + fmt_dec(len(ops)) + \
+ ") obj={}, act={}, op={} {}\n"
for idx, (obj_idx, aidx, oidx) in enumerate(ops):
- self.add_info(" {}) obj={}, act={}, op={} {}\n".format(
+ self.add_info(fmtops.format(
idx, self.fmt_hl_obj_scene(obj_idx, False), aidx, oidx,
self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
True))))
@@ -1917,8 +1940,10 @@ class App(tkinter.Frame):
self.add_info("<i>Not used in handlers</i>\n\n")
else:
self.add_info("<i>Used in handlers</i>: {}\n".format(len(acts)))
+ fmtacts = " " + fmt_dec(len(acts)) + \
+ ") obj={}, act={} {}\n"
for idx, (obj_idx, aidx) in enumerate(acts):
- self.add_info(" {}) obj={}, act={} {}\n".format(
+ self.add_info(fmtacts.format(
idx, self.fmt_hl_obj_scene(obj_idx, False), aidx,
self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
True))))
@@ -1929,9 +1954,10 @@ class App(tkinter.Frame):
else:
self.add_info("<i>Used in dialog handlers</i>: {}\n".format(
len(dacts)))
+ fmtdacts = " " + fmt_dec(len(dacts)) + \
+ ") obj={}, group=<a href=\"/dlgs/{}\">{}</a>, act={} {}\n"
for idx, (obj_idx, gidx, aidx) in enumerate(dacts):
- self.add_info(" {}) obj={}, group=<a href=\"/dlgs/{}\">{}"
- "</a>, act={} {}\n".format(
+ self.add_info(fmtdacts.format(
idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
aidx, self.fmt_cmt("// " + self.fmt_hl_obj_scene(
obj_idx, True))))
@@ -2011,9 +2037,11 @@ class App(tkinter.Frame):
self.add_info("<i>Not used in dialogs</i>\n\n")
else:
self.add_info("<i>Used in dialogs</i>: {}\n".format(len(dls)))
+ fmtdls = " " + fmt_dec(len(dacts)) + \
+ ") obj={}, group=<a href=\"/dlgs/{}\">{}" + \
+ "</a>, act={}, dlg={}, op={} {}\n"
for idx, (obj_idx, gidx, aidx, didx, oidx) in enumerate(dls):
- self.add_info(" {}) obj={}, group=<a href=\"/dlgs/{}\">{}"
- "</a>, act={}, dlg={}, op={} {}\n".format(
+ self.add_info(fmtdls.format(
idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
aidx, didx, oidx, self.fmt_cmt("// " +
self.fmt_hl_obj_scene(obj_idx, True))))
@@ -2051,10 +2079,10 @@ class App(tkinter.Frame):
self.curr_state["btnext"].config(state = tkinter.DISABLED)
if stid is None:
self.add_info("<b>Stores</b>\n\n")
+ fmt = " " + fmt_dec(len(self.strfm.strfd)) + \
+ ") <a href=\"/strs/{}\">{}</a> (tag={})\n"
for idx, st in enumerate(self.strfm.strfd):
- self.add_info(" {}) <a href=\"/strs/{}\">{}</a>"
- " (tag={})\n".
- format(idx + 1, idx, st[1], st[2]))
+ self.add_info(fmt.format(idx + 1, idx, st[1], st[2]))
else:
if stid >= len(self.strfm.strfd):
self.add_info("<b>Store</b> \"{}\" not found\n\n".\
@@ -2076,8 +2104,9 @@ class App(tkinter.Frame):
k = fname.lower().replace("\\", "/")
lst.append((k, idx, fname))
lst.sort()
+ fmt = " " + fmt_dec(len(lst)) + ") {}\n"
for _, idx, fname in lst:
- self.add_info(" {:5}) {}\n".format(idx + 1,
+ self.add_info(fmt.format(idx + 1,
self.fmt_hl_file(fname)))
self.switch_view(0)
@@ -2166,9 +2195,10 @@ class App(tkinter.Frame):
k = fn.lower().replace("\\", "/")
lst.append((k, idx, fn))
lst.sort()
+ fmt = " " + fmt_dec(len(lst)) + ") {}\n"
for _, idx, fn in lst:
#stid, _, _ = self.strfm.strtable[fn]
- self.add_info(" {:5}) {}\n".format(
+ self.add_info(fmt.format(
idx + 1, self.fmt_hl_file(fn)))
else:
try:
Commit: 2be7275bd5e795de56a1480d2d88d4e634b8a528
https://github.com/scummvm/scummvm-tools/commit/2be7275bd5e795de56a1480d2d88d4e634b8a528
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix tab for opcodes
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 7e43ec3a5..da8a71dcd 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1417,10 +1417,10 @@ class App(tkinter.Frame):
act_ref = "0x{:X}".format(act.act_ref)
msg += " 0x{:02X} {}".format(act.act_status, act_ref)
self.add_info(fmtra.format(idx, msg, len(act.ops), cmt))
- fmtao = " " + fmt_dec(len(act.ops)) + " {} "
+ fmtao = " " + fmt_dec(len(act.ops)) + ")"
for oidx, op in enumerate(act.ops):
- self.add_info(fmtao.format(oidx,
- self.fmt_opcode(op.op_code)))
+ self.add_info(self.fmt_cmt(fmtao.format(oidx)))
+ self.add_info(" " + self.fmt_opcode(op.op_code) + " ")
cmt = ""
if op.op_ref == rec.idx:
self.add_info("THIS")
Commit: 56a2a6b1c18bbfb95f66f0acb626be4fe17fe74a
https://github.com/scummvm/scummvm-tools/commit/56a2a6b1c18bbfb95f66f0acb626be4fe17fe74a
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: decode MSK, LEG, OFF. display MSK, LEG, OFF, FLC
Changed paths:
A engines/petka/petka/imgleg.py
A engines/petka/petka/imgmsk.py
engines/petka/help/changes.txt
engines/petka/p12explore.py
engines/petka/petka/__init__.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 81f89ee8c..0832dc58d 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -16,6 +16,9 @@
ÐеÑеÑ
од Ð¾Ñ Ñ
ÑанилиÑа к пеÑÐ²Ð¾Ð¼Ñ ÑÐ°Ð¹Ð»Ñ Ð² обÑем ÑпиÑке
СоÑÑиÑовка ÑпиÑка Ñайлов в Ñ
ÑанилиÑе
ÐÑÑÑÑп Ð¾Ñ Ð¿Ñавого кÑÐ°Ñ Ð´Ð»Ñ Ð±Ð¾Ð»ÑÑиÑ
ÑпиÑков вÑбиÑаеÑÑÑ Ð°Ð²ÑомаÑиÑеÑки
+Ðвижок: декодиÑование Ñайлов LEG, OFF, MSK
+ÐÑобÑажение инÑоÑмаÑии из LEG, OFF, MSK, FLC
+ÐнÑоÑмаÑÐ¸Ñ Ð¾ ÑекÑÑем Ñазделе оÑобÑажаеÑÑÑ Ð² заголовке окна
2014-12-20 веÑÑÐ¸Ñ 0.3e
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index da8a71dcd..71b714801 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -283,7 +283,7 @@ class App(tkinter.Frame):
# bind path handlers
self.path_handler["parts"] = [self.path_parts, self.desc_parts]
- self.path_handler["res"] = [self.path_res, None] # TODO:
+ self.path_handler["res"] = [self.path_res, self.desc_res]
self.path_handler["objs"] = [self.path_objs_scenes,
desc_def("Objects", "Object")]
self.path_handler["scenes"] = [self.path_objs_scenes,
@@ -315,7 +315,6 @@ class App(tkinter.Frame):
self.update_after()
repath = "/about"
- print(self.start_act)
for cmd, arg in self.start_act:
if cmd == "load":
if not self.open_data_from(arg):
@@ -337,7 +336,6 @@ class App(tkinter.Frame):
print("DEBUG: stop opening after " + arg)
repath = ""
break
- print("Loading end", repath)
if repath:
self.open_path(repath)
@@ -475,6 +473,16 @@ class App(tkinter.Frame):
self.hist.append([path])
self.histf = []
print("DEBUG: Open", path)
+ # set title
+ capt = APPNAME
+ try:
+ if path == ("about",):
+ capt = APPNAME + " - " + VERSION
+ else:
+ capt = APPNAME + " - " + self.desc_path(path)
+ except:
+ pass
+ self.master.title(capt)
self.curr_path = path
if len(path) > 0:
self.curr_help = path[0]
@@ -1097,6 +1105,18 @@ class App(tkinter.Frame):
return False
return True
+ def desc_res(self, path):
+ if path == ("res",):
+ path = ("res", "all")
+ if path[1] == "flt":
+ if len(path) > 2:
+ return "Resource type {}".format(path[2])
+ return "Resources by type"
+ if path[1] == "all":
+ if len(path) > 2:
+ return "Resource {}".format(path[2])
+ return "Resources"
+ return self.path_default(path)
def path_res(self, path):
# res - full list
@@ -1839,7 +1859,7 @@ class App(tkinter.Frame):
self.switch_view(0)
keys = None
def keyslist():
- opstat = {} # opcpdes count
+ opstat = {} # opcodes count
acstat = {} # handlers count
dastat = {} # dialog handlers count
keys = list(petka.OPCODES.keys())
@@ -2293,6 +2313,49 @@ class App(tkinter.Frame):
self.add_info(" <a href=\"{}\">{}</a>\n".format(p,
self.desc_path(p)))
+ if fnl[-4:] in [".leg", ".off"]:
+ legf = petka.LEGLoader()
+ legf.load_data(self.strfm.read_file_stream(fnl))
+ self.add_info("\n<b>LEG/OFF data</b>: {} frame(s)\n".format(
+ len(legf.coords)))
+ fmt = " " + fmt_dec(len(legf.coords)) + ") {}, {}\n"
+ for idx, (x, y) in enumerate(legf.coords):
+ self.add_info(fmt.format(idx + 1, x, y))
+
+ if fnl[-4:] == ".msk":
+ mskf = petka.MSKLoader()
+ mskf.load_data(self.strfm.read_file_stream(fnl))
+ self.add_info("\n<b>MSK data</b>: {} record(s)\n".format(
+ len(mskf.rects)))
+ self.add_info(" bound: {}, {} - {}, {}\n".format(
+ *mskf.bound))
+ fmt = " " + fmt_dec(len(mskf.rects)) + \
+ ") stamp = {}, {} rect(s)\n"
+ for idx, (stamp, rs) in enumerate(mskf.rects):
+ self.add_info(fmt.format(idx + 1, stamp, len(rs)))
+ fmtr = " " + fmt_dec(len(rs)) + ") {}, {} - {}, {}\n"
+ for idxr, r in enumerate(rs):
+ self.add_info(fmtr.format(idxr + 1, *r))
+
+ if fnl[-4:] == ".flc":
+ flcf = petka.FLCLoader()
+ flcf.load_info(self.strfm.read_file_stream(fnl))
+ if flcf.image:
+ # PIL
+ self.add_info("\n<b>FLC data</b> (pil)\n")
+ self.add_info(" Mode: {}\n Size: {}x{}\n"
+ " Frames: {}\n Delay: {}".\
+ format(flcf.image.mode, \
+ flcf.image.size[0], flcf.image.size[1],
+ flcf.frame_num, flcf.image.info["duration"]))
+ else:
+ self.add_info("\n<b>FLC data</b> (internal)\n")
+ self.add_info(" Mode: P\n Size: {}x{}\n"\
+ " Frames: {}\nDelay: {}".\
+ format(flcf.width, flcf.height, \
+ flcf.frame_num, flcf.delay))
+
+
self.switch_view(0)
keys = None
if self.last_path[:1] != ("files",):
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index 40b354c6f..e48578003 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -5,3 +5,6 @@ from .engine import Engine, OPCODES, DLGOPS
from .fman import FileManager
from .imgbmp import BMPLoader
from .imgflc import FLCLoader
+from .imgleg import LEGLoader
+from .imgmsk import MSKLoader
+
diff --git a/engines/petka/petka/imgleg.py b/engines/petka/petka/imgleg.py
new file mode 100644
index 000000000..cc6c9398e
--- /dev/null
+++ b/engines/petka/petka/imgleg.py
@@ -0,0 +1,27 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import array, struct, io
+
+from . import EngineError
+
+class LEGLoader:
+ def __init__(self):
+ self.coords = []
+
+ def load_info(self, f):
+ return self.load_data(f)
+
+ def load_data(self, f):
+ hdr = f.read(4)
+ if hdr != b"xyof":
+ raise EngineError("Bad LEG/OFF magic \"{}\"".format(hdr))
+
+ rest = f.read()
+ if len(rest) % 8:
+ raise EngineError("Bad LEG/OFF size {}".format(len(rest)))
+
+ sf = struct.unpack("<{}l".format(len(rest) // 4), rest)
+ self.coords = [[sf[i * 2], sf[i * 2 + 1]] for i in range(len(rest) // 8)]
+
diff --git a/engines/petka/petka/imgmsk.py b/engines/petka/petka/imgmsk.py
new file mode 100644
index 000000000..cfd20dd9f
--- /dev/null
+++ b/engines/petka/petka/imgmsk.py
@@ -0,0 +1,48 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import array, struct, io
+
+from . import EngineError
+
+class MSKLoader:
+ def __init__(self):
+ self.bound = [0, 0, 0, 0]
+ self.rects = []
+
+ def load_info(self, f):
+ return self.load_data(f)
+
+ def load_data(self, f):
+ rest = f.read()
+ f.seek(0)
+ delta = len(rest) - 16
+ rects = []
+ while delta > 0:
+ temp = f.read(4)
+ delta -= 4
+ rects_len = struct.unpack_from("<I", temp)[0]
+ rec = []
+ for r_ref in range(rects_len):
+ temp = f.read(8)
+ delta -= 8
+ l,t,r,b = struct.unpack_from("<4h", temp)
+ rec.append([l, t, r, b])
+ rects.append(rec)
+ delta -= 4
+
+ if delta != 0:
+ raise EngineError("Bad MSK file")
+
+ temp = f.read(len(rects) * 4)
+ frms = struct.unpack_from("<{}I".format(len(rects)), temp)
+
+ if len(rects) != len(frms):
+ raise EngineError("Bad MSK file structure")
+
+ temp = f.read(16)
+ self.bound = struct.unpack_from("<4i", temp)
+
+ self.rects = list(zip(reversed(frms), rects))
+
Commit: 36514cf080b30c772dac60a0960c0a06bcd6ed48
https://github.com/scummvm/scummvm-tools/commit/36514cf080b30c772dac60a0960c0a06bcd6ed48
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix doc
Changed paths:
engines/petka/help/changes.txt
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 0832dc58d..1c796036a 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,6 @@
ЧÑо нового
==========
-2014-12-27 веÑÑÐ¸Ñ 0.3f
+2014-12-24 веÑÑÐ¸Ñ 0.3f
----------------------
СоÑÑиÑовка ÑообÑений по имени Ñайла, по поÑÑдкÑ, по ÑекÑÑÑ
ÐнÑоÑмаÑÐ¸Ñ Ð¾ ÑвÑзаннÑÑ
ÑайлаÑ
(FLC, MSG, LEF, OFF и BMP, CVX)
Commit: 040c526b50ce3eb29ecf2becc30c88a370d6f1ae
https://github.com/scummvm/scummvm-tools/commit/040c526b50ce3eb29ecf2becc30c88a370d6f1ae
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix doc, fix other
Changed paths:
A engines/petka/help/dlgops.txt
A engines/petka/help/opcodes.txt
engines/petka/help/casts.txt
engines/petka/help/changes.txt
engines/petka/help/dlgs.txt
engines/petka/help/files.txt
engines/petka/help/index.txt
engines/petka/help/info.txt
engines/petka/help/invntr.txt
engines/petka/help/list
engines/petka/help/msgs.txt
engines/petka/help/names.txt
engines/petka/help/objs.txt
engines/petka/help/parts.txt
engines/petka/help/res_view.txt
engines/petka/help/scenes.txt
engines/petka/help/strs.txt
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/help/casts.txt b/engines/petka/help/casts.txt
index eade4010a..defa5742e 100644
--- a/engines/petka/help/casts.txt
+++ b/engines/petka/help/casts.txt
@@ -2,4 +2,7 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ ÑвеÑа опиÑаний пÑедмеÑов на ÑкÑане.
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 1c796036a..e3c475d1e 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,12 @@
ЧÑо нового
==========
+2014-12-27 веÑÑÐ¸Ñ 0.3g
+----------------------
+ÐÑпÑавлено оÑобÑажение в ÑпиÑке ÑÑаз (ÑообÑений)
+ÐÐ¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ ÑпÑавоÑнÑе ÑÐ°Ð¹Ð»Ñ Ð¾ опкодаÑ
(обÑекÑов и диалогов)
+Ðвижок: ÑлÑÑÑена загÑÑзка иÑоÑмаÑии о подÑобноÑÑÑÑ
ÑÑен (пеÑÑпекÑива, пеÑеÑ
одÑ)
+ÐÑобÑажение инÑоÑмаÑии о пеÑÑпекÑиве ÑÑенÑ
+
2014-12-24 веÑÑÐ¸Ñ 0.3f
----------------------
СоÑÑиÑовка ÑообÑений по имени Ñайла, по поÑÑдкÑ, по ÑекÑÑÑ
diff --git a/engines/petka/help/dlgops.txt b/engines/petka/help/dlgops.txt
new file mode 100644
index 000000000..cad8a9c24
--- /dev/null
+++ b/engines/petka/help/dlgops.txt
@@ -0,0 +1,13 @@
+ÐайÑ-код диалогов
+
+Ðа ÑÑой ÑÑÑаниÑе можно ÑÑаÑиÑÑÐ¸ÐºÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¸Ð»Ð¾Ð³Ð¾Ð²ÑÑ
опкодов иÑполÑзÑемÑÑ
+гÑÑппами дилогов в ÑекÑÑей загÑÑженной ÑаÑÑи.
+
+ÐополниÑелÑно:
+
+ * <a href="/help/comp_dlg">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии DIALOGUE.FIX</a>
+ * <a href="/help/info">СпÑавоÑники</a>
+ * <a href="/help/msgs">СобÑениÑ</a>
+ * <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
+
+
diff --git a/engines/petka/help/dlgs.txt b/engines/petka/help/dlgs.txt
index e95d96cde..7b166b2ce 100644
--- a/engines/petka/help/dlgs.txt
+++ b/engines/petka/help/dlgs.txt
@@ -2,4 +2,10 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð²Ñе иÑполÑзÑемÑе гÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð².
+ÐополниÑелÑно:
+
+ * <a href="/help/msgs">СобÑениÑ</a>
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/scenes">СÑенÑ</a>
+ * <a href="/help/dlgops">ÐайÑ-код дилогов</a>
diff --git a/engines/petka/help/files.txt b/engines/petka/help/files.txt
index ab776caf5..996400360 100644
--- a/engines/petka/help/files.txt
+++ b/engines/petka/help/files.txt
@@ -2,4 +2,8 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¾Ð±Ñий ÑпиÑок загÑÑженнÑÑ
Ñайлов.
+ÐополниÑелÑно:
+
+ * <a href="/help/strs">Ð¥ÑанилиÑа</a>
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index 9ba1946ba..bc5de66e5 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -27,6 +27,8 @@
* <a href="/help/casts">ЦвеÑа пÑедмеÑов</a>
* <a href="/help/msgs">СобÑениÑ</a>
* <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
+ * <a href="/help/opcodes">ÐайÑ-код</a>
+ * <a href="/help/dlgops">ÐайÑ-код дилогов</a>
* <a href="/help/strs">Ð¥ÑанилиÑа</a>
* <a href="/help/files">ФайлÑ</a>
diff --git a/engines/petka/help/info.txt b/engines/petka/help/info.txt
index 51ea6c817..553bcb46e 100644
--- a/engines/petka/help/info.txt
+++ b/engines/petka/help/info.txt
@@ -5,3 +5,10 @@
* ÐÐ¾Ð´Ñ Ð¾Ð¿ÐµÑаÑий в обÑабоÑÑикаÑ
* ÐÐ¾Ð´Ñ Ð¾Ð¿ÐµÑаÑий в диалогаÑ
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/scenes">СÑенÑ</a>
+ * <a href="/help/opcodes">ÐайÑ-код</a>
+ * <a href="/help/dlgops">ÐайÑ-код дилогов</a>
+
diff --git a/engines/petka/help/invntr.txt b/engines/petka/help/invntr.txt
index 7bfdd3be9..81190eb8c 100644
--- a/engines/petka/help/invntr.txt
+++ b/engines/petka/help/invntr.txt
@@ -2,4 +2,7 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¾Ð¿Ð¸Ñание пÑедмеÑов инвенÑаÑÑ.
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
diff --git a/engines/petka/help/list b/engines/petka/help/list
index 332e97473..ddca09a42 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -11,6 +11,8 @@ invntr
casts
msgs
dlgs
+opcodes
+dlgops
strs
files
translate
diff --git a/engines/petka/help/msgs.txt b/engines/petka/help/msgs.txt
index 2221caceb..6264e39bd 100644
--- a/engines/petka/help/msgs.txt
+++ b/engines/petka/help/msgs.txt
@@ -2,4 +2,8 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð²Ñе иÑполÑзÑемÑе ÑообÑениÑ.
+ÐополниÑелÑно:
+
+ * <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
diff --git a/engines/petka/help/names.txt b/engines/petka/help/names.txt
index 11331ac02..e418fd51c 100644
--- a/engines/petka/help/names.txt
+++ b/engines/petka/help/names.txt
@@ -2,4 +2,7 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе оÑобÑажаемÑе имена.
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
diff --git a/engines/petka/help/objs.txt b/engines/petka/help/objs.txt
index 3a4f380f7..7f0e40562 100644
--- a/engines/petka/help/objs.txt
+++ b/engines/petka/help/objs.txt
@@ -2,4 +2,11 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе обÑекÑÑ Ð¸ иÑ
паÑамеÑÑÑ.
+ÐополниÑелÑно:
+
+ * <a href="/help/scenes">СÑенÑ</a>
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
+ * <a href="/help/names">ÐÑобÑажаемнÑе имена</a>
+ * <a href="/help/invntr">ÐнвенÑаÑÑ</a>
+ * <a href="/help/casts">ЦвеÑа пÑедмеÑов</a>
diff --git a/engines/petka/help/opcodes.txt b/engines/petka/help/opcodes.txt
new file mode 100644
index 000000000..f4ae9ef73
--- /dev/null
+++ b/engines/petka/help/opcodes.txt
@@ -0,0 +1,12 @@
+ÐайÑ-код
+
+Ðа ÑÑой ÑÑÑаниÑе можно ÑÑаÑиÑÑÐ¸ÐºÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð¿ÐºÐ¾Ð´Ð¾Ð² иÑполÑзÑемÑÑ
обÑекÑами
+и ÑÑенами в ÑекÑÑей загÑÑженной ÑаÑÑи.
+
+ÐополниÑелÑно:
+
+ * <a href="/help/comp_scr">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT</a>
+ * <a href="/help/info">СпÑавоÑники</a>
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/scenes">СÑенÑ</a>
+
diff --git a/engines/petka/help/parts.txt b/engines/petka/help/parts.txt
index 0554a03d0..10e6bcd33 100644
--- a/engines/petka/help/parts.txt
+++ b/engines/petka/help/parts.txt
@@ -3,4 +3,19 @@
Ðа ÑÑой ÑÑÑаниÑе можно вÑбÑаÑÑ ÑаÑÑÑ Ñ ÐºÐ¾ÑоÑой бÑÐ´ÐµÑ Ð² далÑнейÑем веÑÑиÑÑ
ÑабоÑа.
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/scenes">СÑенÑ</a>
+ * <a href="/help/names">ÐÑобÑажаемнÑе имена</a>
+ * <a href="/help/invntr">ÐнвенÑаÑÑ</a>
+ * <a href="/help/casts">ЦвеÑа пÑедмеÑов</a>
+ * <a href="/help/msgs">СобÑениÑ</a>
+ * <a href="/help/dlgs">ÐÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²</a>
+ * <a href="/help/opcodes">ÐайÑ-код</a>
+ * <a href="/help/dlgops">ÐайÑ-код дилогов</a>
+ * <a href="/help/strs">Ð¥ÑанилиÑа</a>
+ * <a href="/help/files">ФайлÑ</a>
diff --git a/engines/petka/help/res_view.txt b/engines/petka/help/res_view.txt
index b0ff49f59..f0d6b3395 100644
--- a/engines/petka/help/res_view.txt
+++ b/engines/petka/help/res_view.txt
@@ -1,3 +1,9 @@
ÐодÑÐ¾Ð±Ð½Ð°Ñ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑеÑÑÑÑе
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¿Ð¾Ð´ÑобнÑÑ Ð¸Ð½ÑоÑмаÑÐ¸Ñ Ð¾ ÑеÑÑÑÑе.
+
+ÐополниÑелÑно:
+
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
+ * <a href="/help/files">ФайлÑ</a>
+
diff --git a/engines/petka/help/scenes.txt b/engines/petka/help/scenes.txt
index 31e7e9302..58767ea2d 100644
--- a/engines/petka/help/scenes.txt
+++ b/engines/petka/help/scenes.txt
@@ -2,4 +2,8 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð¸ÑполÑзÑемÑе ÑÑÐµÐ½Ñ Ð¸ иÑ
паÑамеÑÑÑ.
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
diff --git a/engines/petka/help/strs.txt b/engines/petka/help/strs.txt
index eca1839f6..c00b3cdc5 100644
--- a/engines/petka/help/strs.txt
+++ b/engines/petka/help/strs.txt
@@ -2,4 +2,8 @@
Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ Ð²Ñе загÑÑженнÑе Ñ
ÑанилиÑа и иÑ
ÑодеÑжимое.
+ÐополниÑелÑно:
+
+ * <a href="/help/files">ФайлÑ</a>
+ * <a href="/help/res">РеÑÑÑÑÑ</a>
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 71b714801..473d8df4c 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -30,7 +30,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3e 2014-12-20"
+VERSION = "v0.3g 2014-12-27"
def hlesc(value):
if value is None:
@@ -43,6 +43,9 @@ def cesc(value):
def fmt_hl(loc, desc):
return "<a href=\"{}\">{}</a>".format(loc, desc)
+def fmt_hl_len(loc, desc, ln):
+ sz = max(ln - len(desc), 0)
+ return " "*sz + "<a href=\"{}\">{}</a>".format(loc, desc)
def fmt_arg(value):
if value < 10:
@@ -1509,6 +1512,11 @@ class App(tkinter.Frame):
" #{}".format(hid) + self.fmt_cmt(" // " +
self.fmt_hl_obj_scene(oid, True)) + "\n")
+ # perspective
+ if not isobj and rec.persp:
+ self.add_info("\n<b>Perspective</b>:\n {}, {}, {}, {}, {}\n".
+ format(*rec.persp))
+
# enter areas
if not isobj and rec.entareas:
self.add_info("\n<b>Enter areas</b>: {}\n".format(
@@ -1516,6 +1524,8 @@ class App(tkinter.Frame):
for sf, oo in rec.entareas:
self.add_info(" <i>from</i>: {}\n".format(
self.fmt_hl_scene(sf.idx, True)))
+ #
+ print(rec.name)
self.add_info(" <i>on</i>: {}\n".format(
self.fmt_hl_obj(oo.idx, True)))
return True
@@ -1657,10 +1667,13 @@ class App(tkinter.Frame):
k = msg.name
lst.append((k, msg.msg_wav, idx, msg.name))
lst.sort()
+ fmtlen = fmt_dec_len(len(lst))
for _, wav, idx, capt in lst:
- self.add_info(" <a href=\"/msgs/{}\">{}</a> - {} - {}\n".
- format(idx, idx, self.fmt_hl_file("speech{}/{}".format(
- self.sim.curr_part, wav), wav), capt))
+ self.add_info(" " + fmt_hl_len("/msgs/{}".format(idx),
+ "{}".format(idx), fmtlen))
+ self.add_info(" - {} - {}\n".format(
+ self.fmt_hl_file("speech{}/{}".format(
+ self.sim.curr_part, wav), wav), capt))
else:
# msg info
self.add_info("<b>Message</b>: {}\n".format(path[1]))
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index b5a9685f0..5c87945c4 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -277,25 +277,25 @@ class Engine:
# load .STR
strs = ["Flics", "Background", "Wav", "Music", "SFX", "Speech"]
for strf in strs:
- #pf = self.fman.find_path(self.curr_path + "bgs.ini")
- #if not pf: continue
if strf in ini:
self.fman.load_store(ini[strf], 1)
- # load script.dat, backgrnd.bg and resources.qrc
+ # load script.dat, backgrnd.bg, resources.qrc, etc
self.load_script()
- # parse enter areas
+ # bgs.ini: parse enter areas and perspective
+ settings = self.bgs_ini.get("Settings", {})
for scene in self.scenes:
scene.entareas = None
+ areas = self.bgs_ini.get(scene.name, {})
if scene.name in self.bgs_ini:
scene.entareas = []
- for key in self.bgs_ini["__order__"][scene.name]:
+ for key in areas.keys():
# search scene
sf = None
for scenefrom in self.scenes:
if scenefrom.name == key:
sf = scenefrom
break
- value = self.bgs_ini[scene.name][key]
+ value = areas[key]
# search objects
oo = None
for objon in self.objects:
@@ -304,6 +304,16 @@ class Engine:
break
if sf and oo:
scene.entareas.append((sf, oo))
+ # persp
+ persp = settings.get(scene.name, "")
+ persp = persp.split(" ")
+ persp = [x for x in persp if x]
+ try:
+ persp = [float(persp[0]), float(persp[1]),
+ int(persp[2]), int(persp[3]), float(persp[4])]
+ except:
+ persp = None
+ scene.persp = persp
# load names & invntr
self.load_names()
# load dialogs
Commit: 7c2bb9349c7079d9bcade44cf8256b0fb1fb64bd
https://github.com/scummvm/scummvm-tools/commit/7c2bb9349c7079d9bcade44cf8256b0fb1fb64bd
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: enchance
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 473d8df4c..3b5b92194 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -45,7 +45,7 @@ def fmt_hl(loc, desc):
def fmt_hl_len(loc, desc, ln):
sz = max(ln - len(desc), 0)
- return " "*sz + "<a href=\"{}\">{}</a>".format(loc, desc)
+ return " "*sz + fmt_hl(loc, desc)
def fmt_arg(value):
if value < 10:
@@ -931,26 +931,26 @@ class App(tkinter.Frame):
if self.sim:
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
- self.add_info(" Resources: <a href=\"/res\">{}</a>\n".\
- format(len(self.sim.res)))
- self.add_info(" Objects: <a href=\"/objs\">{}</a>\n".\
- format(len(self.sim.objects)))
- self.add_info(" Scenes: <a href=\"/scenes\">{}</a>\n".\
- format(len(self.sim.scenes)))
- self.add_info(" Names: <a href=\"/names\">{}</a>\n".\
- format(len(self.sim.names)))
- self.add_info(" Invntr: <a href=\"/invntr\">{}</a>\n".\
- format(len(self.sim.invntr)))
- self.add_info(" Casts: <a href=\"/casts\">{}</a>\n".\
- format(len(self.sim.casts)))
- self.add_info(" Messages <a href=\"/msgs\">{}</a>\n".\
- format(len(self.sim.msgs)))
- self.add_info(" Dialog groups: <a href=\"/dlgs\">{}</a>\n".\
- format(len(self.sim.dlgs)))
- self.add_info(" Opened stores: <a href=\"/strs\">{}</a>\n".
- format(len(self.strfm.strfd)))
- self.add_info(" Files: <a href=\"/files\">{}</a>\n".
- format(len(self.strfm.strtable)))
+ self.add_info(" Resources: " + fmt_hl("/res",
+ len(self.sim.res)) + "\n")
+ self.add_info(" Objects: " + fmt_hl("/objs",
+ len(self.sim.objects)) + "\n")
+ self.add_info(" Scenes: " + fmt_hl("/scenes",
+ len(self.sim.scenes)) + "\n")
+ self.add_info(" Names: " + fmt_hl("/names",
+ len(self.sim.names)) + "\n")
+ self.add_info(" Invntr: " + fmt_hl("/invntr",
+ len(self.sim.invntr)) + "\n")
+ self.add_info(" Casts: " + fmt_hl("/casts",
+ len(self.sim.casts)) + "\n")
+ self.add_info(" Messages " + fmt_hl("/msgs",
+ len(self.sim.msgs)) + "\n")
+ self.add_info(" Dialog groups: " + fmt_hl("/dlgs",
+ len(self.sim.dlgs)) + "\n")
+ self.add_info(" Opened stores: " + fmt_hl("strs",
+ len(self.strfm.strfd)) + "\n")
+ self.add_info(" Files: " + fmt_hl("/files",
+ len(self.strfm.strtable)) + "\n")
scn = hlesc(self.sim.start_scene)
for scene in self.sim.scenes:
if scene.name == self.sim.start_scene:
@@ -958,15 +958,14 @@ class App(tkinter.Frame):
break
self.add_info(" Start scene: {}\n".format(scn))
self.add_info("\n")
- self.add_info(" <a href=\"/opcodes\">Opcodes</a>\n")
- self.add_info(" <a href=\"/dlgops\">Dialog opcodes</a>\n\n")
-
+ self.add_info(" " + fmt_hl("/opcodes", "Opcodes") + "\n")
+ self.add_info(" " + fmt_hl("/dlgops", "Dialog opcodes") + "\n")
elif self.strfm:
self.add_info("Single store mode\n\n")
- self.add_info(" Opened stores: <a href=\"/strs\">{}</a>\n".
- format(len(self.strfm.strfd)))
- self.add_info(" Files: <a href=\"/files\">{}</a>\n".
- format(len(self.strfm.strtable)))
+ self.add_info(" Opened stores: " + fmt_hl("/strs",
+ len(self.strfm.strfd)) + "\n")
+ self.add_info(" Files: " + fmt_hl("/files",
+ len(self.strfm.strtable)) + "\n")
def show_hist(self):
self.switch_view(0)
@@ -1255,8 +1254,8 @@ class App(tkinter.Frame):
def path_res_status(self):
self.switch_view(0)
self.clear_info()
- self.add_info("<b>Resources</b>: <a href=\"/res\">{}</a>\n"\
- "Filetypes:\n".format(len(self.sim.res)))
+ self.add_info("<b>Resources</b>: " + fmt_hl("/res", len(self.sim.res))
+ + "\nFiletypes:\n")
fts = {}
for res in self.sim.res.values():
fp = res.rfind(".")
@@ -2323,8 +2322,8 @@ class App(tkinter.Frame):
if sa:
self.add_info("\n<b>See also</b>:\n")
for p in sa:
- self.add_info(" <a href=\"{}\">{}</a>\n".format(p,
- self.desc_path(p)))
+ self.add_info(" " + fmt_hl(p, self.desc_path(p))
+ + "\n")
if fnl[-4:] in [".leg", ".off"]:
legf = petka.LEGLoader()
Commit: 08e06d907b6092e30db0a6681d938bcdc9e32d33
https://github.com/scummvm/scummvm-tools/commit/08e06d907b6092e30db0a6681d938bcdc9e32d33
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fixes
Changed paths:
engines/petka/help/dlgops.txt
engines/petka/help/opcodes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/dlgops.txt b/engines/petka/help/dlgops.txt
index cad8a9c24..7d4f0981c 100644
--- a/engines/petka/help/dlgops.txt
+++ b/engines/petka/help/dlgops.txt
@@ -3,6 +3,8 @@
Ðа ÑÑой ÑÑÑаниÑе можно ÑÑаÑиÑÑÐ¸ÐºÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð´Ð¸Ð»Ð¾Ð³Ð¾Ð²ÑÑ
опкодов иÑполÑзÑемÑÑ
гÑÑппами дилогов в ÑекÑÑей загÑÑженной ÑаÑÑи.
+ЦиÑÑÑ - коллиÑеÑÑво иÑполÑзований опкодов во вÑеÑ
обÑабоÑÑикаÑ
далогов.
+
ÐополниÑелÑно:
* <a href="/help/comp_dlg">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии DIALOGUE.FIX</a>
diff --git a/engines/petka/help/opcodes.txt b/engines/petka/help/opcodes.txt
index f4ae9ef73..bcf4884d9 100644
--- a/engines/petka/help/opcodes.txt
+++ b/engines/petka/help/opcodes.txt
@@ -3,6 +3,11 @@
Ðа ÑÑой ÑÑÑаниÑе можно ÑÑаÑиÑÑÐ¸ÐºÑ Ð¸ÑполÑÐ·Ð¾Ð²Ð°Ð½Ð¸Ñ Ð¾Ð¿ÐºÐ¾Ð´Ð¾Ð² иÑполÑзÑемÑÑ
обÑекÑами
и ÑÑенами в ÑекÑÑей загÑÑженной ÑаÑÑи.
+ÐеÑÐ²Ð°Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ° - колиÑеÑÑво иÑполÑзований ÑÑого опкода в обÑабоÑÑике.
+ÐÑоÑÐ°Ñ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ° - колиÑеÑÑво обÑабоÑÑиков Ñакого Ñипа Ñ Ð¾Ð±ÑекÑов и ÑÑен.
+ТÑеÑÑÑ ÐºÐ¾Ð»Ð¾Ð½ÐºÐ° - колиÑеÑÑво обÑабоÑÑиков Ñакого Ñипа Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð².
+
+
ÐополниÑелÑно:
* <a href="/help/comp_scr">СинÑакÑÐ¸Ñ ÐºÐ¾Ð¼Ð¿Ð¸Ð»ÑÑии SCRIPT.DAT</a>
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3b5b92194..7706c94ee 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1136,7 +1136,7 @@ class App(tkinter.Frame):
return self.path_default(path)
def path_res_open(self, pref, res_id, mode):
- self.curr_help = "res_view"
+ self.curr_help = "res_view" # help override
if res_id not in self.sim.res:
self.switch_view(0)
self.clear_info()
@@ -1523,8 +1523,6 @@ class App(tkinter.Frame):
for sf, oo in rec.entareas:
self.add_info(" <i>from</i>: {}\n".format(
self.fmt_hl_scene(sf.idx, True)))
- #
- print(rec.name)
self.add_info(" <i>on</i>: {}\n".format(
self.fmt_hl_obj(oo.idx, True)))
return True
Commit: 78fd00b49c86e05e0bf6058012411721811a3183
https://github.com/scummvm/scummvm-tools/commit/78fd00b49c86e05e0bf6058012411721811a3183
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: canv resize
Changed paths:
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 7706c94ee..8cde05189 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -656,7 +656,10 @@ class App(tkinter.Frame):
def switch_view(self, main):
# main view
if main == self.curr_main: return
+ last = self.curr_main
self.curr_main = main
+ rw = None
+ rh = None
if main == 0:
self.canv_view.delete(tkinter.ALL)
self.canv_view.grid_forget()
@@ -669,6 +672,10 @@ class App(tkinter.Frame):
self.scr_view_x.config(command = self.text_view.xview)
self.scr_view_y.config(command = self.text_view.yview)
else:
+
+ if last == 0:
+ rw = self.text_view.winfo_width()
+ rh = self.text_view.winfo_height()
self.canv_view.delete(tkinter.ALL)
self.text_view.grid_forget()
self.canv_view.grid(row = 0, column = 0, \
@@ -679,6 +686,10 @@ class App(tkinter.Frame):
)
self.scr_view_x.config(command = self.canv_view.xview)
self.scr_view_y.config(command = self.canv_view.yview)
+ if rh:
+ print(rh)
+ self.canv_view.height = rh
+ print(self.canv_view.winfo_height())
def clear_info(self):
self.text_view.delete(0.0, tkinter.END)
Commit: 56d009d9d561e98142d2de0ebe847268cbe11ab8
https://github.com/scummvm/scummvm-tools/commit/56d009d9d561e98142d2de0ebe847268cbe11ab8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor bgs loading
Changed paths:
engines/petka/petka/engine.py
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 5c87945c4..87488c6ac 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -261,19 +261,6 @@ class Engine:
self.curr_speech = ""
self.curr_diskid = None
- # load BGS.INI
- self.bgs_ini = {}
- self.start_scene = None
- bgsfn = self.curr_path + "bgs.ini"
- if self.fman.exists(bgsfn):
- f = self.fman.read_file_stream(bgsfn)
- try:
- self.bgs_ini = self.parse_ini(f)
- finally:
- f.close()
- if "Settings" in self.bgs_ini:
- if "StartRoom" in self.bgs_ini["Settings"]:
- self.start_scene = self.bgs_ini["Settings"]["StartRoom"]
# load .STR
strs = ["Flics", "Background", "Wav", "Music", "SFX", "Speech"]
for strf in strs:
@@ -281,39 +268,8 @@ class Engine:
self.fman.load_store(ini[strf], 1)
# load script.dat, backgrnd.bg, resources.qrc, etc
self.load_script()
- # bgs.ini: parse enter areas and perspective
- settings = self.bgs_ini.get("Settings", {})
- for scene in self.scenes:
- scene.entareas = None
- areas = self.bgs_ini.get(scene.name, {})
- if scene.name in self.bgs_ini:
- scene.entareas = []
- for key in areas.keys():
- # search scene
- sf = None
- for scenefrom in self.scenes:
- if scenefrom.name == key:
- sf = scenefrom
- break
- value = areas[key]
- # search objects
- oo = None
- for objon in self.objects:
- if objon.name == value:
- oo = objon
- break
- if sf and oo:
- scene.entareas.append((sf, oo))
- # persp
- persp = settings.get(scene.name, "")
- persp = persp.split(" ")
- persp = [x for x in persp if x]
- try:
- persp = [float(persp[0]), float(persp[1]),
- int(persp[2]), int(persp[3]), float(persp[4])]
- except:
- persp = None
- scene.persp = persp
+ # load persp & scenes enter points
+ self.load_bgs()
# load names & invntr
self.load_names()
# load dialogs
@@ -480,6 +436,55 @@ class Engine:
r, g, b = 255, 255, 255
obj.cast = (r, g, b)
+ def load_bgs(self):
+ # load BGS.INI
+ self.bgs_ini = {}
+ self.start_scene = None
+ bgsfn = self.curr_path + "bgs.ini"
+ if self.fman.exists(bgsfn):
+ f = self.fman.read_file_stream(bgsfn)
+ try:
+ self.bgs_ini = self.parse_ini(f)
+ finally:
+ f.close()
+
+ settings = self.bgs_ini.get("Settings", {})
+ self.start_scene = settings.get("StartRoom", None)
+
+ # bgs.ini: parse enter areas and perspective
+ for scene in self.scenes:
+ scene.entareas = None
+ areas = self.bgs_ini.get(scene.name, {})
+ if scene.name in self.bgs_ini:
+ scene.entareas = []
+ for key in areas.keys():
+ # search scene
+ sf = None
+ for scenefrom in self.scenes:
+ if scenefrom.name == key:
+ sf = scenefrom
+ break
+ value = areas[key]
+ # search objects
+ oo = None
+ for objon in self.objects:
+ if objon.name == value:
+ oo = objon
+ break
+ if sf and oo:
+ scene.entareas.append((sf, oo))
+ # persp
+ persp = settings.get(scene.name, "")
+ persp = persp.split(" ")
+ persp = [x for x in persp if x]
+ try:
+ persp = [float(persp[0]), float(persp[1]),
+ int(persp[2]), int(persp[3]), float(persp[4])]
+ except:
+ persp = None
+ scene.persp = persp
+
+
def load_dialogs(self, fixname = None, lodname = None, noobjref = False):
self.msgs = []
# DIALOGUES.LOD
Commit: 17d4eba581536eaba14bf9650d090f0149aba8e0
https://github.com/scummvm/scummvm-tools/commit/17d4eba581536eaba14bf9650d090f0149aba8e0
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: save decoding
Changed paths:
A engines/petka/help/save.txt
A engines/petka/petka/saves.py
engines/petka/help/changes.txt
engines/petka/help/cmdline.txt
engines/petka/help/faq.txt
engines/petka/help/index.txt
engines/petka/help/list
engines/petka/p12explore.py
engines/petka/petka/__init__.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
engines/petka/petka/imgbmp.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index e3c475d1e..e960e2f31 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -6,6 +6,8 @@
ÐÐ¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ ÑпÑавоÑнÑе ÑÐ°Ð¹Ð»Ñ Ð¾ опкодаÑ
(обÑекÑов и диалогов)
Ðвижок: ÑлÑÑÑена загÑÑзка иÑоÑмаÑии о подÑобноÑÑÑÑ
ÑÑен (пеÑÑпекÑива, пеÑеÑ
одÑ)
ÐÑобÑажение инÑоÑмаÑии о пеÑÑпекÑиве ÑÑенÑ
+Ðвижок: загÑÑзка ÑоÑ
Ñанений (ÑаÑÑиÑно)
+ÐагÑÑзка ÑоÑ
Ñанений и оÑобÑажение инÑоÑмаÑии (ÑаÑÑиÑно)
2014-12-24 веÑÑÐ¸Ñ 0.3f
----------------------
diff --git a/engines/petka/help/cmdline.txt b/engines/petka/help/cmdline.txt
index 52d7c8549..c552b87b1 100644
--- a/engines/petka/help/cmdline.txt
+++ b/engines/petka/help/cmdline.txt
@@ -6,11 +6,15 @@
p12explore [-d пÑÑÑ Ðº даннÑм]|[-t пÑÑÑ Ðº пеÑеводÑ]|[оÑкÑÑваемÑй Ñаздел]
+ÐÑÑÑ Ðº даннÑм - пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð¸Ð»Ð¸ каÑÐ°Ð»Ð¾Ð³Ñ Ð³Ð´Ðµ наÑ
одиÑÑÑ Ñайл Ñ Ð´Ð°Ð½Ð½Ñми.
+
ÐÑкÑÑÑÑ Ñ
ÑанилиÑе
- p12explore [-s пÑÑÑ Ðº .str]
+ p12explore [-s пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ .str]
-ÐÑÑÑ Ðº даннÑм - пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ Ð¸Ð»Ð¸ каÑÐ°Ð»Ð¾Ð³Ñ Ð³Ð´Ðµ наÑ
одиÑÑÑ Ñайл Ñ Ð´Ð°Ð½Ð½Ñми.
+ÐагÑÑзиÑÑ ÑоÑ
ÑанÑнное ÑоÑÑоÑние
+
+ p12explore [-sd пÑÑÑ Ðº ÑÐ°Ð¹Ð»Ñ save?.dat]
ÐÑновнÑе ÑазделÑ:
@@ -20,9 +24,14 @@
* /res/all/31000 - загÑÑзиÑÑ ÑеÑÑÑÑ 31000
* /objs - обÑекÑÑ
* /scenes - ÑÑенÑ
+ * /names - оÑобÑажаемÑе имена
+ * /invntr - инвенÑаÑÑ
+ * /casts - ÑвеÑа пÑедмеÑов
* /msgs - ÑообÑениÑ
* /dlgs - гÑÑÐ¿Ð¿Ñ Ð´Ð¸Ð°Ð»Ð¾Ð³Ð¾Ð²
* /strs - Ñ
ÑанилиÑа
+ * /files - загÑÑженнве ÑайлÑ
+ * /save - ÑоÑ
ÑанÑнное ÑоÑÑоÑние игÑÑ
Так как поÑле оÑкÑÑÑÐ¸Ñ Ð´Ð°Ð½Ð½ÑÑ
даннÑе о пеÑеводе ÑдалÑÑÑÑÑ Ñо ÑекомендÑеÑÑÑ
ÑледÑÑÑий поÑÑдок загÑÑзки:
diff --git a/engines/petka/help/faq.txt b/engines/petka/help/faq.txt
index 1e30f7fe7..2b8d65773 100644
--- a/engines/petka/help/faq.txt
+++ b/engines/petka/help/faq.txt
@@ -7,3 +7,6 @@
пÑедназнаÑена Ð´Ð»Ñ Ðемо-веÑÑии 1й ÑаÑÑи. Тем не менее Ð²Ñ Ð¼Ð¾Ð¶ÐµÑе пеÑейÑи в
Ñаздел вÑÐ±Ð¾Ñ ÑаÑÑи (Edit->Parts) и нажаÑÑ ÐºÐ½Ð¾Ð¿ÐºÑ [Fix Paths].
+<i>ÐÑи оÑкÑÑÑии Ñайла Ñ ÑоÑ
Ñанением (SAVEx.DAT) поÑвлÑеÑÑÑ Ð¾Ñибка</i>
+УбедиÑеÑÑ ÑÑо Ñайл Ñ ÑоÑ
Ñанением пÑедназнаÑен Ð´Ð»Ñ ÑÑой игÑÑ.
+
diff --git a/engines/petka/help/index.txt b/engines/petka/help/index.txt
index bc5de66e5..9a2449a62 100644
--- a/engines/petka/help/index.txt
+++ b/engines/petka/help/index.txt
@@ -11,6 +11,7 @@
* ÐÑоÑмаÑÑиваÑÑ Ð¸ ÑаÑпаковÑваÑÑ ÑодеÑжимое .STR Ñайлов
* РабоÑаÑÑ Ñ Ð¿ÐµÑеводом игÑÑ Ð½Ð° дÑÑгой ÑзÑк (Ñм. <a href="/help/translate">Ð´Ð»Ñ Ð¿ÐµÑеводÑика</a>)
* ÐекомпилиÑоваÑÑ ÑÑÑÑкÑÑÑÑ Ð¸ <a href="/help/compiler">компилиÑоваÑÑ</a> обÑаÑно
+ * ÐÑоÑмаÑÑиваÑÑ ÑоÑ
Ñаненное ÑоÑÑоÑние
* <a href="/help/changes">ЧÑо нового</a>
* <a href="/help/faq">ЧаÑÑо задаваемÑе вопÑоÑÑ</a>
@@ -31,7 +32,7 @@
* <a href="/help/dlgops">ÐайÑ-код дилогов</a>
* <a href="/help/strs">Ð¥ÑанилиÑа</a>
* <a href="/help/files">ФайлÑ</a>
-
+ * <a href="/help/save">СоÑ
Ñаненное ÑоÑÑоÑние</a>
ÐÑоÑÐ°Ñ Ð¸Ð½ÑоÑмаÑиÑ
diff --git a/engines/petka/help/list b/engines/petka/help/list
index ddca09a42..1273fb9a1 100644
--- a/engines/petka/help/list
+++ b/engines/petka/help/list
@@ -15,6 +15,7 @@ opcodes
dlgops
strs
files
+save
translate
cmdline
support
diff --git a/engines/petka/help/save.txt b/engines/petka/help/save.txt
new file mode 100644
index 000000000..28beae819
--- /dev/null
+++ b/engines/petka/help/save.txt
@@ -0,0 +1,11 @@
+СоÑ
Ñаненное ÑоÑÑоÑние
+
+Ðа ÑÑой ÑÑÑаниÑе можно пÑоÑмоÑÑеÑÑ ÑодеÑжимое ÑоÑ
ÑанÑнного ÑоÑÑоÑниÑ.
+ÐÐ»Ñ ÑабоÑÑ Ð½ÐµÐ¾Ð±Ñ
одимо пÑедваÑиÑелÑно загÑÑзиÑÑ Ñайл SAVEx.DAT.
+
+ÐополниÑелÑно:
+
+ * <a href="/help/objs">ÐбÑекÑÑ</a>
+ * <a href="/help/scenes">СÑенÑ</a>
+
+
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 8cde05189..642ddfae0 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -156,8 +156,7 @@ class HyperlinkManager:
if tag[:6] == "hyper-":
self.links[tag]()
return
-
-
+
# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
class ReadOnlyText(tkinter.Text):
def __init__(self, *args, **kwargs):
@@ -167,7 +166,7 @@ class ReadOnlyText(tkinter.Text):
self.redirector.register("insert", lambda *args, **kw: "break")
self.delete = \
self.redirector.register("delete", lambda *args, **kw: "break")
-
+
class App(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
@@ -207,9 +206,11 @@ class App(tkinter.Frame):
self.sim = None
# store manager
self.strfm = None
+ # save
+ self.save = None
# translation
- self.tran = None
-
+ self.tran = None
+
def create_widgets(self):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
@@ -310,6 +311,7 @@ class App(tkinter.Frame):
self.path_handler["strs"] = [self.path_stores,
desc_def("Stores", "Store")]
self.path_handler["files"] = [self.path_files, self.desc_files]
+ self.path_handler["save"] = [self.path_save, "Save"]
self.path_handler["test"] = [self.path_test, "Tests"]
self.path_handler["about"] = [self.path_about, "About"]
self.path_handler["support"] = [self.path_support, "Support"]
@@ -329,6 +331,12 @@ class App(tkinter.Frame):
break
else:
repath = "/strs"
+ elif cmd == "savedat":
+ if not self.open_savedat_from(arg):
+ repath = ""
+ break
+ else:
+ repath = "/save"
elif cmd == "tran":
if not self.open_tran_from(arg):
repath = ""
@@ -363,6 +371,9 @@ class App(tkinter.Frame):
self.menufile.add_command(
command = self.on_open_data,
label = "Open data...")
+ self.menufile.add_command(
+ command = self.on_open_savedat,
+ label = "Open SAVEx.DAT...")
self.menufile.add_separator()
self.menufile.add_command(
command = self.on_open_str,
@@ -378,7 +389,7 @@ class App(tkinter.Frame):
editnav = ["/parts", None, "/res", "/objs", "/scenes", "/names",
"/invntr", "/casts", "/msgs", "/dlgs", "/opcodes", "/dlgops",
- "/strs", "/files"]
+ "/strs", "/files", "/save"]
mkmenupaths(self.menuedit, editnav)
self.menunav = tkinter.Menu(self.master, tearoff = 0)
@@ -977,6 +988,8 @@ class App(tkinter.Frame):
len(self.strfm.strfd)) + "\n")
self.add_info(" Files: " + fmt_hl("/files",
len(self.strfm.strtable)) + "\n")
+ if self.save:
+ self.add_info(" " + fmt_hl("/save", "Save") + "\n")
def show_hist(self):
self.switch_view(0)
@@ -1039,6 +1052,13 @@ class App(tkinter.Frame):
]
for name, act in acts:
self.insert_lb_act(name, act)
+
+ if self.save is not None:
+ acts = [
+ ("Save", "/save"),
+ ]
+ for name, act in acts:
+ self.insert_lb_act(name, act)
return True
def desc_parts(self, path):
@@ -2375,7 +2395,6 @@ class App(tkinter.Frame):
" Frames: {}\nDelay: {}".\
format(flcf.width, flcf.height, \
flcf.frame_num, flcf.delay))
-
self.switch_view(0)
keys = None
@@ -2390,6 +2409,43 @@ class App(tkinter.Frame):
"files.sort", {0: "order", 1: "filename"}, upd_files)
upd_files()
return True
+
+ def path_save(self, path):
+ if self.sim is None:
+ return self.path_default([])
+
+ def upd_save():
+ path = self.curr_path
+ fid = None
+ self.switch_view(0)
+ if self.save is None:
+ self.add_info("<b>Saved state:not loaded</b>\n\n")
+
+ if path == ("save",):
+ path = ("save", "info")
+ if path[1] == "shot":
+ self.select_lb_item("shot")
+ self.main_image = \
+ self.make_image(self.save.shot)
+ self.switch_view(1)
+ self.update_canvas()
+ elif path[1] == "info":
+ self.clear_info()
+ self.add_info("<b>Saved state:</b>\n\n")
+ self.add_info(" part: {}, chapter {}\n".format(
+ self.save.part, self.save.chap))
+ self.add_info(" stamp: " + hlesc(self.save.stamp) + "\n")
+ self.add_info(" scene: " + hlesc(self.save.scene) + "\n")
+ else:
+ self.select_lb_item("info")
+
+ if self.last_path[:1] != ("save",):
+ # calc statistics
+ self.update_gui("Save")
+ self.insert_lb_act("Info", ["save"], "info")
+ self.insert_lb_act("Screenshot", ["save", "shot"], "shot")
+ upd_save()
+ return True
def path_test(self, path):
@@ -2516,6 +2572,12 @@ class App(tkinter.Frame):
self.add_info(" <b>Path</b>: {}\n\n".format(
hlesc(self.strfm.root)))
+ self.add_info("<b>Saved state</b>: ")
+ if not self.strfm:
+ self.add_info("<i>not loaded</i>\n")
+ else:
+ self.add_info("<i>loaded</i>\n\n")
+
if self.sim or self.strfm:
self.path_info_outline()
@@ -2667,7 +2729,7 @@ class App(tkinter.Frame):
os.chdir(os.path.dirname(fn))
self.clear_hist()
if self.open_str_from(fn):
- self.open_path("")
+ self.open_path("/strs")
self.clear_hist()
def open_str_from(self, fn):
@@ -2685,6 +2747,49 @@ class App(tkinter.Frame):
self.clear_info()
self.add_info("Error opening \"{}\" \n\n{}".\
format(hlesc(fn), hlesc(traceback.format_exc())))
+
+ def on_open_savedat(self):
+ ft = [\
+ ('Save files (*.dat)', '.DAT'),
+ ('all files', '.*')]
+ fn = filedialog.askopenfilename(parent = self,
+ title = "Open SAVEx.DAT file",
+ filetypes = ft,
+ initialdir = os.path.abspath(os.curdir))
+ if not fn: return
+ os.chdir(os.path.dirname(osfn))
+ if self.open_savedat_from(fn):
+ self.open_path("/save")
+
+ def open_savedat_from(self, fn):
+ if self.sim is None:
+ self.switch_view(0)
+ self.update_gui("")
+ self.clear_info()
+ self.add_info("Open data before loading saves")
+ return
+ self.save = None
+ try:
+ self.save = petka.SaveLoader("cp1251")
+ with open(fn, "rb") as f:
+ self.save.load_data(f, self.sim.curr_part,
+ len(self.sim.objects) + len(self.sim.scenes))
+ if self.save.part != self.sim.curr_part:
+ # load
+ print("DEBUG: change part {}".format(self.save.part))
+ self.sim.open_part(self.save.part, 0)
+ f.seek(0)
+ self.save.load_data(f, self.sim.curr_part,
+ len(self.sim.objects) + len(self.sim.scenes))
+ return True
+ except:
+ print("DEBUG: Error opening SAVEx.DAT")
+ self.save = None
+ self.switch_view(0)
+ self.update_gui("")
+ self.clear_info()
+ self.add_info("Error opening \"{}\" \n\n{}".\
+ format(hlesc(fn), hlesc(traceback.format_exc())))
def on_tran_save(self):
@@ -2845,6 +2950,9 @@ def main():
elif argv[0] == "-s": # open str file
app.start_act.append(["str", argv[1]])
argv = argv[2:]
+ elif argv[0] == "-sd": # open savex.dat file
+ app.start_act.append(["savedat", argv[1]])
+ argv = argv[2:]
elif argv[0] == "-t": # open translation
app.start_act.append(["tran", argv[1]])
argv = argv[2:]
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index e48578003..775345ee1 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -7,4 +7,5 @@ from .imgbmp import BMPLoader
from .imgflc import FLCLoader
from .imgleg import LEGLoader
from .imgmsk import MSKLoader
+from .saves import SaveLoader
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 87488c6ac..0f164244f 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -659,3 +659,6 @@ class Engine:
for op in self.dlgops:
f.write(struct.pack("<H2B", op.ref, op.arg, op.opcode))
+ def load_save(self, ls):
+ pass
+
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index 427c9a752..e83d68682 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -72,7 +72,7 @@ class FileManager:
# add file descriptor
self.strfd.append((f, name, tag, strlst))
print("DEBUG: Loaded store \"{}\"".format(name))
-
+
def read_file(self, fname):
sf = fname.lower().replace("\\", "/")
if sf in self.strtable:
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 7f3ec4c4e..26e8261ba 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -69,8 +69,8 @@ class BMPLoader:
return pictw, picth, picture_data
- def pixelswap16(self, pw, ph, pd):
- # convert 16 bit to 24
+ def pixelswap16ud(self, pw, ph, pd):
+ # convert 16 bit to 24 + vertical reverse
b16arr = array.array("H") # unsigned short
b16arr.frombytes(pd)
b16arr.byteswap()
@@ -84,6 +84,21 @@ class BMPLoader:
rgb[off + 2] = (b16 >> 8) & 0b11111000
return rgb
+ def pixelswap16(self, pw, ph, pd):
+ # convert 16 bit to 24
+ b16arr = array.array("H") # unsigned short
+ b16arr.frombytes(pd)
+ #b16arr.byteswap()
+ rgb = array.array("B", [0] * pw * ph * 3)
+ for j in range(ph):
+ for i in range(pw):
+ off = j * pw * 3 + i * 3
+ b16 = b16arr[j * pw + i]
+ rgb[off + 2] = (b16 << 3) & 0b11111000
+ rgb[off + 1] = (b16 >> 3) & 0b11111100
+ rgb[off + 0] = (b16 >> 8) & 0b11111000
+ return rgb
+
def load_info(self, f):
try:
pw, ph, pd = self.load_data_int16(f)
@@ -93,11 +108,20 @@ class BMPLoader:
f.seek(0)
self.image = Image.open(f)
+ def load_raw(self, pw, ph, pd):
+ if Image:
+ pd = self.pixelswap16(pw, ph, pd).tobytes()
+ self.image = Image.frombytes("RGB", (pw, ph), pd)
+ else:
+ self.width = pw
+ self.height = ph
+ self.rgb = self.pixelswap16(pw, ph, pd)
+
def load_data(self, f):
try:
pw, ph, pd = self.load_data_int16(f)
if Image:
- pd = self.pixelswap16(pw, ph, pd).tobytes()
+ pd = self.pixelswap16ud(pw, ph, pd).tobytes()
self.image = Image.frombytes("RGB", (pw, ph), pd)
else:
self.width = pw
@@ -106,4 +130,4 @@ class BMPLoader:
except:
f.seek(0)
self.image = Image.open(f)
-
+
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
new file mode 100644
index 000000000..f565577bb
--- /dev/null
+++ b/engines/petka/petka/saves.py
@@ -0,0 +1,82 @@
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2014
+
+import array, struct, io
+import binascii
+
+from . import EngineError, BMPLoader
+
+
+class SaveLoader:
+ def __init__(self, enc = None):
+ self.part = None
+ self.chap = None
+ self.stamp = None
+ self.enc = enc
+
+ def load_data(self, f, part, objnum):
+ data = f.read(8)
+ self.part, self.chap = struct.unpack("<2I", data)
+ if self.part != part: return
+
+ # read date stamp, asciiz
+ stamp = b""
+ while len(stamp) < 30:
+ ch = f.read(1)
+ if ch == b"\x00": break
+ stamp += ch
+ self.stamp = stamp.decode(self.enc)
+ print("Saved at", len(self.stamp), repr(self.stamp))
+ hz1 = f.read(max(0, 29 - len(stamp)))
+ #print("HZ1", hz1)
+
+ # read screenshot
+ sl = 108 * 81 * 2
+ rgb = f.read(sl)
+ if len(rgb) != sl:
+ raise EngineError("Bad SAVE length (no screenshot)")
+ self.shot = BMPLoader()
+ self.shot.load_raw(108, 81, rgb)
+
+ print("RGB beg", binascii.hexlify(rgb[:8]))
+ print("RGB end", binascii.hexlify(rgb[-8:]))
+
+ hz2 = f.read(216)
+ if hz2 != b"\x00" * 216:
+ print("HZ2", hz2) # all zeroes?
+ raise EngineError("Bad SAVE error in HZ2 field")
+
+ #print("HZ2", hz2) # all zeroes?
+ data = f.read(4)
+ hz3 = struct.unpack("<I", data)[0]
+ print("HZ3", hz3)
+
+ def readstr():
+ data = f.read(4)
+ strlen = struct.unpack("<I", data)[0]
+ s = f.read(strlen)
+ #print("STR", strlen, data, s)
+ return s.decode(self.enc)
+
+ print("Req", objnum)
+ for i in range(objnum):
+ s1 = readstr()
+ s2 = readstr()
+ data = f.read(33)
+ #print(i, s1, s2)
+
+
+ # scene
+ data = f.read(4)
+ hz4len = struct.unpack("<I", data)[0]
+ data = f.read(hz4len * 2)
+ hz4 = struct.unpack("<{}H".format(hz4len), data)
+ print("HZ4", hz4)
+
+ self.scene = readstr()
+ print("Scene:", self.scene)
+
+
+ data = f.read()
+ print(len(data))
Commit: 762ebd64edf828e6d1bc30eaed5c9a8647cc90f9
https://github.com/scummvm/scummvm-tools/commit/762ebd64edf828e6d1bc30eaed5c9a8647cc90f9
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: saved decoding: inventory
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/saves.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 642ddfae0..29a21e6da 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -10,6 +10,7 @@ from idlelib.WidgetRedirector import WidgetRedirector
import traceback
import urllib.parse
import math
+import binascii
# Image processing
try:
@@ -2419,7 +2420,8 @@ class App(tkinter.Frame):
fid = None
self.switch_view(0)
if self.save is None:
- self.add_info("<b>Saved state:not loaded</b>\n\n")
+ self.add_info("<b>Saved state</b>: not loaded\n\n")
+ return
if path == ("save",):
path = ("save", "info")
@@ -2436,6 +2438,40 @@ class App(tkinter.Frame):
self.save.part, self.save.chap))
self.add_info(" stamp: " + hlesc(self.save.stamp) + "\n")
self.add_info(" scene: " + hlesc(self.save.scene) + "\n")
+
+ self.add_info(" invntr: {}\n".format(len(self.save.invntr)))
+ fmt = " " + fmt_dec(len(self.save.invntr)) + ") "
+ for idx, inv in enumerate(self.save.invntr):
+ self.add_info(fmt.format(idx + 1) +
+ self.fmt_hl_obj_scene(inv, True) + "\n")
+
+ self.add_info("\n objects: {}\n".format(len(
+ self.save.objects)))
+ fmt = " " + fmt_dec(len(self.save.objects)) + ") \"{}\" {}\n"
+
+ for idx, obj in enumerate(self.save.objects):
+ self.add_info(fmt.format(idx + 1, obj["name"],
+ obj["alias"]))
+ fndobj = None
+ for sobj in self.sim.objects + self.sim.scenes:
+ if sobj.name == obj["name"]:
+ fndobj = sobj
+ break
+ if fndobj:
+ self.add_info(" " +
+ self.fmt_hl_obj_scene(fndobj.idx, True) + "\n")
+
+ self.add_info(" {}, {}, {}, {}, {}, {}, {}, {}, {}\n".
+ format(*obj["recs"]))
+ if obj["res"] in self.sim.res:
+ res_id = obj["res"]
+ self.add_info(" " + fmt_hl("/res/all/{}".
+ format(res_id), "{}".format(res_id)) +
+ " (0x{:X}) - {}\n".format(res_id,
+ hlesc(self.sim.res[res_id])))
+
+
+
else:
self.select_lb_item("info")
@@ -2573,8 +2609,8 @@ class App(tkinter.Frame):
hlesc(self.strfm.root)))
self.add_info("<b>Saved state</b>: ")
- if not self.strfm:
- self.add_info("<i>not loaded</i>\n")
+ if not self.save:
+ self.add_info("<i>not loaded</i>\n\n")
else:
self.add_info("<i>loaded</i>\n\n")
@@ -2733,7 +2769,6 @@ class App(tkinter.Frame):
self.clear_hist()
def open_str_from(self, fn):
- self.last_fn = fn
self.clear_data()
try:
self.strfm = petka.FileManager(os.path.dirname(fn))
@@ -2757,7 +2792,7 @@ class App(tkinter.Frame):
filetypes = ft,
initialdir = os.path.abspath(os.curdir))
if not fn: return
- os.chdir(os.path.dirname(osfn))
+ os.chdir(os.path.dirname(os.path.dirname(fn)))
if self.open_savedat_from(fn):
self.open_path("/save")
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index f565577bb..ef70363bb 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -14,6 +14,7 @@ class SaveLoader:
self.chap = None
self.stamp = None
self.enc = enc
+ self.objects = []
def load_data(self, f, part, objnum):
data = f.read(8)
@@ -21,15 +22,10 @@ class SaveLoader:
if self.part != part: return
# read date stamp, asciiz
- stamp = b""
- while len(stamp) < 30:
- ch = f.read(1)
- if ch == b"\x00": break
- stamp += ch
+ stamp = f.read(30)
+ stamp = stamp.split(b"\x00")[0]
self.stamp = stamp.decode(self.enc)
print("Saved at", len(self.stamp), repr(self.stamp))
- hz1 = f.read(max(0, 29 - len(stamp)))
- #print("HZ1", hz1)
# read screenshot
sl = 108 * 81 * 2
@@ -64,16 +60,20 @@ class SaveLoader:
s1 = readstr()
s2 = readstr()
data = f.read(33)
+ obj = {"name": s1, "alias": s2, "data": data}
+ recs = struct.unpack("<B8i", data)
+ obj["recs"] = recs
+ obj["res"] = recs[2]
+ self.objects.append(obj)
#print(i, s1, s2)
-
- # scene
+ # invntr
data = f.read(4)
- hz4len = struct.unpack("<I", data)[0]
- data = f.read(hz4len * 2)
- hz4 = struct.unpack("<{}H".format(hz4len), data)
- print("HZ4", hz4)
+ invlen = struct.unpack("<I", data)[0]
+ data = f.read(invlen * 2)
+ self.invntr = struct.unpack("<{}H".format(invlen), data)
+ # scene
self.scene = readstr()
print("Scene:", self.scene)
Commit: a820343b11459ef88fc05e6457bd9963d0543636
https://github.com/scummvm/scummvm-tools/commit/a820343b11459ef88fc05e6457bd9963d0543636
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: saves decoding: charter positions, cursor resources
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/__init__.py
engines/petka/petka/engine.py
engines/petka/petka/saves.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 29a21e6da..497721134 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -908,6 +908,14 @@ class App(tkinter.Frame):
return fmt
return "{} (0x{:X})".format(rec_id, rec_id)
+ def fmt_hl_res(self, resid, full = True):
+ if resid in self.sim.res:
+ lnk = fmt_hl("/res/all/{}".format(resid), resid)
+ if full:
+ lnk += " (0x{:X}) - {}".format(resid,
+ hlesc(self.sim.res[resid]))
+ return lnk
+
def fmt_hl_obj(self, obj_id, full = False):
return self.fmt_hl_rec(self.sim.obj_idx, "objs", obj_id, full, "obj")
@@ -947,6 +955,12 @@ class App(tkinter.Frame):
def fmt_hl_dlg(self, grp_id, full = False):
return self.fmt_hl_rec(self.sim.dlg_idx, "dlgs", grp_id, full, "dlg")
+ def fmt_hl_file(self, fn, capt = None):
+ fnl = fn.lower().replace("\\", "/")
+ capt = capt or fn
+ fid = urllib.parse.quote_plus(fnl)
+ return fmt_hl("/files/{}".format(fid), capt)
+
def path_info_outline(self):
if self.sim is None and self.strfm is None:
self.add_info("No data loaded. Open PARTS.INI or SCRIPT.DAT first.")
@@ -1499,9 +1513,7 @@ class App(tkinter.Frame):
self.add_info("\n<b>Used resources</b>: {}\n".\
format(len(resused)))
for res_id in resused:
- self.add_info(" " + fmt_hl("/res/all/{}".format(res_id),
- "{}".format(res_id)) + " (0x{:X}) - {}\n".format(res_id,
- hlesc(self.sim.res[res_id])))
+ self.add_info(" " + self.fmt_hl_res(res_id, True) + "\n")
if len(dlgused) > 0:
self.add_info("\n<b>Used dialog groups</b>: {}\n".\
format(len(dlgused)))
@@ -2109,13 +2121,7 @@ class App(tkinter.Frame):
self.fmt_hl_obj_scene(obj_idx, True))))
self.add_info("\n")
return True
-
- def fmt_hl_file(self, fn, capt = None):
- fnl = fn.lower().replace("\\", "/")
- capt = capt or fn
- fid = urllib.parse.quote_plus(fnl)
- return "<a href=\"/files/{}\">{}</a>".format(fid, hlesc(capt))
-
+
def path_stores(self, path):
if self.strfm is None:
return self.path_default([])
@@ -2434,10 +2440,21 @@ class App(tkinter.Frame):
elif path[1] == "info":
self.clear_info()
self.add_info("<b>Saved state:</b>\n\n")
- self.add_info(" part: {}, chapter {}\n".format(
+ self.add_info(" part: {}, chapter {}\n".format(
self.save.part, self.save.chap))
- self.add_info(" stamp: " + hlesc(self.save.stamp) + "\n")
- self.add_info(" scene: " + hlesc(self.save.scene) + "\n")
+ self.add_info(" stamp: " + hlesc(self.save.stamp) + "\n")
+ self.add_info(" scene: " + hlesc(self.save.scene) + "\n")
+ self.add_info(" cursor: {} - {}\n".format(self.save.cursor,
+ petka.ACTIONS.get(self.save.cursor, ["ACT{:2X}".format(
+ self.save.cursor), 0])[0]))
+ self.add_info(" " + self.fmt_hl_res(self.save.cursor_res,
+ True) + "\n")
+ self.add_info(" char 1: {}, {} ".format(self.save.char1[0],
+ self.save.char1[1]) + self.fmt_hl_res(
+ self.save.char1[2], True) + "\n")
+ self.add_info(" char 2: {}, {} ".format(self.save.char2[0],
+ self.save.char2[1]) + self.fmt_hl_res(
+ self.save.char2[2], True) + "\n")
self.add_info(" invntr: {}\n".format(len(self.save.invntr)))
fmt = " " + fmt_dec(len(self.save.invntr)) + ") "
@@ -2460,17 +2477,11 @@ class App(tkinter.Frame):
if fndobj:
self.add_info(" " +
self.fmt_hl_obj_scene(fndobj.idx, True) + "\n")
-
self.add_info(" {}, {}, {}, {}, {}, {}, {}, {}, {}\n".
format(*obj["recs"]))
if obj["res"] in self.sim.res:
- res_id = obj["res"]
- self.add_info(" " + fmt_hl("/res/all/{}".
- format(res_id), "{}".format(res_id)) +
- " (0x{:X}) - {}\n".format(res_id,
- hlesc(self.sim.res[res_id])))
-
-
+ self.add_info(" " + self.fmt_hl_res(obj["res"],
+ True) + "\n")
else:
self.select_lb_item("info")
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index 775345ee1..7c2864ce2 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -1,7 +1,7 @@
class EngineError(Exception): pass
-from .engine import Engine, OPCODES, DLGOPS
+from .engine import Engine, OPCODES, DLGOPS, ACTIONS
from .fman import FileManager
from .imgbmp import BMPLoader
from .imgflc import FLCLoader
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 0f164244f..58c19d36e 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -80,6 +80,14 @@ DLGOPS = {
8: ("CIRCLE", 6),
}
+ACTIONS = {
+ 0: ("VIEW", 5002),
+ 1: ("GOTO", 5003),
+ 2: ("USE", 5004),
+ 3: ("TAKE", 5005),
+ 4: ("TALK", 5006),
+}
+
class ScrObject:
def __init__(self, idx, name):
self.idx = idx
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index ef70363bb..e9581db44 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -77,6 +77,21 @@ class SaveLoader:
self.scene = readstr()
print("Scene:", self.scene)
+ # char positions
+
data = f.read()
print(len(data))
+
+ items = struct.unpack("<{}I".format(len(data) // 4), data)
+ print(items[:20])
+
+ # cursor and res-num (-13 and -14)
+ self.cursor = items[-12]
+ self.cursor_res = items[-13]
+
+ # charters: x, y, res
+ self.char1 = (items[0], items[1], items[-10])
+ self.char2 = (items[2], items[3], items[-9])
+
+
Commit: d8b4720443567ac3926a0d415384c32613e95af4
https://github.com/scummvm/scummvm-tools/commit/d8b4720443567ac3926a0d415384c32613e95af4
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: saves: struct decoded
Changed paths:
engines/petka/petka/saves.py
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index e9581db44..8de59a583 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -25,7 +25,6 @@ class SaveLoader:
stamp = f.read(30)
stamp = stamp.split(b"\x00")[0]
self.stamp = stamp.decode(self.enc)
- print("Saved at", len(self.stamp), repr(self.stamp))
# read screenshot
sl = 108 * 81 * 2
@@ -35,18 +34,16 @@ class SaveLoader:
self.shot = BMPLoader()
self.shot.load_raw(108, 81, rgb)
- print("RGB beg", binascii.hexlify(rgb[:8]))
- print("RGB end", binascii.hexlify(rgb[-8:]))
-
hz2 = f.read(216)
if hz2 != b"\x00" * 216:
print("HZ2", hz2) # all zeroes?
raise EngineError("Bad SAVE error in HZ2 field")
- #print("HZ2", hz2) # all zeroes?
data = f.read(4)
hz3 = struct.unpack("<I", data)[0]
- print("HZ3", hz3)
+
+ if hz3 != objnum + 3:
+ raise EngineError("Bad SAVE objects number")
def readstr():
data = f.read(4)
@@ -55,7 +52,6 @@ class SaveLoader:
#print("STR", strlen, data, s)
return s.decode(self.enc)
- print("Req", objnum)
for i in range(objnum):
s1 = readstr()
s2 = readstr()
@@ -78,20 +74,22 @@ class SaveLoader:
print("Scene:", self.scene)
# char positions
+ data = f.read(16)
+ charpos = struct.unpack("<4I", data)
+ # arr hz5
+ data = f.read(4)
+ hz5len = struct.unpack("<I", data)[0]
+ hz5 = struct.unpack("<{}I".format(hz5len), f.read(hz5len * 4))
- data = f.read()
- print(len(data))
-
- items = struct.unpack("<{}I".format(len(data) // 4), data)
- print(items[:20])
-
- # cursor and res-num (-13 and -14)
- self.cursor = items[-12]
- self.cursor_res = items[-13]
+ data = f.read(52)
+ self.cursor_res, self.cursor, hz6, c1res, c2res, *hz = \
+ struct.unpack("<13I", data)
# charters: x, y, res
- self.char1 = (items[0], items[1], items[-10])
- self.char2 = (items[2], items[3], items[-9])
-
+ self.char1 = (charpos[0], charpos[1], c1res)
+ self.char2 = (charpos[2], charpos[3], c2res)
+
+ if f.read():
+ raise EngineError("Bad SAVE length (extra data)")
Commit: 34ad33b6b16ff6ce30b7c190cb4db966c8216756
https://github.com/scummvm/scummvm-tools/commit/34ad33b6b16ff6ce30b7c190cb4db966c8216756
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: saves display
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/saves.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 497721134..6ac863ef3 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -188,7 +188,6 @@ class App(tkinter.Frame):
self.curr_path = []
self.curr_help = ""
self.last_path = [None]
- self.last_fn = ""
self.curr_gui = []
self.curr_state = {} # local state for location group
self.curr_lb_acts = None
@@ -205,10 +204,12 @@ class App(tkinter.Frame):
def clear_data(self):
self.sim = None
+ self.last_fn = ""
# store manager
self.strfm = None
# save
self.save = None
+ self.last_savefn = ""
# translation
self.tran = None
@@ -2146,7 +2147,8 @@ class App(tkinter.Frame):
self.upd_toolgrp(self.curr_state["btnsort"], sm)
self.curr_state["btnext"].config(state = tkinter.DISABLED)
if stid is None:
- self.add_info("<b>Stores</b>\n\n")
+ self.add_info("<b>Store manager:</b> {}\n\n".format(
+ self.strfm.root))
fmt = " " + fmt_dec(len(self.strfm.strfd)) + \
") <a href=\"/strs/{}\">{}</a> (tag={})\n"
for idx, st in enumerate(self.strfm.strfd):
@@ -2439,7 +2441,8 @@ class App(tkinter.Frame):
self.update_canvas()
elif path[1] == "info":
self.clear_info()
- self.add_info("<b>Saved state:</b>\n\n")
+ self.add_info("<b>Saved state:</b> {}\n\n".format(
+ self.last_savefn))
self.add_info(" part: {}, chapter {}\n".format(
self.save.part, self.save.chap))
self.add_info(" stamp: " + hlesc(self.save.stamp) + "\n")
@@ -2482,6 +2485,18 @@ class App(tkinter.Frame):
if obj["res"] in self.sim.res:
self.add_info(" " + self.fmt_hl_res(obj["res"],
True) + "\n")
+ elif path[1] in ["arr5", "arr6"]:
+ self.clear_info()
+ if path[1] == "arr5":
+ arr = self.save.hz5
+ else:
+ arr = self.save.hz
+ self.add_info("<b>Array {}:</b> len={}\n\n".format(
+ path[1][3:], len(arr)))
+ fmt = " " + fmt_dec(len(arr)) + ") {}\n"
+ for idx, val in enumerate(arr):
+ self.add_info(fmt.format(idx + 1, hex(val)))
+
else:
self.select_lb_item("info")
@@ -2491,6 +2506,8 @@ class App(tkinter.Frame):
self.update_gui("Save")
self.insert_lb_act("Info", ["save"], "info")
self.insert_lb_act("Screenshot", ["save", "shot"], "shot")
+ self.insert_lb_act("Array 5", ["save", "arr5"], "arr5")
+ self.insert_lb_act("Array 6", ["save", "arr6"], "arr6")
upd_save()
return True
@@ -2615,15 +2632,15 @@ class App(tkinter.Frame):
if not self.strfm:
self.add_info("<i>not initialized</i>\n")
else:
- self.add_info("<i>works</i>\n\n")
- self.add_info(" <b>Path</b>: {}\n\n".format(
- hlesc(self.strfm.root)))
+ self.add_info("<i>works</i>\n")
+ self.add_info(" path: {}\n\n".format(hlesc(self.strfm.root)))
self.add_info("<b>Saved state</b>: ")
if not self.save:
self.add_info("<i>not loaded</i>\n\n")
else:
- self.add_info("<i>loaded</i>\n\n")
+ self.add_info("<i>loaded</i>\n")
+ self.add_info(" path: {}\n\n".format(hlesc(self.last_savefn)))
if self.sim or self.strfm:
self.path_info_outline()
@@ -2816,6 +2833,7 @@ class App(tkinter.Frame):
return
self.save = None
try:
+ self.last_savefn = fn
self.save = petka.SaveLoader("cp1251")
with open(fn, "rb") as f:
self.save.load_data(f, self.sim.curr_part,
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index 8de59a583..ebb5d547a 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -71,7 +71,6 @@ class SaveLoader:
# scene
self.scene = readstr()
- print("Scene:", self.scene)
# char positions
data = f.read(16)
@@ -80,10 +79,10 @@ class SaveLoader:
# arr hz5
data = f.read(4)
hz5len = struct.unpack("<I", data)[0]
- hz5 = struct.unpack("<{}I".format(hz5len), f.read(hz5len * 4))
+ self.hz5 = struct.unpack("<{}I".format(hz5len), f.read(hz5len * 4))
data = f.read(52)
- self.cursor_res, self.cursor, hz6, c1res, c2res, *hz = \
+ self.cursor_res, self.cursor, hz6, c1res, c2res, *self.hz = \
struct.unpack("<13I", data)
# charters: x, y, res
@@ -93,3 +92,5 @@ class SaveLoader:
if f.read():
raise EngineError("Bad SAVE length (extra data)")
+ print("HZ5", hz5len, hz5len / objnum, hz5len / hz3)
+
Commit: b266ee00dd795ddc518631f15fce0ede0ede26de
https://github.com/scummvm/scummvm-tools/commit/b266ee00dd795ddc518631f15fce0ede0ede26de
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fixes
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index e960e2f31..db02fb92c 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,6 +1,6 @@
ЧÑо нового
==========
-2014-12-27 веÑÑÐ¸Ñ 0.3g
+2014-12-29 веÑÑÐ¸Ñ 0.3g
----------------------
ÐÑпÑавлено оÑобÑажение в ÑпиÑке ÑÑаз (ÑообÑений)
ÐÐ¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ ÑпÑавоÑнÑе ÑÐ°Ð¹Ð»Ñ Ð¾ опкодаÑ
(обÑекÑов и диалогов)
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 6ac863ef3..0df00e928 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -31,7 +31,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3g 2014-12-27"
+VERSION = "v0.3g 2014-12-29"
def hlesc(value):
if value is None:
Commit: f5a459b9aea1d4b7bc138df619762a4a18bddff9
https://github.com/scummvm/scummvm-tools/commit/f5a459b9aea1d4b7bc138df619762a4a18bddff9
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix dislog opcodes info
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index db02fb92c..835da3a1c 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,9 @@
ЧÑо нового
==========
+2015-01-12 веÑÑÐ¸Ñ 0.3h
+----------------------
+ÐÑпÑавлено оÑобÑажение ÑпиÑка диалоговÑÑ
гÑÑпп где иÑполÑзÑеÑÑÑ ÑказаннÑй опкод
+ (оÑибка поÑвилаÑÑ Ð² 0.3g)
2014-12-29 веÑÑÐ¸Ñ 0.3g
----------------------
ÐÑпÑавлено оÑобÑажение в ÑпиÑке ÑÑаз (ÑообÑений)
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 0df00e928..046c9d869 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -31,7 +31,7 @@ except ImportError:
import petka
APPNAME = "P1&2 Explorer"
-VERSION = "v0.3g 2014-12-29"
+VERSION = "v0.3h 2015-01-12"
def hlesc(value):
if value is None:
@@ -2112,7 +2112,7 @@ class App(tkinter.Frame):
self.add_info("<i>Not used in dialogs</i>\n\n")
else:
self.add_info("<i>Used in dialogs</i>: {}\n".format(len(dls)))
- fmtdls = " " + fmt_dec(len(dacts)) + \
+ fmtdls = " " + fmt_dec(len(dls)) + \
") obj={}, group=<a href=\"/dlgs/{}\">{}" + \
"</a>, act={}, dlg={}, op={} {}\n"
for idx, (obj_idx, gidx, aidx, didx, oidx) in enumerate(dls):
Commit: 7f09c7ed2a4e31dedcf6566417a38f63649eb03c
https://github.com/scummvm/scummvm-tools/commit/7f09c7ed2a4e31dedcf6566417a38f63649eb03c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: saves almost decoded
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
engines/petka/petka/engine.py
engines/petka/petka/saves.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 835da3a1c..f679ca225 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -4,6 +4,8 @@
----------------------
ÐÑпÑавлено оÑобÑажение ÑпиÑка диалоговÑÑ
гÑÑпп где иÑполÑзÑеÑÑÑ ÑказаннÑй опкод
(оÑибка поÑвилаÑÑ Ð² 0.3g)
+ÐагÑÑзка ÑоÑ
Ñанений доÑабоÑана
+
2014-12-29 веÑÑÐ¸Ñ 0.3g
----------------------
ÐÑпÑавлено оÑобÑажение в ÑпиÑке ÑÑаз (ÑообÑений)
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 046c9d869..170284924 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -2452,6 +2452,11 @@ class App(tkinter.Frame):
self.save.cursor), 0])[0]))
self.add_info(" " + self.fmt_hl_res(self.save.cursor_res,
True) + "\n")
+ if self.save.cursor_obj == 0xffffffff:
+ self.add_info(" object: <i>none</i>\n")
+ else:
+ self.add_info(" object: " + self.fmt_hl_obj(
+ self.save.cursor_obj, True) + "\n")
self.add_info(" char 1: {}, {} ".format(self.save.char1[0],
self.save.char1[1]) + self.fmt_hl_res(
self.save.char1[2], True) + "\n")
@@ -2485,19 +2490,14 @@ class App(tkinter.Frame):
if obj["res"] in self.sim.res:
self.add_info(" " + self.fmt_hl_res(obj["res"],
True) + "\n")
- elif path[1] in ["arr5", "arr6"]:
+ elif path[1] == "dlgops":
self.clear_info()
- if path[1] == "arr5":
- arr = self.save.hz5
- else:
- arr = self.save.hz
- self.add_info("<b>Array {}:</b> len={}\n\n".format(
- path[1][3:], len(arr)))
- fmt = " " + fmt_dec(len(arr)) + ") {}\n"
- for idx, val in enumerate(arr):
- self.add_info(fmt.format(idx + 1, hex(val)))
-
-
+ self.add_info("<b>Dialog opcodes:</b> len = {} (0x{:x})\n\n".
+ format(len(self.save.dlgops), len(self.save.dlgops)))
+ fmt = " " + fmt_dec(len(self.save.dlgops)) + ") {} {:02x} " +\
+ "{:04x}\n"
+ for idx, (code, arg, ref) in enumerate(self.save.dlgops):
+ self.add_info(fmt.format(idx + 1, self.fmt_dlgop(code), arg, ref))
else:
self.select_lb_item("info")
@@ -2506,8 +2506,7 @@ class App(tkinter.Frame):
self.update_gui("Save")
self.insert_lb_act("Info", ["save"], "info")
self.insert_lb_act("Screenshot", ["save", "shot"], "shot")
- self.insert_lb_act("Array 5", ["save", "arr5"], "arr5")
- self.insert_lb_act("Array 6", ["save", "arr6"], "arr6")
+ self.insert_lb_act("Dialog opcodes", ["save", "dlgops"], "dlgops")
upd_save()
return True
@@ -2716,6 +2715,7 @@ class App(tkinter.Frame):
self.update_gui("Info")
self.insert_lb_act("Opcodes", ["info", "opcodes"], "opcodes")
self.insert_lb_act("Dialog opcodes", ["info", "dlgops"], "dlgops")
+ self.insert_lb_act("Actions", ["info", "acts"], "acts")
# change
name = None
if len(path) > 1:
@@ -2744,6 +2744,15 @@ class App(tkinter.Frame):
for key in k:
self.add_info(" {} (0x{:X}) - {}\n".format(key, key,
petka.DLGOPS[key][0]))
+ elif name == "acts":
+ self.add_info("<b>Actions<b>\n\n")
+ k = list(petka.ACTIONS.keys())
+ k.sort()
+ for key in k:
+ self.add_info(" {} (0x{:X}) - {}\n".format(key, key,
+ petka.ACTIONS[key][0]))
+ self.add_info(" " +
+ self.fmt_hl_res(petka.ACTIONS[key][1]) + "\n")
else:
self.add_info("Unknown data type \"{}\"\n".format(hlesc(name)))
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 58c19d36e..30c437bea 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -86,6 +86,9 @@ ACTIONS = {
2: ("USE", 5004),
3: ("TAKE", 5005),
4: ("TALK", 5006),
+ 5: ("CHAPAY", 5007),
+ 6: ("INVNTR", -1),
+
}
class ScrObject:
@@ -167,8 +170,8 @@ class Engine:
self.enc = enc
self.objects = []
self.scenes = []
- self.obj_idx = {}
- self.scn_idx = {}
+ self.obj_idx = {} # id -> object
+ self.scn_idx = {} # id -> scene
self.msgs = []
self.dlgs = []
self.dlg_idx = {}
@@ -590,7 +593,7 @@ class Engine:
num_ops = struct.unpack_from("<I", temp)[0]
for oidx, i in enumerate(range(num_ops)):
temp = f.read(4)
- ref, arg, code = struct.unpack_from("<HBB", temp)
+ ref, arg, code = struct.unpack_from("<HBB", temp)
dlgop = DlgOpObject(code, arg, ref)
dlgop.pos = oidx
if ref < len(self.msgs):
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index ebb5d547a..ec24a2e8f 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -36,7 +36,6 @@ class SaveLoader:
hz2 = f.read(216)
if hz2 != b"\x00" * 216:
- print("HZ2", hz2) # all zeroes?
raise EngineError("Bad SAVE error in HZ2 field")
data = f.read(4)
@@ -76,21 +75,28 @@ class SaveLoader:
data = f.read(16)
charpos = struct.unpack("<4I", data)
- # arr hz5
+ # arr dialog opcodes
data = f.read(4)
- hz5len = struct.unpack("<I", data)[0]
- self.hz5 = struct.unpack("<{}I".format(hz5len), f.read(hz5len * 4))
-
- data = f.read(52)
- self.cursor_res, self.cursor, hz6, c1res, c2res, *self.hz = \
- struct.unpack("<13I", data)
+ dlgoplen = struct.unpack("<I", data)[0]
+ self.dlgops = []
+ for _ in range(dlgoplen):
+ data = f.read(4)
+ ref, arg, code = struct.unpack_from("<HBB", data)
+ self.dlgops.append([code, arg, ref])
+ data = f.read(20)
+ self.cursor_res, self.cursor, self.cursor_obj, c1res, c2res = \
+ struct.unpack("<5I", data)
+
# charters: x, y, res
self.char1 = (charpos[0], charpos[1], c1res)
self.char2 = (charpos[2], charpos[3], c2res)
+ hz7 = f.read(32)
+ if hz7 != b"\xff" * 32:
+ raise EngineError("Bad SAVE error in HZ7 field")
+
if f.read():
raise EngineError("Bad SAVE length (extra data)")
- print("HZ5", hz5len, hz5len / objnum, hz5len / hz3)
Commit: 21155abca77555f34252da9913bfb7504cd9c63f
https://github.com/scummvm/scummvm-tools/commit/21155abca77555f34252da9913bfb7504cd9c63f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: saves loading in engine (wip)
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/engine.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 170284924..3185596cb 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -10,7 +10,6 @@ from idlelib.WidgetRedirector import WidgetRedirector
import traceback
import urllib.parse
import math
-import binascii
# Image processing
try:
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 30c437bea..82fbebcb5 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -113,6 +113,12 @@ class ScrOpObject:
self.op_arg2 = op_arg2
self.op_arg3 = op_arg3
+class ScrObjectState:
+ def __init__(self, obj):
+ self.obj = obj
+ self.state = 0
+ self.prop = [0] * 8
+
class MsgObject:
def __init__(self, idx, wav, arg1, arg2, arg3):
self.idx = idx
@@ -150,6 +156,7 @@ class DlgOpObject:
self.arg = arg # argument (ref, offset etc.)
self.ref = ref # message idx
self.msg = None # message
+ self.pos = None
class Engine:
def __init__(self):
@@ -286,6 +293,15 @@ class Engine:
# load dialogs
self.load_dialogs()
+ # current state
+ self.curr_scene = None
+ self.curr_obj = None
+ self.curr_dlg = None
+ self.curr_cursor = None
+ self.curr_char1 = None
+ self.curr_char2 = None
+ self.curr_invntr = None
+
def load_script(self, scrname = None, bkgname = None, resname = None):
self.objects = []
self.scenes = []
@@ -534,10 +550,10 @@ class Engine:
if f:
f.close()
+ # DIALOGUES.FIX
self.dlgs = []
self.dlg_idx = {}
self.dlgops = []
- # DIALOGUES.FIX
if fixname is None:
try:
f = self.fman.read_file_stream(self.curr_path + "dialogue.fix")
@@ -670,6 +686,37 @@ class Engine:
for op in self.dlgops:
f.write(struct.pack("<H2B", op.ref, op.arg, op.opcode))
- def load_save(self, ls):
+ def scene_to_id(self, name):
pass
+ # create current state from initial state
+ def init_game(self):
+ self.curr_scene = self.scene_to_id(self.start_scene)
+
+ self.curr_obj = []
+ for obj in self.objects + self.scenes:
+ state = ScrObjectState(obj)
+ self.curr_obj.append(state)
+ state.prop
+
+ self.curr_dlg = []
+ for dlgop in self.dlgops:
+ dlgstate = DlgOpObject(dlgop.code, dlgop.arg, dlgop.ref)
+ dlgstate.pos = dlgop.pos
+ self.curr_dlg.append(dlgstate)
+
+ self.curr_cursor = None
+ self.curr_char1 = None
+ self.curr_char2 = None
+ self.curr_invntr = []
+
+ def load_save(self, ls):
+ self.curr_scene = self.scene_to_id(ls.scene)
+
+ self.curr_obj = None
+ self.curr_dlg = None
+ self.curr_cursor = None
+ self.curr_char1 = None
+ self.curr_char2 = None
+ self.curr_invntr = None
+
Commit: 31cf5f81264876cf19fc358d8aea795b35a26931
https://github.com/scummvm/scummvm-tools/commit/31cf5f81264876cf19fc358d8aea795b35a26931
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix compiler: creating scenes with zero references to objects
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12script.py
engines/petka/petka/engine.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index f679ca225..c7f0fbd9e 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -5,6 +5,7 @@
ÐÑпÑавлено оÑобÑажение ÑпиÑка диалоговÑÑ
гÑÑпп где иÑполÑзÑеÑÑÑ ÑказаннÑй опкод
(оÑибка поÑвилаÑÑ Ð² 0.3g)
ÐагÑÑзка ÑоÑ
Ñанений доÑабоÑана
+ÐÑпÑавлено в компилÑÑоÑе Ñоздание ÑÑен Ñ Ð½ÑлевÑм колиÑеÑÑвом ÑÑÑлок на обÑекÑÑ
2014-12-29 веÑÑÐ¸Ñ 0.3g
----------------------
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
index 6ccdce86e..107e272c7 100755
--- a/engines/petka/p12script.py
+++ b/engines/petka/p12script.py
@@ -13,7 +13,7 @@ import petka
import petka.engine
APPNAME = "P1&2 Compiler and decompiler"
-VERSION = "v0.3 2014-06-01"
+VERSION = "v0.3h 2015-01-12"
class ScriptSyntaxError(Exception): pass
@@ -462,6 +462,7 @@ class P12Compiler:
num_bkg = 0
for citem in compscene:
scenerec = makerec(citem)
+ scenerec.refs = None
pe.scenes.append(scenerec)
if citem["ref"] is not None:
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index 82fbebcb5..afe725c62 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -355,6 +355,7 @@ class Engine:
for i in range(num_scn):
off, scn = read_rec(off)
+ scn.refs = None
self.scenes.append(scn)
self.scn_idx[scn.idx] = scn
Commit: 9f0f8c56ea550dfeca37ec234d467b85f9eafd7f
https://github.com/scummvm/scummvm-tools/commit/9f0f8c56ea550dfeca37ec234d467b85f9eafd7f
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: change save decoding
Changed paths:
engines/petka/p12explore.py
engines/petka/petka/saves.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3185596cb..f5f1828d4 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -2314,7 +2314,7 @@ class App(tkinter.Frame):
self.fmt_hl_msg(idx, True)))
grp = [
- [".leg", ".off", ".msk", ".flc"],
+ [".leg", ".off", ".msk", ".flc", ".ms2"],
[".bmp", ".cvx"]
]
sg = None
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index ec24a2e8f..2f5ebda0c 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -56,7 +56,7 @@ class SaveLoader:
s2 = readstr()
data = f.read(33)
obj = {"name": s1, "alias": s2, "data": data}
- recs = struct.unpack("<B8i", data)
+ recs = struct.unpack("<iB7i", data)
obj["recs"] = recs
obj["res"] = recs[2]
self.objects.append(obj)
Commit: 3219f4b1158a1b70560e6a5af0b806116c94500a
https://github.com/scummvm/scummvm-tools/commit/3219f4b1158a1b70560e6a5af0b806116c94500a
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: add interlinks for objetcs and dialog groups. allow open home sites
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index c7f0fbd9e..86f3b8009 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -6,6 +6,9 @@
(оÑибка поÑвилаÑÑ Ð² 0.3g)
ÐагÑÑзка ÑоÑ
Ñанений доÑабоÑана
ÐÑпÑавлено в компилÑÑоÑе Ñоздание ÑÑен Ñ Ð½ÑлевÑм колиÑеÑÑвом ÑÑÑлок на обÑекÑÑ
+ÐÐ¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ Ð¿ÐµÑеÑ
Ð¾Ð´Ñ Ð¸Ð· обÑекÑов к гÑÑппамм диалогов Ñ Ñаким же номеÑом, Ñак как
+ они ÑвÑзанÑ
+Ðазвание изменено на "Petka Explorer", Ð´Ð¾Ð±Ð°Ð²Ð»ÐµÐ½Ñ ÑÑÑлка на ÑайÑ
2014-12-29 веÑÑÐ¸Ñ 0.3g
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index f5f1828d4..ff5ed7589 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -10,6 +10,7 @@ from idlelib.WidgetRedirector import WidgetRedirector
import traceback
import urllib.parse
import math
+import webbrowser
# Image processing
try:
@@ -29,8 +30,10 @@ except ImportError:
import petka
-APPNAME = "P1&2 Explorer"
+APPNAME = "Petka Explorer"
VERSION = "v0.3h 2015-01-12"
+HOME_URLS = ["http://petka-vich.com/petkaexplorer/",
+ "https://bitbucket.org/romiq/p12simtran"]
def hlesc(value):
if value is None:
@@ -482,6 +485,13 @@ class App(tkinter.Frame):
path = path[:-1]
return path
+ def open_http(self, path):
+ if path not in HOME_URLS:
+ if not messagebox.askokcancel(parent = self, title = "Visit URL?",
+ message = "Would you like to open external URL:\n" + path +
+ " ?"): return
+ webbrowser.open(path)
+
def open_path(self, loc, withhist = True):
path = self.parse_path(loc)
if withhist:
@@ -738,6 +748,8 @@ class App(tkinter.Frame):
ref = ref[:-1]
def make_cb(path):
def cb():
+ if path[:5] == "http:" or path[:6] == "https:":
+ return self.open_http(path)
return self.open_path(path)
return cb
tags.append(self.text_hl.add(make_cb(ref)))
@@ -1466,6 +1478,9 @@ class App(tkinter.Frame):
resused = []
dlgused = []
+ # check group with same id
+ if rec.idx in self.sim.dlg_idx:
+ dlgused.append(rec.idx)
self.add_info("\n<b>Handlers</b>: {}\n".format(len(rec.acts)))
fmtra = " " + fmt_dec(len(rec.acts)) + \
") <u>on {}</u>, ops: {}{}\n"
@@ -1531,7 +1546,7 @@ class App(tkinter.Frame):
self.add_info(" " + self.fmt_hl_msg(msg.idx, True) + "\n")
oplst = {}
- # objects tan use this objects in TALK opcode
+ # objects can use this objects in TALK opcode
wasmsg = False
for obj2 in self.sim.objects + self.sim.scenes:
if obj2.idx == rec.idx: continue
@@ -1887,24 +1902,34 @@ class App(tkinter.Frame):
self.add_info(" {}{}{}{}\n".\
format(opcode, oparg, opref, cmt))
- def usedby(lst):
- for idx, rec in enumerate(lst):
+ def usedby(lst, hl):
+ hdr = False
+ for rec in lst:
+ if grp.idx == rec.idx:
+ # linked object woth same id
+ if not hdr:
+ self.add_info(hl)
+ hdr = True
+ self.add_info(" linked " +
+ self.fmt_hl_obj_scene(rec.idx, True) + "\n")
+ continue
ru = False
for act in rec.acts:
if ru: break
for op in act.ops:
if op.op_code == 0x11 and \
op.op_ref == grp.idx: # DIALOG
+ if not hdr:
+ self.add_info(hl)
+ hdr = True
self.add_info(" " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
ru = True
break
#print(op_id, op_code, op_res, op4, op5)
- self.add_info("\n\n<b>Used by objects</b>:\n")
- usedby(self.sim.objects)
- self.add_info("\n<b>Used by scenes</b>:\n")
- usedby(self.sim.scenes)
+ usedby(self.sim.objects, "\n<b>Used by objects</b>:\n")
+ usedby(self.sim.scenes, "\n<b>Used by scenes</b>:\n")
return True
def path_opcodes(self, path):
@@ -2584,10 +2609,12 @@ class App(tkinter.Frame):
self.update_gui("About")
self.insert_lb_act("Outline", [])
self.clear_info()
- self.add_info("Welcome to <b>Petka 1 & 2 resource explorer</b>\n\n")
- self.add_info(" " + APPNAME + " " + VERSION + "\n")
- self.add_info(" romiq.kh at gmail.com\n")
- self.add_info(" https://bitbucket.org/romiq/p12simtran\n")
+ self.add_info("Welcome to <b>Petka Explorer</b>\n")
+ self.add_info(" A resource explorer for Petka 1 and 2\n")
+ self.add_info(" " + APPNAME + " " + VERSION + ", ")
+ self.add_info("romiq.kh at gmail.com\n")
+ for u in HOME_URLS:
+ self.add_info(" " + fmt_hl(u, u) + "\n")
self.add_info("\n")
self.path_info_outline()
return True
Commit: 461afeebada4771267778a304528c4d03980a06c
https://github.com/scummvm/scummvm-tools/commit/461afeebada4771267778a304528c4d03980a06c
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: fix scenes with no referenced objects. add interlinks between objects and scenes
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 86f3b8009..66b240d52 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,10 @@
ЧÑо нового
==========
+2015-01-19 веÑÑÐ¸Ñ 0.3i
+----------------------
+ÐÑпÑавлено оÑобÑажение ÑÑен пÑи оÑÑÑÑÑÑвии ÑÑÑлок на обÑекÑÑ
+Ðобавлена инÑоÑмаÑÐ¸Ñ Ð¾ ÑвÑзанÑÑ
диалогаÑ
Ñ Ð¾Ð±ÑекÑов и наобоÑоÑ
+
2015-01-12 веÑÑÐ¸Ñ 0.3h
----------------------
ÐÑпÑавлено оÑобÑажение ÑпиÑка диалоговÑÑ
гÑÑпп где иÑполÑзÑеÑÑÑ ÑказаннÑй опкод
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index ff5ed7589..1b89b9ff8 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -31,7 +31,7 @@ except ImportError:
import petka
APPNAME = "Petka Explorer"
-VERSION = "v0.3h 2015-01-12"
+VERSION = "v0.3i 2015-01-19"
HOME_URLS = ["http://petka-vich.com/petkaexplorer/",
"https://bitbucket.org/romiq/p12simtran"]
@@ -1408,7 +1408,11 @@ class App(tkinter.Frame):
else:
# record info
self.add_info(("<b>Object</b>" if isobj \
- else "<b>Scene</b>") + ":\n")
+ else "<b>Scene</b>") + ":")
+ # check linked dialog
+ if rec.idx in self.sim.dlg_idx:
+ self.add_info(" (dialog " + self.fmt_hl_dlg(rec.idx) + ")")
+ self.add_info("\n")
self.add_info(" Index: {} (0x{:X})\n".format(rec.idx, rec.idx))
self.add_info(" Name: {}\n".format(hlesc(rec.name)))
if self.tran:
@@ -1455,26 +1459,29 @@ class App(tkinter.Frame):
self.fmt_hl_scene(scn.idx, True) + "\n")
break
else:
- if len(rec.refs) == 0:
+ if rec.refs is None:
self.add_info("\nNo references\n")
- else:
- self.add_info("\n<b>References</b>: {}\n".\
- format(len(rec.refs)))
- fmtd = " " + fmt_dec(len(rec.refs)) + ") "
- for idx, ref in enumerate(rec.refs):
- self.add_info(fmtd.format(idx) +
- self.fmt_hl_obj(ref[0].idx))
- msg = ""
- for arg in ref[1:]:
- msg += " "
- if arg < 10:
- msg += "{}".format(arg)
- elif arg == 0xffffffff:
- msg += "-1"
- else:
- msg += "0x{:X}".format(arg)
- self.add_info(msg + self.fmt_cmt(" // " + self.fmt_hl_obj(
- ref[0].idx, True)) + "\n")
+ else:
+ if len(rec.refs) == 0:
+ self.add_info("\nEmpty references\n")
+ else:
+ self.add_info("\n<b>References</b>: {}\n".\
+ format(len(rec.refs)))
+ fmtd = " " + fmt_dec(len(rec.refs)) + ") "
+ for idx, ref in enumerate(rec.refs):
+ self.add_info(fmtd.format(idx) +
+ self.fmt_hl_obj(ref[0].idx))
+ msg = ""
+ for arg in ref[1:]:
+ msg += " "
+ if arg < 10:
+ msg += "{}".format(arg)
+ elif arg == 0xffffffff:
+ msg += "-1"
+ else:
+ msg += "0x{:X}".format(arg)
+ self.add_info(msg + self.fmt_cmt(" // " +
+ self.fmt_hl_obj(ref[0].idx, True)) + "\n")
resused = []
dlgused = []
@@ -1802,8 +1809,11 @@ class App(tkinter.Frame):
self.add_info("Select <b>dialog group</b> from list\n")
else:
# grp info
- self.add_info("<b>Dialog group</b>: {} (0x{:X})\n".format(\
+ self.add_info("<b>Dialog group</b>: {} (0x{:X})".format(\
grp.idx, grp.idx))
+ if grp.idx in self.sim.obj_idx:
+ self.add_info(" (object " + self.fmt_hl_obj(grp.idx) + ")")
+ self.add_info("\n")
self.add_info(" arg1: {a} (0x{a:X})\n\n".format(a = grp.grp_arg1))
self.add_info("<b>Dialog handlers<b>: {}\n".format(len(grp.acts)))
fmtga = " " + fmt_dec(len(grp.acts)) + \
Commit: ba42c34aa5d0c7ffd08fbd5ceadc46189892f941
https://github.com/scummvm/scummvm-tools/commit/ba42c34aa5d0c7ffd08fbd5ceadc46189892f941
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Refactor GUI to separate file
Changed paths:
A engines/petka/tkguibrowser.py
engines/petka/p12explore.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 1b89b9ff8..67182b8df 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -1,26 +1,22 @@
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
-# romiq.kh at gmail.com, 2014
+# romiq.kh at gmail.com, 2015
import sys, os
import tkinter
-from tkinter import ttk, font, filedialog, messagebox
-from idlelib.WidgetRedirector import WidgetRedirector
+from tkinter import filedialog, messagebox
import traceback
-import urllib.parse
-import math
import webbrowser
+from tkguibrowser import TkBrowser, hlesc, cesc, fmt_hl, fmt_hl_len, fmt_arg, \
+ fmt_dec, fmt_dec_len
+
# Image processing
try:
from PIL import Image
except ImportError:
Image = None
-try:
- from PIL import ImageTk
-except ImportError:
- ImageTk = None
# Translations
try:
@@ -34,40 +30,6 @@ APPNAME = "Petka Explorer"
VERSION = "v0.3i 2015-01-19"
HOME_URLS = ["http://petka-vich.com/petkaexplorer/",
"https://bitbucket.org/romiq/p12simtran"]
-
-def hlesc(value):
- if value is None:
- return "None"
- return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
-
-def cesc(value):
- return value.replace("\\", "\\\\").replace("\"", "\\\"")
-
-def fmt_hl(loc, desc):
- return "<a href=\"{}\">{}</a>".format(loc, desc)
-
-def fmt_hl_len(loc, desc, ln):
- sz = max(ln - len(desc), 0)
- return " "*sz + fmt_hl(loc, desc)
-
-def fmt_arg(value):
- if value < 10:
- return "{}".format(value)
- elif value == 0xffff:
- return "-1"
- else:
- return "0x{:X}".format(value)
-
-def fmt_dec(value, add = 0):
- return "{{:{}}}".format(fmt_dec_len(value, add))
-
-def fmt_dec_len(value, add = 0):
- if value == 0:
- d = 1
- else:
- d = int(math.log10(value)) + 1
- d += add
- return d
def translit(text):
ru = "абвгдеÑзийклмнопÑÑÑÑÑÑ
ÑÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐРСТУФХЪЫЬÐ"
@@ -103,79 +65,13 @@ def translit(text):
ret = ret.upper()
return ret
-# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
-class HyperlinkManager:
- def __init__(self, text):
- self.text = text
- self.text.tag_config("hyper", foreground = "blue", underline = 1)
- self.text.tag_bind("hyper", "<Enter>", self._enter)
- self.text.tag_bind("hyper", "<Leave>", self._leave)
- self.text.tag_bind("hyper", "<Button-1>", self._click)
- bold_font = font.Font(text, self.text.cget("font"))
- bold_font.configure(weight = "bold")
- self.text.tag_config("bold", font = bold_font)
- italic_font = font.Font(text, self.text.cget("font"))
- italic_font.configure(slant = "italic")
- self.text.tag_config("italic", font = italic_font)
- self.text.tag_config("underline", underline = 1)
- self.reset()
-
- def reset(self):
- self.links = {}
- self.colors = []
- self.bgs = []
-
- def add(self, action):
- # add an action to the manager. returns tags to use in
- # associated text widget
- tag = "hyper-{}".format(len(self.links))
- self.links[tag] = action
- return "hyper", tag
-
- def color(self, color):
- tag = "color-{}".format(color)
- if tag not in self.colors:
- self.colors.append(tag)
- self.text.tag_config(tag, foreground = color)
- self.text.tag_raise("hyper")
- return (tag,)
-
- def bg(self, color):
- tag = "bg-{}".format(color)
- if tag not in self.bgs:
- self.bgs.append(tag)
- self.text.tag_config(tag, background = color)
- self.text.tag_raise("hyper")
- return (tag,)
-
- def _enter(self, event):
- self.text.config(cursor = "hand2")
-
- def _leave(self, event):
- self.text.config(cursor = "")
-
- def _click(self, event):
- for tag in self.text.tag_names(tkinter.CURRENT):
- if tag[:6] == "hyper-":
- self.links[tag]()
- return
-# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
-class ReadOnlyText(tkinter.Text):
- def __init__(self, *args, **kwargs):
- tkinter.Text.__init__(self, *args, **kwargs)
- self.redirector = WidgetRedirector(self)
- self.insert = \
- self.redirector.register("insert", lambda *args, **kw: "break")
- self.delete = \
- self.redirector.register("delete", lambda *args, **kw: "break")
-
-class App(tkinter.Frame):
+class App(TkBrowser):
def __init__(self, master):
- tkinter.Frame.__init__(self, master)
- master.title(APPNAME)
- self.pack(fill = tkinter.BOTH, expand = 1)
- self.pad = None
+ super().__init__(master)
+
+ def init_gui(self):
+ self.master.title(APPNAME)
self.clear_data()
# path
if hasattr(sys, 'frozen'):
@@ -183,27 +79,7 @@ class App(tkinter.Frame):
else:
self.app_path = __file__
self.app_path = os.path.abspath(os.path.dirname(self.app_path))
- self.start_act = []
- # gui
- self.path_handler = {}
- self.curr_main = -1 # 0 - frame, 1 - canvas
- self.curr_path = []
- self.curr_help = ""
- self.last_path = [None]
- self.curr_gui = []
- self.curr_state = {} # local state for location group
- self.curr_lb_acts = None
- self.curr_lb_idx = None
- self.hist = []
- self.histf = []
- self.gl_state = {} # global state until program exit
- # canvas
- self.need_update = False
- self.canv_view_fact = 1
- self.main_image = tkinter.PhotoImage(width = 1, height = 1)
- # add on_load handler
- self.after_idle(self.on_first_display)
-
+
def clear_data(self):
self.sim = None
self.last_fn = ""
@@ -216,70 +92,7 @@ class App(tkinter.Frame):
self.tran = None
def create_widgets(self):
- ttk.Style().configure("Tool.TButton", width = -1) # minimal width
- ttk.Style().configure("TLabel", padding = self.pad)
- ttk.Style().configure('Info.TFrame', background = 'white', \
- foreground = "black")
-
- # toolbar
- self.toolbar = ttk.Frame(self)
- self.toolbar.pack(fill = tkinter.BOTH)
- btns = [
- ["Outline", lambda: self.open_path("")],
- ["Help", self.on_help],
- [None, None],
- ["<-", self.on_back],
- ["->", self.on_forward],
- ]
- for text, cmd in btns:
- if text is None:
- frm = ttk.Frame(self.toolbar, width = self.pad,
- height = self.pad)
- frm.pack(side = tkinter.LEFT)
- continue
- btn = ttk.Button(self.toolbar, text = text, \
- style = "Tool.TButton", command = cmd)
- btn.pack(side = tkinter.LEFT)
- frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
- frm.pack(side = tkinter.LEFT)
-
- # main panel
- self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
- self.pan_main.pack(fill = tkinter.BOTH, expand = 1)
-
- # leftpanel
- self.frm_left = ttk.Frame(self.pan_main)
- self.pan_main.add(self.frm_left)
- # main view
- self.frm_view = ttk.Frame(self.pan_main)
- self.pan_main.add(self.frm_view)
- self.frm_view.grid_rowconfigure(0, weight = 1)
- self.frm_view.grid_columnconfigure(0, weight = 1)
- self.scr_view_x = ttk.Scrollbar(self.frm_view,
- orient = tkinter.HORIZONTAL)
- self.scr_view_x.grid(row = 1, column = 0, \
- sticky = tkinter.E + tkinter.W)
- self.scr_view_y = ttk.Scrollbar(self.frm_view)
- self.scr_view_y.grid(row = 0, column = 1, sticky = \
- tkinter.N + tkinter.S)
- # canvas
- self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
- bd = 0, highlightthickness = 0,
- scrollregion = (0, 0, 50, 50),
- )
- # don't forget
- # canvas.config(scrollregion=(left, top, right, bottom))
- self.canv_view.bind('<Configure>', self.on_resize_view)
- self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
-
- # text
- self.text_view = ReadOnlyText(self.frm_view,
- highlightthickness = 0,
- )
- self.text_hl = HyperlinkManager(self.text_view)
- self.text_view.bind('<Configure>', self.on_resize_view)
-
-
+ super().create_widgets()
def desc_def(aname, name, lst = {}):
def desc(path):
if len(path) > 1:
@@ -288,7 +101,6 @@ class App(tkinter.Frame):
else:
return aname
return desc
-
# bind path handlers
self.path_handler["parts"] = [self.path_parts, self.desc_parts]
self.path_handler["res"] = [self.path_res, self.desc_res]
@@ -353,8 +165,10 @@ class App(tkinter.Frame):
break
if repath:
self.open_path(repath)
+
def create_menu(self):
+ super().create_menu()
def mkmenupaths(parent, items):
for n in items:
if n is None:
@@ -365,10 +179,6 @@ class App(tkinter.Frame):
parent.add_command(
command = cmd(n),
label = self.desc_path(n))
-
- self.menubar = tkinter.Menu(self.master)
- self.master.configure(menu = self.menubar)
-
self.menufile = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menufile,
label = "File")
@@ -440,431 +250,6 @@ class App(tkinter.Frame):
helpnav = ["/help/index", None, "/support", "/info", "/about"]
mkmenupaths(self.menuhelp, helpnav)
- def update_after(self):
- if not self.need_update:
- self.after_idle(self.on_idle)
- self.need_update = True
-
- def on_idle(self):
- self.need_update = False
- self.update_canvas()
-
- def on_first_display(self):
- fnt = font.Font()
- try:
- self.pad = fnt.measure(":")
- except:
- self.pad = 5
- self.create_widgets()
- self.create_menu()
-
- def on_exit(self):
- self.master.destroy()
-
- def on_mouse_view(self, event):
- self.update_after()
-
- def on_resize_view(self, event):
- self.update_after()
-
- def parse_path(self, loc):
- if isinstance(loc, str):
- path = []
- if loc[:1] == "/":
- loc = loc[1:]
- if loc != "":
- for item in loc.split("/"):
- try:
- path.append(int(item, 10))
- except:
- path.append(item)
- else:
- path = loc
- path = tuple(path)
- while path[-1:] == ("",):
- path = path[:-1]
- return path
-
- def open_http(self, path):
- if path not in HOME_URLS:
- if not messagebox.askokcancel(parent = self, title = "Visit URL?",
- message = "Would you like to open external URL:\n" + path +
- " ?"): return
- webbrowser.open(path)
-
- def open_path(self, loc, withhist = True):
- path = self.parse_path(loc)
- if withhist:
- self.hist.append([path])
- self.histf = []
- print("DEBUG: Open", path)
- # set title
- capt = APPNAME
- try:
- if path == ("about",):
- capt = APPNAME + " - " + VERSION
- else:
- capt = APPNAME + " - " + self.desc_path(path)
- except:
- pass
- self.master.title(capt)
- self.curr_path = path
- if len(path) > 0:
- self.curr_help = path[0]
- else:
- self.curr_help = ""
- if len(path) > 0:
- if path[0] in self.path_handler:
- return self.path_handler[path[0]][0](path)
- return self.path_default(path)
-
- def desc_path(self, loc):
- path = self.parse_path(loc)
- if len(path) > 0:
- if path[0] in self.path_handler:
- desc = self.path_handler[path[0]][1]
- if callable(desc):
- return desc(path)
- elif desc:
- return desc
- return self.desc_default(path)
-
- def update_canvas(self):
- if self.curr_main == 0:
- return
- # draw grahics
- c = self.canv_view
- c.delete(tkinter.ALL)
- if self.sim is None: return
-
- w = self.canv_view.winfo_width()
- h = self.canv_view.winfo_height()
- if (w == 0) or (h == 0):
- return
-
- scale = 0
-
- # Preview image
- if not isinstance(self.main_image, tkinter.PhotoImage):
- mw, mh = self.main_image.size
- if scale == 0: # Fit
- try:
- psc = w / h
- isc = mw / mh
- if psc < isc:
- fact = w / mw
- else:
- fact = h / mh
- except:
- fact = 1.0
- else:
- fact = scale
- pw = int(mw * fact)
- ph = int(mh * fact)
- img = self.main_image.resize((pw, ph), Image.ANTIALIAS)
- self.canv_image = ImageTk.PhotoImage(img)
- else:
- mw = self.main_image.width()
- mh = self.main_image.height()
- if scale == 0: # Fit
- try:
- psc = w / h
- isc = mw / mh
- if psc < isc:
- if w > mw:
- fact = w // mw
- else:
- fact = -mw // w
- else:
- if h > mh:
- fact = h // mh
- else:
- fact = -mh // h
- except:
- fact = 1
- else:
- fact = scale
- self.canv_image = self.main_image.copy()
- if fact > 0:
- self.canv_image = self.canv_image.zoom(fact)
- else:
- self.canv_image = self.canv_image.subsample(-fact)
- self.canv_image_fact = fact
-
- # place on canvas
- if fact > 0:
- pw = mw * fact
- ph = mh * fact
- else:
- pw = mw // -fact
- ph = mh // -fact
-
- cw = max(pw, w)
- ch = max(ph, h)
- c.config(scrollregion = (0, 0, cw - 2, ch - 2))
- #print("Place c %d %d, p %d %d" % (cw, ch, w, h))
- c.create_image(cw // 2, ch // 2, image = self.canv_image)
-
- def make_image(self, imgobj):
- if imgobj.image is not None:
- return imgobj.image
- width = imgobj.width
- height = imgobj.height
- data = imgobj.rgb
- # create P6
- phdr = ("P6\n{} {}\n255\n".format(width, height))
- rawlen = width * height * 3 # RGB
- #phdr = ("P5\n{} {}\n255\n".format(width, height))
- #rawlen = width * height
- phdr = phdr.encode("UTF-8")
-
- if len(data) > rawlen:
- # truncate
- pdata = data[:rawlen]
- if len(data) < rawlen:
- # fill gap
- gap = bytearray()
- data += b"\xff" * (rawlen - len(data))
- p = bytearray(phdr)
- # fix UTF-8 issue
- for ch in data:
- if ch > 0x7f:
- p += bytes((0b11000000 |\
- ch >> 6, 0b10000000 |\
- (ch & 0b00111111)))
- else:
- p += bytes((ch,))
- image = tkinter.PhotoImage(width = width, height = height, \
- data = bytes(p))
- return image
-
- def update_gui(self, text = "<Undefined>"):
- self.last_path = self.curr_path
- # cleanup
- for item in self.curr_gui:
- item()
- self.curr_gui = []
- self.curr_state = {} # save state across moves
- # left listbox
- lab = tkinter.Label(self.frm_left, text = text)
- lab.pack()
- frm_lb = ttk.Frame(self.frm_left)
- frm_lb.pack(fill = tkinter.BOTH, expand = 1)
- frm_lb.grid_rowconfigure(0, weight = 1)
- frm_lb.grid_columnconfigure(0, weight = 1)
- scr_lb_x = ttk.Scrollbar(frm_lb, orient = tkinter.HORIZONTAL)
- scr_lb_x.grid(row = 1, column = 0, sticky = tkinter.E + tkinter.W)
- scr_lb_y = ttk.Scrollbar(frm_lb)
- scr_lb_y.grid(row = 0, column = 1, sticky = tkinter.N + tkinter.S)
- frmlbpad = ttk.Frame(frm_lb, borderwidth = self.pad)
- lb = tkinter.Listbox(frm_lb,
- highlightthickness = 0,
- xscrollcommand = scr_lb_x.set,
- yscrollcommand = scr_lb_y.set)
- lb.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
- scr_lb_x.config(command = lb.xview)
- scr_lb_y.config(command = lb.yview)
- self.curr_gui.append(lambda:lb.grid_remove())
- self.curr_gui.append(lambda:lab.pack_forget())
- self.curr_gui.append(lambda:frm_lb.pack_forget())
- lb.bind("<Double-Button-1>", self.on_left_listbox)
- lb.bind("<Return>", self.on_left_listbox)
- # actions on listbox
- self.curr_lb = lb
- self.curr_lb_acts = []
- self.curr_lb_idx = {}
-
- def switch_view(self, main):
- # main view
- if main == self.curr_main: return
- last = self.curr_main
- self.curr_main = main
- rw = None
- rh = None
- if main == 0:
- self.canv_view.delete(tkinter.ALL)
- self.canv_view.grid_forget()
- self.text_view.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
- self.text_view.configure(
- xscrollcommand = self.scr_view_x.set,
- yscrollcommand = self.scr_view_y.set
- )
- self.scr_view_x.config(command = self.text_view.xview)
- self.scr_view_y.config(command = self.text_view.yview)
- else:
-
- if last == 0:
- rw = self.text_view.winfo_width()
- rh = self.text_view.winfo_height()
- self.canv_view.delete(tkinter.ALL)
- self.text_view.grid_forget()
- self.canv_view.grid(row = 0, column = 0, \
- sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
- self.canv_view.configure(
- xscrollcommand = self.scr_view_x.set,
- yscrollcommand = self.scr_view_y.set
- )
- self.scr_view_x.config(command = self.canv_view.xview)
- self.scr_view_y.config(command = self.canv_view.yview)
- if rh:
- print(rh)
- self.canv_view.height = rh
- print(self.canv_view.winfo_height())
-
- def clear_info(self):
- self.text_view.delete(0.0, tkinter.END)
-
- def add_info(self, text):
- mode = 0 # 0 - normal, 1 - tag
- curr_tag = None
- curr_text = ""
- tags = []
- esc = False
- for ch in text:
- if mode == 0:
- if esc:
- curr_text += ch
- esc = False
- else:
- if ch == "\\":
- esc = True
- elif ch == "<":
- mode = 1
- curr_tag = ""
- else:
- curr_text += ch
- else:
- if ch == ">":
- if len(curr_text) > 0:
- self.text_view.insert(tkinter.INSERT, curr_text, \
- tuple(reversed([x for x in tags for x in x])))
- if curr_tag[:7] == "a href=":
- ref = curr_tag[7:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- def make_cb(path):
- def cb():
- if path[:5] == "http:" or path[:6] == "https:":
- return self.open_http(path)
- return self.open_path(path)
- return cb
- tags.append(self.text_hl.add(make_cb(ref)))
- elif curr_tag[:11] == "font color=":
- ref = curr_tag[11:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.text_hl.color(ref))
- elif curr_tag[:8] == "font bg=":
- ref = curr_tag[8:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.text_hl.bg(ref))
- elif curr_tag == "b":
- tags.append(["bold"])
- elif curr_tag == "i":
- tags.append(["italic"])
- elif curr_tag == "u":
- tags.append(["underline"])
- elif curr_tag[:1] == "/":
- tags = tags[:-1]
- curr_text = ""
- mode = 0
- else:
- curr_tag += ch
- if len(curr_text) > 0:
- self.text_view.insert(tkinter.INSERT, curr_text, \
- tuple(reversed([x for x in tags for x in x])))
-
- def insert_lb_act(self, name, act, key = None):
- if key is not None:
- self.curr_lb_idx[key] = len(self.curr_lb_acts)
- self.curr_lb_acts.append((name, act))
- if name == "-" and act is None:
- self.curr_lb.insert(tkinter.END, "")
- else:
- self.curr_lb.insert(tkinter.END, " " + name)
-
- def select_lb_item(self, key):
- idx = self.curr_lb_idx.get(key, None)
- need = (idx is not None)
- idxs = "{}".format(idx)
- for sel in self.curr_lb.curselection():
- if sel == idxs:
- need = False
- else:
- self.curr_lb.selection_clear(sel)
- if need:
- self.curr_lb.selection_set(idxs)
- if idx is not None:
- self.curr_lb.see(idxs)
-
- def on_left_listbox(self, event):
- def currsel():
- try:
- num = self.curr_lb.curselection()[0]
- num = int(num)
- except:
- return None
- return num
-
- if self.curr_lb_acts:
- act = self.curr_lb_acts[currsel()]
- if act[1] is not None:
- self.open_path(act[1])
-
- def add_toolbtn(self, text, cmd):
- if text is None:
- frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
- frm.pack(side = tkinter.LEFT)
- self.curr_gui.append(lambda:frm.pack_forget())
- return
- btn = ttk.Button(self.toolbar, text = text, \
- style = "Tool.TButton", command = cmd)
- btn.pack(side = tkinter.LEFT)
- self.curr_gui.append(lambda:btn.pack_forget())
- return btn
-
- def add_toollabel(self, text):
- lab = ttk.Label(self.toolbar, text = text)
- lab.pack(side = tkinter.LEFT)
- self.curr_gui.append(lambda:lab.pack_forget())
- return lab
-
- def add_toolgrp(self, label, glkey, items, cbupd):
- def makecb(v, g):
- def btncb():
- self.gl_state[g] = v
- cbupd()
- return btncb
- if label:
- self.add_toollabel(label)
- kl = list(items.keys())
- kl.sort()
- res = []
- for k in kl:
- b = self.add_toolbtn(items[k], makecb(k, glkey))
- res.append([b, k])
- return res
-
- def upd_toolgrp(self, btns, state):
- for btn, idx in btns:
- if idx != state and state != -1:
- btn.config(state = tkinter.NORMAL)
- else:
- btn.config(state = tkinter.DISABLED)
-
-
- def clear_hist(self):
- self.hist = self.hist[-1:]
- self.histf = []
def on_help(self):
self.open_path(["help", self.curr_help])
@@ -883,6 +268,21 @@ class App(tkinter.Frame):
self.hist.append(np)
self.open_path(np[0], False)
+ def open_path(self, loc, withhist = True):
+ res = super().open_path(loc, withhist)
+ # set title
+ capt = APPNAME
+ try:
+ if path == ("about",):
+ capt = APPNAME + " - " + VERSION
+ else:
+ capt = APPNAME + " - " + self.desc_path(path)
+ except:
+ pass
+ self.master.title(capt)
+ return res
+
+
def _t(self, value, tp):
if not self.tran: return value
if tp in self.tran:
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
new file mode 100644
index 000000000..675d8df2c
--- /dev/null
+++ b/engines/petka/tkguibrowser.py
@@ -0,0 +1,634 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2015
+
+import math
+import urllib.parse
+
+import tkinter
+from tkinter import ttk, font, filedialog, messagebox
+from idlelib.WidgetRedirector import WidgetRedirector
+
+try:
+ from PIL import ImageTk
+except ImportError:
+ ImageTk = None
+
+def hlesc(value):
+ if value is None:
+ return "None"
+ return value.replace("\\", "\\\\").replace("<", "\\<").replace(">", "\\>")
+
+def cesc(value):
+ return value.replace("\\", "\\\\").replace("\"", "\\\"")
+
+def fmt_hl(loc, desc):
+ return "<a href=\"{}\">{}</a>".format(loc, desc)
+
+def fmt_hl_len(loc, desc, ln):
+ sz = max(ln - len(desc), 0)
+ return " "*sz + fmt_hl(loc, desc)
+
+def fmt_arg(value):
+ if value < 10:
+ return "{}".format(value)
+ elif value == 0xffff:
+ return "-1"
+ else:
+ return "0x{:X}".format(value)
+
+def fmt_dec(value, add = 0):
+ return "{{:{}}}".format(fmt_dec_len(value, add))
+
+def fmt_dec_len(value, add = 0):
+ if value == 0:
+ d = 1
+ else:
+ d = int(math.log10(value)) + 1
+ d += add
+ return d
+
+# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
+class HyperlinkManager:
+ def __init__(self, text):
+ self.text = text
+ self.text.tag_config("hyper", foreground = "blue", underline = 1)
+ self.text.tag_bind("hyper", "<Enter>", self._enter)
+ self.text.tag_bind("hyper", "<Leave>", self._leave)
+ self.text.tag_bind("hyper", "<Button-1>", self._click)
+ bold_font = font.Font(text, self.text.cget("font"))
+ bold_font.configure(weight = "bold")
+ self.text.tag_config("bold", font = bold_font)
+ italic_font = font.Font(text, self.text.cget("font"))
+ italic_font.configure(slant = "italic")
+ self.text.tag_config("italic", font = italic_font)
+ self.text.tag_config("underline", underline = 1)
+ self.reset()
+
+ def reset(self):
+ self.links = {}
+ self.colors = []
+ self.bgs = []
+
+ def add(self, action):
+ # add an action to the manager. returns tags to use in
+ # associated text widget
+ tag = "hyper-{}".format(len(self.links))
+ self.links[tag] = action
+ return "hyper", tag
+
+ def color(self, color):
+ tag = "color-{}".format(color)
+ if tag not in self.colors:
+ self.colors.append(tag)
+ self.text.tag_config(tag, foreground = color)
+ self.text.tag_raise("hyper")
+ return (tag,)
+
+ def bg(self, color):
+ tag = "bg-{}".format(color)
+ if tag not in self.bgs:
+ self.bgs.append(tag)
+ self.text.tag_config(tag, background = color)
+ self.text.tag_raise("hyper")
+ return (tag,)
+
+ def _enter(self, event):
+ self.text.config(cursor = "hand2")
+
+ def _leave(self, event):
+ self.text.config(cursor = "")
+
+ def _click(self, event):
+ for tag in self.text.tag_names(tkinter.CURRENT):
+ if tag[:6] == "hyper-":
+ self.links[tag]()
+ return
+
+# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
+class ReadOnlyText(tkinter.Text):
+ def __init__(self, *args, **kwargs):
+ tkinter.Text.__init__(self, *args, **kwargs)
+ self.redirector = WidgetRedirector(self)
+ self.insert = \
+ self.redirector.register("insert", lambda *args, **kw: "break")
+ self.delete = \
+ self.redirector.register("delete", lambda *args, **kw: "break")
+
+class TkBrowser(tkinter.Frame):
+ def __init__(self, master):
+ tkinter.Frame.__init__(self, master)
+ self.pack(fill = tkinter.BOTH, expand = 1)
+ self.pad = None
+
+ # gui
+ self.path_handler = {}
+ self.curr_main = -1 # 0 - frame, 1 - canvas
+ self.curr_path = []
+ self.curr_help = ""
+ self.last_path = [None]
+ self.curr_gui = []
+ self.curr_state = {} # local state for location group
+ self.curr_lb_acts = None
+ self.curr_lb_idx = None
+ self.hist = []
+ self.histf = []
+ self.gl_state = {} # global state until program exit
+ self.start_act = []
+ self.init_gui() # init custom gui data
+
+ # canvas
+ self.need_update = False
+ self.canv_view_fact = 1
+ self.main_image = tkinter.PhotoImage(width = 1, height = 1)
+ # add on_load handler
+ self.after_idle(self.on_first_display)
+
+ def init_gui(self):
+ pass
+
+ def update_after(self):
+ if not self.need_update:
+ self.after_idle(self.on_idle)
+ self.need_update = True
+
+ def on_idle(self):
+ self.need_update = False
+ self.update_canvas()
+
+ def on_first_display(self):
+ fnt = font.Font()
+ try:
+ self.pad = fnt.measure(":")
+ except:
+ self.pad = 5
+ self.create_widgets()
+ self.create_menu()
+
+ def create_widgets(self):
+ ttk.Style().configure("Tool.TButton", width = -1) # minimal width
+ ttk.Style().configure("TLabel", padding = self.pad)
+ ttk.Style().configure('Info.TFrame', background = 'white', \
+ foreground = "black")
+
+ # toolbar
+ self.toolbar = ttk.Frame(self)
+ self.toolbar.pack(fill = tkinter.BOTH)
+ btns = [
+ ["Outline", lambda: self.open_path("")],
+ ["Help", self.on_help],
+ [None, None],
+ ["<-", self.on_back],
+ ["->", self.on_forward],
+ ]
+ for text, cmd in btns:
+ if text is None:
+ frm = ttk.Frame(self.toolbar, width = self.pad,
+ height = self.pad)
+ frm.pack(side = tkinter.LEFT)
+ continue
+ btn = ttk.Button(self.toolbar, text = text, \
+ style = "Tool.TButton", command = cmd)
+ btn.pack(side = tkinter.LEFT)
+ frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
+ frm.pack(side = tkinter.LEFT)
+
+ # main panel
+ self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
+ self.pan_main.pack(fill = tkinter.BOTH, expand = 1)
+
+ # leftpanel
+ self.frm_left = ttk.Frame(self.pan_main)
+ self.pan_main.add(self.frm_left)
+ # main view
+ self.frm_view = ttk.Frame(self.pan_main)
+ self.pan_main.add(self.frm_view)
+ self.frm_view.grid_rowconfigure(0, weight = 1)
+ self.frm_view.grid_columnconfigure(0, weight = 1)
+ self.scr_view_x = ttk.Scrollbar(self.frm_view,
+ orient = tkinter.HORIZONTAL)
+ self.scr_view_x.grid(row = 1, column = 0, \
+ sticky = tkinter.E + tkinter.W)
+ self.scr_view_y = ttk.Scrollbar(self.frm_view)
+ self.scr_view_y.grid(row = 0, column = 1, sticky = \
+ tkinter.N + tkinter.S)
+ # canvas
+ self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
+ bd = 0, highlightthickness = 0,
+ scrollregion = (0, 0, 50, 50),
+ )
+ # don't forget
+ # canvas.config(scrollregion=(left, top, right, bottom))
+ self.canv_view.bind('<Configure>', self.on_resize_view)
+ self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
+
+ # text
+ self.text_view = ReadOnlyText(self.frm_view,
+ highlightthickness = 0,
+ )
+ self.text_hl = HyperlinkManager(self.text_view)
+ self.text_view.bind('<Configure>', self.on_resize_view)
+
+ def create_menu(self):
+ self.menubar = tkinter.Menu(self.master)
+ self.master.configure(menu = self.menubar)
+
+ def on_exit(self):
+ self.master.destroy()
+
+ def on_mouse_view(self, event):
+ self.update_after()
+
+ def on_resize_view(self, event):
+ self.update_after()
+
+ def parse_path(self, loc):
+ if isinstance(loc, str):
+ path = []
+ if loc[:1] == "/":
+ loc = loc[1:]
+ if loc != "":
+ for item in loc.split("/"):
+ try:
+ path.append(int(item, 10))
+ except:
+ path.append(item)
+ else:
+ path = loc
+ path = tuple(path)
+ while path[-1:] == ("",):
+ path = path[:-1]
+ return path
+
+ def open_http(self, path):
+ if path not in HOME_URLS:
+ if not messagebox.askokcancel(parent = self, title = "Visit URL?",
+ message = "Would you like to open external URL:\n" + path +
+ " ?"): return
+ webbrowser.open(path)
+
+ def open_path(self, loc, withhist = True):
+ path = self.parse_path(loc)
+ if withhist:
+ self.hist.append([path])
+ self.histf = []
+ print("DEBUG: Open", path)
+ self.curr_path = path
+ if len(path) > 0:
+ self.curr_help = path[0]
+ else:
+ self.curr_help = ""
+ if len(path) > 0:
+ if path[0] in self.path_handler:
+ return self.path_handler[path[0]][0](path)
+ return self.path_default(path)
+
+ def desc_path(self, loc):
+ path = self.parse_path(loc)
+ if len(path) > 0:
+ if path[0] in self.path_handler:
+ desc = self.path_handler[path[0]][1]
+ if callable(desc):
+ return desc(path)
+ elif desc:
+ return desc
+ return self.desc_default(path)
+
+ def update_canvas(self):
+ if self.curr_main == 0:
+ return
+ # draw grahics
+ c = self.canv_view
+ c.delete(tkinter.ALL)
+ if self.sim is None: return
+
+ w = self.canv_view.winfo_width()
+ h = self.canv_view.winfo_height()
+ if (w == 0) or (h == 0):
+ return
+
+ scale = 0
+
+ # Preview image
+ if not isinstance(self.main_image, tkinter.PhotoImage):
+ mw, mh = self.main_image.size
+ if scale == 0: # Fit
+ try:
+ psc = w / h
+ isc = mw / mh
+ if psc < isc:
+ fact = w / mw
+ else:
+ fact = h / mh
+ except:
+ fact = 1.0
+ else:
+ fact = scale
+ pw = int(mw * fact)
+ ph = int(mh * fact)
+ img = self.main_image.resize((pw, ph), Image.ANTIALIAS)
+ self.canv_image = ImageTk.PhotoImage(img)
+ else:
+ mw = self.main_image.width()
+ mh = self.main_image.height()
+ if scale == 0: # Fit
+ try:
+ psc = w / h
+ isc = mw / mh
+ if psc < isc:
+ if w > mw:
+ fact = w // mw
+ else:
+ fact = -mw // w
+ else:
+ if h > mh:
+ fact = h // mh
+ else:
+ fact = -mh // h
+ except:
+ fact = 1
+ else:
+ fact = scale
+ self.canv_image = self.main_image.copy()
+ if fact > 0:
+ self.canv_image = self.canv_image.zoom(fact)
+ else:
+ self.canv_image = self.canv_image.subsample(-fact)
+ self.canv_image_fact = fact
+
+ # place on canvas
+ if fact > 0:
+ pw = mw * fact
+ ph = mh * fact
+ else:
+ pw = mw // -fact
+ ph = mh // -fact
+
+ cw = max(pw, w)
+ ch = max(ph, h)
+ c.config(scrollregion = (0, 0, cw - 2, ch - 2))
+ #print("Place c %d %d, p %d %d" % (cw, ch, w, h))
+ c.create_image(cw // 2, ch // 2, image = self.canv_image)
+
+ def make_image(self, imgobj):
+ if imgobj.image is not None:
+ return imgobj.image
+ width = imgobj.width
+ height = imgobj.height
+ data = imgobj.rgb
+ # create P6
+ phdr = ("P6\n{} {}\n255\n".format(width, height))
+ rawlen = width * height * 3 # RGB
+ #phdr = ("P5\n{} {}\n255\n".format(width, height))
+ #rawlen = width * height
+ phdr = phdr.encode("UTF-8")
+
+ if len(data) > rawlen:
+ # truncate
+ pdata = data[:rawlen]
+ if len(data) < rawlen:
+ # fill gap
+ gap = bytearray()
+ data += b"\xff" * (rawlen - len(data))
+ p = bytearray(phdr)
+ # fix UTF-8 issue
+ for ch in data:
+ if ch > 0x7f:
+ p += bytes((0b11000000 |\
+ ch >> 6, 0b10000000 |\
+ (ch & 0b00111111)))
+ else:
+ p += bytes((ch,))
+ image = tkinter.PhotoImage(width = width, height = height, \
+ data = bytes(p))
+ return image
+
+ def update_gui(self, text = "<Undefined>"):
+ self.last_path = self.curr_path
+ # cleanup
+ for item in self.curr_gui:
+ item()
+ self.curr_gui = []
+ self.curr_state = {} # save state across moves
+ # left listbox
+ lab = tkinter.Label(self.frm_left, text = text)
+ lab.pack()
+ frm_lb = ttk.Frame(self.frm_left)
+ frm_lb.pack(fill = tkinter.BOTH, expand = 1)
+ frm_lb.grid_rowconfigure(0, weight = 1)
+ frm_lb.grid_columnconfigure(0, weight = 1)
+ scr_lb_x = ttk.Scrollbar(frm_lb, orient = tkinter.HORIZONTAL)
+ scr_lb_x.grid(row = 1, column = 0, sticky = tkinter.E + tkinter.W)
+ scr_lb_y = ttk.Scrollbar(frm_lb)
+ scr_lb_y.grid(row = 0, column = 1, sticky = tkinter.N + tkinter.S)
+ frmlbpad = ttk.Frame(frm_lb, borderwidth = self.pad)
+ lb = tkinter.Listbox(frm_lb,
+ highlightthickness = 0,
+ xscrollcommand = scr_lb_x.set,
+ yscrollcommand = scr_lb_y.set)
+ lb.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ scr_lb_x.config(command = lb.xview)
+ scr_lb_y.config(command = lb.yview)
+ self.curr_gui.append(lambda:lb.grid_remove())
+ self.curr_gui.append(lambda:lab.pack_forget())
+ self.curr_gui.append(lambda:frm_lb.pack_forget())
+ lb.bind("<Double-Button-1>", self.on_left_listbox)
+ lb.bind("<Return>", self.on_left_listbox)
+ # actions on listbox
+ self.curr_lb = lb
+ self.curr_lb_acts = []
+ self.curr_lb_idx = {}
+
+ def switch_view(self, main):
+ # main view
+ if main == self.curr_main: return
+ last = self.curr_main
+ self.curr_main = main
+ rw = None
+ rh = None
+ if main == 0:
+ self.canv_view.delete(tkinter.ALL)
+ self.canv_view.grid_forget()
+ self.text_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ self.text_view.configure(
+ xscrollcommand = self.scr_view_x.set,
+ yscrollcommand = self.scr_view_y.set
+ )
+ self.scr_view_x.config(command = self.text_view.xview)
+ self.scr_view_y.config(command = self.text_view.yview)
+ else:
+
+ if last == 0:
+ rw = self.text_view.winfo_width()
+ rh = self.text_view.winfo_height()
+ self.canv_view.delete(tkinter.ALL)
+ self.text_view.grid_forget()
+ self.canv_view.grid(row = 0, column = 0, \
+ sticky = tkinter.N + tkinter.S + tkinter.E + tkinter.W)
+ self.canv_view.configure(
+ xscrollcommand = self.scr_view_x.set,
+ yscrollcommand = self.scr_view_y.set
+ )
+ self.scr_view_x.config(command = self.canv_view.xview)
+ self.scr_view_y.config(command = self.canv_view.yview)
+ if rh:
+ print(rh)
+ self.canv_view.height = rh
+ print(self.canv_view.winfo_height())
+
+ def clear_info(self):
+ self.text_view.delete(0.0, tkinter.END)
+
+ def add_info(self, text):
+ mode = 0 # 0 - normal, 1 - tag
+ curr_tag = None
+ curr_text = ""
+ tags = []
+ esc = False
+ for ch in text:
+ if mode == 0:
+ if esc:
+ curr_text += ch
+ esc = False
+ else:
+ if ch == "\\":
+ esc = True
+ elif ch == "<":
+ mode = 1
+ curr_tag = ""
+ else:
+ curr_text += ch
+ else:
+ if ch == ">":
+ if len(curr_text) > 0:
+ self.text_view.insert(tkinter.INSERT, curr_text, \
+ tuple(reversed([x for x in tags for x in x])))
+ if curr_tag[:7] == "a href=":
+ ref = curr_tag[7:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ def make_cb(path):
+ def cb():
+ if path[:5] == "http:" or path[:6] == "https:":
+ return self.open_http(path)
+ return self.open_path(path)
+ return cb
+ tags.append(self.text_hl.add(make_cb(ref)))
+ elif curr_tag[:11] == "font color=":
+ ref = curr_tag[11:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.text_hl.color(ref))
+ elif curr_tag[:8] == "font bg=":
+ ref = curr_tag[8:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.text_hl.bg(ref))
+ elif curr_tag == "b":
+ tags.append(["bold"])
+ elif curr_tag == "i":
+ tags.append(["italic"])
+ elif curr_tag == "u":
+ tags.append(["underline"])
+ elif curr_tag[:1] == "/":
+ tags = tags[:-1]
+ curr_text = ""
+ mode = 0
+ else:
+ curr_tag += ch
+ if len(curr_text) > 0:
+ self.text_view.insert(tkinter.INSERT, curr_text, \
+ tuple(reversed([x for x in tags for x in x])))
+
+ def insert_lb_act(self, name, act, key = None):
+ if key is not None:
+ self.curr_lb_idx[key] = len(self.curr_lb_acts)
+ self.curr_lb_acts.append((name, act))
+ if name == "-" and act is None:
+ self.curr_lb.insert(tkinter.END, "")
+ else:
+ self.curr_lb.insert(tkinter.END, " " + name)
+
+ def select_lb_item(self, key):
+ idx = self.curr_lb_idx.get(key, None)
+ need = (idx is not None)
+ idxs = "{}".format(idx)
+ for sel in self.curr_lb.curselection():
+ if sel == idxs:
+ need = False
+ else:
+ self.curr_lb.selection_clear(sel)
+ if need:
+ self.curr_lb.selection_set(idxs)
+ if idx is not None:
+ self.curr_lb.see(idxs)
+
+ def on_left_listbox(self, event):
+ def currsel():
+ try:
+ num = self.curr_lb.curselection()[0]
+ num = int(num)
+ except:
+ return None
+ return num
+
+ if self.curr_lb_acts:
+ act = self.curr_lb_acts[currsel()]
+ if act[1] is not None:
+ self.open_path(act[1])
+
+ def add_toolbtn(self, text, cmd):
+ if text is None:
+ frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
+ frm.pack(side = tkinter.LEFT)
+ self.curr_gui.append(lambda:frm.pack_forget())
+ return
+ btn = ttk.Button(self.toolbar, text = text, \
+ style = "Tool.TButton", command = cmd)
+ btn.pack(side = tkinter.LEFT)
+ self.curr_gui.append(lambda:btn.pack_forget())
+ return btn
+
+ def add_toollabel(self, text):
+ lab = ttk.Label(self.toolbar, text = text)
+ lab.pack(side = tkinter.LEFT)
+ self.curr_gui.append(lambda:lab.pack_forget())
+ return lab
+
+ def add_toolgrp(self, label, glkey, items, cbupd):
+ def makecb(v, g):
+ def btncb():
+ self.gl_state[g] = v
+ cbupd()
+ return btncb
+ if label:
+ self.add_toollabel(label)
+ kl = list(items.keys())
+ kl.sort()
+ res = []
+ for k in kl:
+ b = self.add_toolbtn(items[k], makecb(k, glkey))
+ res.append([b, k])
+ return res
+
+ def upd_toolgrp(self, btns, state):
+ for btn, idx in btns:
+ if idx != state and state != -1:
+ btn.config(state = tkinter.NORMAL)
+ else:
+ btn.config(state = tkinter.DISABLED)
+
+
+ def clear_hist(self):
+ self.hist = self.hist[-1:]
+ self.histf = []
+
Commit: b6ef152bc3f855efd440a798b662bfb42b17d3e1
https://github.com/scummvm/scummvm-tools/commit/b6ef152bc3f855efd440a798b662bfb42b17d3e1
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor gui
Changed paths:
A engines/petka/testtkgui.py
engines/petka/p12explore.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 67182b8df..dae941c61 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -4,20 +4,14 @@
# romiq.kh at gmail.com, 2015
import sys, os
+import urllib.parse
import tkinter
from tkinter import filedialog, messagebox
import traceback
-import webbrowser
from tkguibrowser import TkBrowser, hlesc, cesc, fmt_hl, fmt_hl_len, fmt_arg, \
fmt_dec, fmt_dec_len
-# Image processing
-try:
- from PIL import Image
-except ImportError:
- Image = None
-
# Translations
try:
import polib
@@ -27,7 +21,7 @@ except ImportError:
import petka
APPNAME = "Petka Explorer"
-VERSION = "v0.3i 2015-01-19"
+VERSION = "v0.4 2015-06-20"
HOME_URLS = ["http://petka-vich.com/petkaexplorer/",
"https://bitbucket.org/romiq/p12simtran"]
@@ -164,8 +158,7 @@ class App(TkBrowser):
repath = ""
break
if repath:
- self.open_path(repath)
-
+ self.open_path(repath)
def create_menu(self):
super().create_menu()
@@ -251,23 +244,6 @@ class App(TkBrowser):
mkmenupaths(self.menuhelp, helpnav)
- def on_help(self):
- self.open_path(["help", self.curr_help])
-
- def on_back(self):
- if len(self.hist) > 1:
- np = self.hist[-2:-1][0]
- self.histf = self.hist[-1:] + self.histf
- self.hist = self.hist[:-1]
- self.open_path(np[0], False)
-
- def on_forward(self):
- if len(self.histf) > 0:
- np = self.histf[0]
- self.histf = self.histf[1:]
- self.hist.append(np)
- self.open_path(np[0], False)
-
def open_path(self, loc, withhist = True):
res = super().open_path(loc, withhist)
# set title
@@ -282,6 +258,8 @@ class App(TkBrowser):
self.master.title(capt)
return res
+ def on_help(self):
+ self.open_path(["help", self.curr_help])
def _t(self, value, tp):
if not self.tran: return value
diff --git a/engines/petka/testtkgui.py b/engines/petka/testtkgui.py
new file mode 100755
index 000000000..6250041fb
--- /dev/null
+++ b/engines/petka/testtkgui.py
@@ -0,0 +1,68 @@
+#! /usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+# romiq.kh at gmail.com, 2015
+
+import sys, os
+import traceback
+import tkinter
+
+from tkguibrowser import TkBrowser, hlesc, cesc, fmt_hl, fmt_hl_len, fmt_arg, \
+ fmt_dec, fmt_dec_len
+
+APPNAME = "Test tkinter gui browser"
+VERSION = "v0.1 2015-06-20"
+
+class App(TkBrowser):
+ def __init__(self, master):
+ super().__init__(master)
+
+ def init_gui(self):
+ self.master.title(APPNAME)
+ # path
+ if hasattr(sys, 'frozen'):
+ self.app_path = sys.executable
+ else:
+ self.app_path = __file__
+ self.app_path = os.path.abspath(os.path.dirname(self.app_path))
+
+ def create_widgets(self):
+ super().create_widgets()
+ self.open_path("/")
+
+
+ def create_menu(self):
+ super().create_menu()
+ self.menufile = tkinter.Menu(self.master, tearoff = 0)
+ self.menubar.add_cascade(menu = self.menufile,
+ label = "File")
+ self.menufile.add_separator()
+ self.menufile.add_command(
+ command = self.on_exit,
+ label = "Quit")
+
+def main():
+ root = tkinter.Tk()
+ app = App(master = root)
+ argv = sys.argv[1:]
+ while len(argv) > 0:
+ if argv[0] == "-d": # open data
+ app.start_act.append(["load", argv[1]])
+ argv = argv[2:]
+ elif argv[0] == "-s": # open str file
+ app.start_act.append(["str", argv[1]])
+ argv = argv[2:]
+ elif argv[0] == "-sd": # open savex.dat file
+ app.start_act.append(["savedat", argv[1]])
+ argv = argv[2:]
+ elif argv[0] == "-t": # open translation
+ app.start_act.append(["tran", argv[1]])
+ argv = argv[2:]
+ else:
+ app.start_act.append(["open", argv[0]])
+ argv = argv[1:]
+ app.mainloop()
+
+
+if __name__ == "__main__":
+ main()
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index 675d8df2c..0aa376226 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -4,12 +4,17 @@
# romiq.kh at gmail.com, 2015
import math
-import urllib.parse
import tkinter
from tkinter import ttk, font, filedialog, messagebox
from idlelib.WidgetRedirector import WidgetRedirector
+# Image processing
+try:
+ from PIL import Image
+except ImportError:
+ Image = None
+
try:
from PIL import ImageTk
except ImportError:
@@ -166,6 +171,24 @@ class TkBrowser(tkinter.Frame):
self.create_widgets()
self.create_menu()
+ def on_help(self):
+ pass
+
+ def on_back(self):
+ if len(self.hist) > 1:
+ np = self.hist[-2:-1][0]
+ self.histf = self.hist[-1:] + self.histf
+ self.hist = self.hist[:-1]
+ self.open_path(np[0], False)
+
+ def on_forward(self):
+ if len(self.histf) > 0:
+ np = self.histf[0]
+ self.histf = self.histf[1:]
+ self.hist.append(np)
+ self.open_path(np[0], False)
+
+
def create_widgets(self):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
@@ -296,12 +319,11 @@ class TkBrowser(tkinter.Frame):
return self.desc_default(path)
def update_canvas(self):
- if self.curr_main == 0:
+ if self.curr_main == 0:
return
# draw grahics
c = self.canv_view
c.delete(tkinter.ALL)
- if self.sim is None: return
w = self.canv_view.winfo_width()
h = self.canv_view.winfo_height()
@@ -627,8 +649,14 @@ class TkBrowser(tkinter.Frame):
else:
btn.config(state = tkinter.DISABLED)
-
def clear_hist(self):
self.hist = self.hist[-1:]
self.histf = []
+ def path_default(self, path):
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Open path\n\n" + str(path))
+
+
+
Commit: 950acde83a83fc6d203ba99ec305e24ab9db43f9
https://github.com/scummvm/scummvm-tools/commit/950acde83a83fc6d203ba99ec305e24ab9db43f9
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Fixes for gui
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
engines/petka/testtkgui.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 66b240d52..cb2b466f3 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -1,5 +1,9 @@
ЧÑо нового
==========
+2015-06-20 веÑÑÐ¸Ñ 0.4
+---------------------
+ÐÑаÑиÑеÑкий инÑеÑÑÐµÐ¹Ñ Ð²Ñделен в оÑделÑнÑй модÑлÑ
+
2015-01-19 веÑÑÐ¸Ñ 0.3i
----------------------
ÐÑпÑавлено оÑобÑажение ÑÑен пÑи оÑÑÑÑÑÑвии ÑÑÑлок на обÑекÑÑ
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index dae941c61..70b4b08ed 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -58,11 +58,11 @@ def translit(text):
if allcaps:
ret = ret.upper()
return ret
-
class App(TkBrowser):
+
def __init__(self, master):
- super().__init__(master)
+ super().__init__(master)
def init_gui(self):
self.master.title(APPNAME)
@@ -122,7 +122,6 @@ class App(TkBrowser):
desc_def("Stores", "Store")]
self.path_handler["files"] = [self.path_files, self.desc_files]
self.path_handler["save"] = [self.path_save, "Save"]
- self.path_handler["test"] = [self.path_test, "Tests"]
self.path_handler["about"] = [self.path_about, "About"]
self.path_handler["support"] = [self.path_support, "Support"]
self.path_handler["help"] = [self.path_help, self.desc_help]
@@ -243,6 +242,12 @@ class App(TkBrowser):
helpnav = ["/help/index", None, "/support", "/info", "/about"]
mkmenupaths(self.menuhelp, helpnav)
+ def open_http(self, path):
+ if path not in HOME_URLS:
+ if not messagebox.askokcancel(parent = self, title = "Visit URL?",
+ message = "Would you like to open external URL:\n" + path +
+ " ?"): return
+ webbrowser.open(path)
def open_path(self, loc, withhist = True):
res = super().open_path(loc, withhist)
@@ -1921,76 +1926,6 @@ class App(TkBrowser):
self.insert_lb_act("Dialog opcodes", ["save", "dlgops"], "dlgops")
upd_save()
return True
-
-
- def path_test(self, path):
- def display_page():
- item = None
- path = self.curr_path
- if len(path) > 2:
- item = path[2]
- self.clear_info()
- sm = self.gl_state.get("test.info.mode", 0)
- if item is None:
- sm = -1
- self.upd_toolgrp(self.curr_state["gbtns"], sm)
- if item is None:
- self.switch_view(0)
- self.add_info("Select item " + path[1])
- else:
- if path[1] == "image":
- self.switch_view(1)
- self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
- elif path[1] == "info":
- self.switch_view(0)
- self.add_info("Information panel for {}\n".format(path))
- self.add_info("Local mode {}\n".format(
- self.curr_state.get("mode", None)))
- self.add_info("Global mode {}\n".format(
- self.gl_state.get("test.info.mode", None)))
- for i in range(100):
- self.add_info(" Item {}\n".format(i))
-
- if self.last_path[:1] != ("test",):
- self.update_gui("Test {}".format(path[1]))
- self.insert_lb_act("Outline", [])
- self.insert_lb_act("-", None)
- for i in range(15):
- self.insert_lb_act("{} #{}".format(path[1], i),
- path[:2] + (i,), i)
- # create mode buttons
- def sw_mode1():
- print("Mode 1")
- self.curr_state["mode"] = 1
- self.curr_state["btn1"].config(state = tkinter.DISABLED)
- self.curr_state["btn2"].config(state = tkinter.NORMAL)
- display_page()
- def sw_mode2():
- print("Mode 2")
- self.curr_state["mode"] = 2
- self.curr_state["btn1"].config(state = tkinter.NORMAL)
- self.curr_state["btn2"].config(state = tkinter.DISABLED)
- display_page()
- self.curr_state["btn1"] = self.add_toolbtn("Mode 1", sw_mode1)
- self.curr_state["btn2"] = self.add_toolbtn("Mode 2", sw_mode2)
- # we store buttons in local state
- self.curr_state["gbtns"] = self.add_toolgrp(None, "test.info.mode",
- {0: "mode 1", 1: "mode 2", 2: "mode 3"}, display_page)
-
- # change
- item = None
- if len(path) > 2:
- # index
- self.select_lb_item(path[2])
- try:
- item = path[2]
- except:
- pass
- else:
- self.select_lb_item(None)
- # display
- display_page()
- return True
def path_about(self, path):
self.switch_view(0)
diff --git a/engines/petka/testtkgui.py b/engines/petka/testtkgui.py
index 6250041fb..ba8def711 100755
--- a/engines/petka/testtkgui.py
+++ b/engines/petka/testtkgui.py
@@ -28,7 +28,19 @@ class App(TkBrowser):
def create_widgets(self):
super().create_widgets()
- self.open_path("/")
+
+ self.path_handler["test"] = [self.path_test, "Tests"]
+
+ repath = "/"
+ for cmd, arg in self.start_act:
+ if cmd == "open":
+ repath = ""
+ if not self.open_path(arg):
+ print("DEBUG: stop opening after " + arg)
+ repath = ""
+ break
+ if repath:
+ self.open_path(repath)
def create_menu(self):
@@ -41,28 +53,116 @@ class App(TkBrowser):
command = self.on_exit,
label = "Quit")
+ def path_default(self, path):
+ self.switch_view(0)
+ self.update_gui("Outline")
+ self.clear_info()
+ self.add_info("Open path\n\n" + str(path))
+
+ self.add_info("\n\n")
+ self.add_info("<a href=\"http://example.com/test\">example.com</a>\n")
+ self.add_info("\n\n<b>This is multi-")
+ self.add_info("line\nbold</b>\n")
+ self.add_info("\n\n<u>This is multi-")
+ self.add_info("line\nunderline</u>\n")
+ self.add_info("\n\n<font color=\"#ff00FF\">This is multi-")
+ self.add_info("line\nunderline</u>\n")
+
+ self.insert_lb_act("Testing", "/test")
+ return True
+
+ def path_test(self, path):
+ if len(path) > 1:
+ return self.path_test_item(path)
+ if self.last_path != ("test",):
+ self.update_gui("Test")
+ self.insert_lb_act("Outline", [])
+ self.insert_lb_act("-", None)
+ self.insert_lb_act("Info", "/test/info")
+ self.insert_lb_act("Image", "/test/image")
+ self.switch_view(0)
+ self.clear_info()
+ self.add_info("Select test from outline")
+ return True
+
+ def path_test_item(self, path):
+ def display_page():
+ item = None
+ path = self.curr_path
+ if len(path) > 2:
+ item = path[2]
+ self.clear_info()
+ sm = self.gl_state.get("test.info.mode", 0)
+ if item is None:
+ sm = -1
+ self.upd_toolgrp(self.curr_state["gbtns"], sm)
+ if item is None:
+ self.switch_view(0)
+ self.add_info("Select item " + path[1])
+ else:
+ if path[1] == "image":
+ self.switch_view(1)
+ self.main_image = tkinter.PhotoImage(file = "img/splash.gif")
+ elif path[1] == "info":
+ self.switch_view(0)
+ self.add_info("Information panel for {}\n".format(path))
+ self.add_info("Local mode {}\n".format(
+ self.curr_state.get("mode", None)))
+ self.add_info("Global mode {}\n".format(
+ self.gl_state.get("test.info.mode", None)))
+ for i in range(100):
+ self.add_info(" Item {}\n".format(i))
+
+ if self.last_path[:2] != ("test", path[1]):
+ self.update_gui("Test %s" % path[1])
+ self.insert_lb_act("Testing", "/test")
+ self.insert_lb_act("-", None)
+ for i in range(15):
+ self.insert_lb_act("{} #{}".format(path[1], i),
+ path[:2] + (i,), i)
+ # create mode buttons
+ def sw_mode1():
+ print("Mode 1")
+ self.curr_state["mode"] = 1
+ self.curr_state["btn1"].config(state = tkinter.DISABLED)
+ self.curr_state["btn2"].config(state = tkinter.NORMAL)
+ display_page()
+ def sw_mode2():
+ print("Mode 2")
+ self.curr_state["mode"] = 2
+ self.curr_state["btn1"].config(state = tkinter.NORMAL)
+ self.curr_state["btn2"].config(state = tkinter.DISABLED)
+ display_page()
+ self.curr_state["btn1"] = self.add_toolbtn("Mode 1", sw_mode1)
+ self.curr_state["btn1"].config(state = tkinter.DISABLED)
+ self.curr_state["btn2"] = self.add_toolbtn("Mode 2", sw_mode2)
+ # we store buttons in local state
+ self.curr_state["gbtns"] = self.add_toolgrp(None, "test.info.mode",
+ {0: "mode 1", 1: "mode 2", 2: "mode 3"}, display_page)
+
+ # change
+ item = None
+ if len(path) > 2:
+ # index
+ self.select_lb_item(path[2])
+ else:
+ self.select_lb_item(None)
+ # display
+ display_page()
+ return True
+
def main():
root = tkinter.Tk()
app = App(master = root)
argv = sys.argv[1:]
while len(argv) > 0:
- if argv[0] == "-d": # open data
- app.start_act.append(["load", argv[1]])
- argv = argv[2:]
- elif argv[0] == "-s": # open str file
- app.start_act.append(["str", argv[1]])
- argv = argv[2:]
- elif argv[0] == "-sd": # open savex.dat file
- app.start_act.append(["savedat", argv[1]])
- argv = argv[2:]
- elif argv[0] == "-t": # open translation
- app.start_act.append(["tran", argv[1]])
- argv = argv[2:]
+ if argv[0] == "--nooutline": # open data
+ app.gui_setup["outline"] = False
+ argv = argv[1:]
else:
app.start_act.append(["open", argv[0]])
argv = argv[1:]
app.mainloop()
-
if __name__ == "__main__":
main()
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index 0aa376226..95f22d0c6 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -4,6 +4,7 @@
# romiq.kh at gmail.com, 2015
import math
+import traceback
import tkinter
from tkinter import ttk, font, filedialog, messagebox
@@ -56,6 +57,7 @@ def fmt_dec_len(value, add = 0):
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager:
+
def __init__(self, text):
self.text = text
self.text.tag_config("hyper", foreground = "blue", underline = 1)
@@ -111,8 +113,10 @@ class HyperlinkManager:
self.links[tag]()
return
+
# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
class ReadOnlyText(tkinter.Text):
+
def __init__(self, *args, **kwargs):
tkinter.Text.__init__(self, *args, **kwargs)
self.redirector = WidgetRedirector(self)
@@ -121,6 +125,7 @@ class ReadOnlyText(tkinter.Text):
self.delete = \
self.redirector.register("delete", lambda *args, **kw: "break")
+
class TkBrowser(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
@@ -284,29 +289,6 @@ class TkBrowser(tkinter.Frame):
path = path[:-1]
return path
- def open_http(self, path):
- if path not in HOME_URLS:
- if not messagebox.askokcancel(parent = self, title = "Visit URL?",
- message = "Would you like to open external URL:\n" + path +
- " ?"): return
- webbrowser.open(path)
-
- def open_path(self, loc, withhist = True):
- path = self.parse_path(loc)
- if withhist:
- self.hist.append([path])
- self.histf = []
- print("DEBUG: Open", path)
- self.curr_path = path
- if len(path) > 0:
- self.curr_help = path[0]
- else:
- self.curr_help = ""
- if len(path) > 0:
- if path[0] in self.path_handler:
- return self.path_handler[path[0]][0](path)
- return self.path_default(path)
-
def desc_path(self, loc):
path = self.parse_path(loc)
if len(path) > 0:
@@ -504,6 +486,9 @@ class TkBrowser(tkinter.Frame):
def clear_info(self):
self.text_view.delete(0.0, tkinter.END)
+ def add_text(self, text):
+ self.text_view.insert(tkinter.INSERT, text)
+
def add_info(self, text):
mode = 0 # 0 - normal, 1 - tag
curr_tag = None
@@ -653,10 +638,34 @@ class TkBrowser(tkinter.Frame):
self.hist = self.hist[-1:]
self.histf = []
+ def open_http(self, path):
+ messagebox.showinfo(parent = self, title = "URL", message = path)
+
+ def open_path(self, loc, withhist = True):
+ path = self.parse_path(loc)
+ if withhist:
+ self.hist.append([path])
+ self.histf = []
+ print("DEBUG: Open", path)
+ self.curr_path = path
+ if len(path) > 0:
+ self.curr_help = path[0]
+ else:
+ self.curr_help = ""
+ try:
+ if len(path) > 0:
+ if path[0] in self.path_handler:
+ return self.path_handler[path[0]][0](path)
+ return self.path_default(path)
+ except Exception:
+ self.switch_view(0)
+ self.add_text("\n" + "="*20 + "\n" + traceback.format_exc())
+ return True
+
def path_default(self, path):
self.switch_view(0)
self.clear_info()
self.add_info("Open path\n\n" + str(path))
-
+ return True
Commit: 49cc81971b8a8b8824e06c741b9fa67a231e7bf1
https://github.com/scummvm/scummvm-tools/commit/49cc81971b8a8b8824e06c741b9fa67a231e7bf1
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: linefeed do not break color tags
Changed paths:
engines/petka/help/changes.txt
engines/petka/testtkgui.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index cb2b466f3..31755529c 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -3,6 +3,8 @@
2015-06-20 веÑÑÐ¸Ñ 0.4
---------------------
ÐÑаÑиÑеÑкий инÑеÑÑÐµÐ¹Ñ Ð²Ñделен в оÑделÑнÑй модÑлÑ
+ÐеÑевод ÑÑÑок не закÑÑÐ²Ð°ÐµÑ Ñеги
+ÐоÑле оконÑÐ°Ð½Ð¸Ñ Ð²Ñвода необÑ
одимо вÑзÑваÑÑ ÑÑнкÑÐ¸Ñ Ð´Ð»Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð¸Ñ Ð²Ñвода
2015-01-19 веÑÑÐ¸Ñ 0.3i
----------------------
diff --git a/engines/petka/testtkgui.py b/engines/petka/testtkgui.py
index ba8def711..42dc3182e 100755
--- a/engines/petka/testtkgui.py
+++ b/engines/petka/testtkgui.py
@@ -62,11 +62,11 @@ class App(TkBrowser):
self.add_info("\n\n")
self.add_info("<a href=\"http://example.com/test\">example.com</a>\n")
self.add_info("\n\n<b>This is multi-")
- self.add_info("line\nbold</b>\n")
+ self.add_info("line\nbold</b> text\n")
self.add_info("\n\n<u>This is multi-")
- self.add_info("line\nunderline</u>\n")
+ self.add_info("line\nunderline</u> text\n")
self.add_info("\n\n<font color=\"#ff00FF\">This is multi-")
- self.add_info("line\nunderline</u>\n")
+ self.add_info("line\ncolor</font> text\n")
self.insert_lb_act("Testing", "/test")
return True
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index 95f22d0c6..2ed0398c3 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -127,6 +127,7 @@ class ReadOnlyText(tkinter.Text):
class TkBrowser(tkinter.Frame):
+
def __init__(self, master):
tkinter.Frame.__init__(self, master)
self.pack(fill = tkinter.BOTH, expand = 1)
@@ -140,6 +141,7 @@ class TkBrowser(tkinter.Frame):
self.last_path = [None]
self.curr_gui = []
self.curr_state = {} # local state for location group
+ self.curr_markup = "" # current unparsed markup data (unclosed tags, etc)
self.curr_lb_acts = None
self.curr_lb_idx = None
self.hist = []
@@ -463,8 +465,7 @@ class TkBrowser(tkinter.Frame):
)
self.scr_view_x.config(command = self.text_view.xview)
self.scr_view_y.config(command = self.text_view.yview)
- else:
-
+ else:
if last == 0:
rw = self.text_view.winfo_width()
rh = self.text_view.winfo_height()
@@ -487,12 +488,19 @@ class TkBrowser(tkinter.Frame):
self.text_view.delete(0.0, tkinter.END)
def add_text(self, text):
+ self.end_markup()
self.text_view.insert(tkinter.INSERT, text)
def add_info(self, text):
+ self.curr_markup += text
+
+ def end_markup(self):
+ if not self.curr_markup: return
mode = 0 # 0 - normal, 1 - tag
curr_tag = None
curr_text = ""
+ text = self.curr_markup
+ self.curr_markup = ""
tags = []
esc = False
for ch in text:
@@ -506,6 +514,9 @@ class TkBrowser(tkinter.Frame):
elif ch == "<":
mode = 1
curr_tag = ""
+ elif ch == "\n":
+ curr_text += ch
+ pass
else:
curr_text += ch
else:
@@ -653,14 +664,15 @@ class TkBrowser(tkinter.Frame):
else:
self.curr_help = ""
try:
- if len(path) > 0:
- if path[0] in self.path_handler:
- return self.path_handler[path[0]][0](path)
- return self.path_default(path)
+ if len(path) > 0 and path[0] in self.path_handler:
+ res = self.path_handler[path[0]][0](path)
+ else:
+ res = self.path_default(path)
except Exception:
self.switch_view(0)
self.add_text("\n" + "="*20 + "\n" + traceback.format_exc())
- return True
+ res = True
+ self.end_markup()
def path_default(self, path):
self.switch_view(0)
Commit: 9f235c5d8e936a9a390798caa4011b8c572ca068
https://github.com/scummvm/scummvm-tools/commit/9f235c5d8e936a9a390798caa4011b8c572ca068
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: refactor markup
Changed paths:
engines/petka/testtkgui.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/testtkgui.py b/engines/petka/testtkgui.py
index 42dc3182e..384b5d097 100755
--- a/engines/petka/testtkgui.py
+++ b/engines/petka/testtkgui.py
@@ -68,6 +68,8 @@ class App(TkBrowser):
self.add_info("\n\n<font color=\"#ff00FF\">This is multi-")
self.add_info("line\ncolor</font> text\n")
+ self.add_info("\n<font bg=\"red\" color=\"white\"> White on red </font>\n")
+
self.insert_lb_act("Testing", "/test")
return True
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index 2ed0398c3..99370fa13 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -113,6 +113,70 @@ class HyperlinkManager:
self.links[tag]()
return
+ def add_markup(self, text, widget, handler):
+ mode = 0 # 0 - normal, 1 - tag
+ curr_tag = None
+ curr_text = ""
+ tags = []
+ esc = False
+ for ch in text:
+ if mode == 0:
+ if esc:
+ curr_text += ch
+ esc = False
+ else:
+ if ch == "\\":
+ esc = True
+ elif ch == "<":
+ mode = 1
+ curr_tag = ""
+ elif ch == "\n":
+ curr_text += ch
+ pass
+ else:
+ curr_text += ch
+ else:
+ if ch == ">":
+ if len(curr_text) > 0:
+ widget.insert(tkinter.INSERT, curr_text, \
+ tuple(reversed([x for x in tags for x in x])))
+ if curr_tag[:7] == "a href=":
+ ref = curr_tag[7:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.add(handler(ref)))
+ elif curr_tag[:11] == "font color=":
+ ref = curr_tag[11:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.color(ref))
+ elif curr_tag[:8] == "font bg=":
+ ref = curr_tag[8:]
+ if ref[:1] == "\"":
+ ref = ref[1:]
+ if ref[-1:] == "\"":
+ ref = ref[:-1]
+ tags.append(self.bg(ref))
+ elif curr_tag == "b":
+ tags.append(["bold"])
+ elif curr_tag == "i":
+ tags.append(["italic"])
+ elif curr_tag == "u":
+ tags.append(["underline"])
+ elif curr_tag[:1] == "/":
+ tags = tags[:-1]
+ curr_text = ""
+ mode = 0
+ else:
+ curr_tag += ch
+ if len(curr_text) > 0:
+ widget.insert(tkinter.INSERT, curr_text, \
+ tuple(reversed([x for x in tags for x in x])))
+
# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
class ReadOnlyText(tkinter.Text):
@@ -195,7 +259,6 @@ class TkBrowser(tkinter.Frame):
self.hist.append(np)
self.open_path(np[0], False)
-
def create_widgets(self):
ttk.Style().configure("Tool.TButton", width = -1) # minimal width
ttk.Style().configure("TLabel", padding = self.pad)
@@ -496,76 +559,14 @@ class TkBrowser(tkinter.Frame):
def end_markup(self):
if not self.curr_markup: return
- mode = 0 # 0 - normal, 1 - tag
- curr_tag = None
- curr_text = ""
- text = self.curr_markup
+ def make_cb(path):
+ def cb():
+ if path[:5] == "http:" or path[:6] == "https:":
+ return self.open_http(path)
+ return self.open_path(path)
+ return cb
+ self.text_hl.add_markup(self.curr_markup, self.text_view, make_cb)
self.curr_markup = ""
- tags = []
- esc = False
- for ch in text:
- if mode == 0:
- if esc:
- curr_text += ch
- esc = False
- else:
- if ch == "\\":
- esc = True
- elif ch == "<":
- mode = 1
- curr_tag = ""
- elif ch == "\n":
- curr_text += ch
- pass
- else:
- curr_text += ch
- else:
- if ch == ">":
- if len(curr_text) > 0:
- self.text_view.insert(tkinter.INSERT, curr_text, \
- tuple(reversed([x for x in tags for x in x])))
- if curr_tag[:7] == "a href=":
- ref = curr_tag[7:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- def make_cb(path):
- def cb():
- if path[:5] == "http:" or path[:6] == "https:":
- return self.open_http(path)
- return self.open_path(path)
- return cb
- tags.append(self.text_hl.add(make_cb(ref)))
- elif curr_tag[:11] == "font color=":
- ref = curr_tag[11:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.text_hl.color(ref))
- elif curr_tag[:8] == "font bg=":
- ref = curr_tag[8:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.text_hl.bg(ref))
- elif curr_tag == "b":
- tags.append(["bold"])
- elif curr_tag == "i":
- tags.append(["italic"])
- elif curr_tag == "u":
- tags.append(["underline"])
- elif curr_tag[:1] == "/":
- tags = tags[:-1]
- curr_text = ""
- mode = 0
- else:
- curr_tag += ch
- if len(curr_text) > 0:
- self.text_view.insert(tkinter.INSERT, curr_text, \
- tuple(reversed([x for x in tags for x in x])))
def insert_lb_act(self, name, act, key = None):
if key is not None:
Commit: 66a62d9911f533e0bf5a4ea45242ec975f397db8
https://github.com/scummvm/scummvm-tools/commit/66a62d9911f533e0bf5a4ea45242ec975f397db8
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: replace html parser with HtmlParser
Changed paths:
engines/petka/help/changes.txt
engines/petka/p12explore.py
engines/petka/testtkgui.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/help/changes.txt b/engines/petka/help/changes.txt
index 31755529c..eec0eacb0 100644
--- a/engines/petka/help/changes.txt
+++ b/engines/petka/help/changes.txt
@@ -5,6 +5,7 @@
ÐÑаÑиÑеÑкий инÑеÑÑÐµÐ¹Ñ Ð²Ñделен в оÑделÑнÑй модÑлÑ
ÐеÑевод ÑÑÑок не закÑÑÐ²Ð°ÐµÑ Ñеги
ÐоÑле оконÑÐ°Ð½Ð¸Ñ Ð²Ñвода необÑ
одимо вÑзÑваÑÑ ÑÑнкÑÐ¸Ñ Ð´Ð»Ñ Ð·Ð°Ð²ÐµÑÑÐµÐ½Ð¸Ñ Ð²Ñвода
+ÐаÑÑинг html пеÑеведÑн на ÑÑандаÑÑнÑÑ Ð±Ð¸Ð±Ð»Ð¸Ð¾ÑекÑ
2015-01-19 веÑÑÐ¸Ñ 0.3i
----------------------
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 70b4b08ed..72bf52d84 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -8,6 +8,7 @@ import urllib.parse
import tkinter
from tkinter import filedialog, messagebox
import traceback
+import webbrowser
from tkguibrowser import TkBrowser, hlesc, cesc, fmt_hl, fmt_hl_len, fmt_arg, \
fmt_dec, fmt_dec_len
diff --git a/engines/petka/testtkgui.py b/engines/petka/testtkgui.py
index 384b5d097..56a953a71 100755
--- a/engines/petka/testtkgui.py
+++ b/engines/petka/testtkgui.py
@@ -68,7 +68,7 @@ class App(TkBrowser):
self.add_info("\n\n<font color=\"#ff00FF\">This is multi-")
self.add_info("line\ncolor</font> text\n")
- self.add_info("\n<font bg=\"red\" color=\"white\"> White on red </font>\n")
+ self.add_info("\n<font bg=\"red\" color=\"white\"> <b>White</b> on <i>red</i> </font>\n")
self.insert_lb_act("Testing", "/test")
return True
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index 99370fa13..efa9dfdce 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -5,6 +5,7 @@
import math
import traceback
+from html.parser import HTMLParser
import tkinter
from tkinter import ttk, font, filedialog, messagebox
@@ -54,9 +55,9 @@ def fmt_dec_len(value, add = 0):
d = int(math.log10(value)) + 1
d += add
return d
-
+
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
-class HyperlinkManager:
+class HyperlinkManager(HTMLParser):
def __init__(self, text):
self.text = text
@@ -71,12 +72,17 @@ class HyperlinkManager:
italic_font.configure(slant = "italic")
self.text.tag_config("italic", font = italic_font)
self.text.tag_config("underline", underline = 1)
+ self.parser = HTMLParser()
+ self.parser.handle_starttag = self.handle_starttag
+ self.parser.handle_endtag = self.handle_endtag
+ self.parser.handle_data = self.handle_data
self.reset()
def reset(self):
self.links = {}
self.colors = []
self.bgs = []
+ self.colorbgs = []
def add(self, action):
# add an action to the manager. returns tags to use in
@@ -101,6 +107,14 @@ class HyperlinkManager:
self.text.tag_raise("hyper")
return (tag,)
+ def colorbg(self, color, bg):
+ tag = "colorbg-{}".format(color, bg)
+ if tag not in self.colorbgs:
+ self.colorbgs.append(tag)
+ self.text.tag_config(tag, foreground = color, background = bg)
+ self.text.tag_raise("hyper")
+ return (tag,)
+
def _enter(self, event):
self.text.config(cursor = "hand2")
@@ -113,70 +127,46 @@ class HyperlinkManager:
self.links[tag]()
return
- def add_markup(self, text, widget, handler):
- mode = 0 # 0 - normal, 1 - tag
- curr_tag = None
- curr_text = ""
- tags = []
- esc = False
- for ch in text:
- if mode == 0:
- if esc:
- curr_text += ch
- esc = False
- else:
- if ch == "\\":
- esc = True
- elif ch == "<":
- mode = 1
- curr_tag = ""
- elif ch == "\n":
- curr_text += ch
- pass
- else:
- curr_text += ch
+ def handle_starttag(self, tag, attrs):
+ tagmap = {"b": "bold", "i": "italic", "u": "underline"}
+ if tag in tagmap:
+ self.parser_tags.append([tagmap[tag]])
+ elif tag == "a":
+ ref = ""
+ for k, v in attrs:
+ if k == "href":
+ ref = v
+ self.parser_tags.append(self.add(self.parser_handler(ref)))
+ elif tag == "font":
+ color = ""
+ bg = ""
+ for k, v in attrs:
+ if k == "color":
+ color = v
+ elif k == "bg":
+ bg = v
+ if color and bg:
+ self.parser_tags.append(self.colorbg(color, bg))
+ elif bg:
+ self.parser_tags.append(self.bg(bg))
else:
- if ch == ">":
- if len(curr_text) > 0:
- widget.insert(tkinter.INSERT, curr_text, \
- tuple(reversed([x for x in tags for x in x])))
- if curr_tag[:7] == "a href=":
- ref = curr_tag[7:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.add(handler(ref)))
- elif curr_tag[:11] == "font color=":
- ref = curr_tag[11:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.color(ref))
- elif curr_tag[:8] == "font bg=":
- ref = curr_tag[8:]
- if ref[:1] == "\"":
- ref = ref[1:]
- if ref[-1:] == "\"":
- ref = ref[:-1]
- tags.append(self.bg(ref))
- elif curr_tag == "b":
- tags.append(["bold"])
- elif curr_tag == "i":
- tags.append(["italic"])
- elif curr_tag == "u":
- tags.append(["underline"])
- elif curr_tag[:1] == "/":
- tags = tags[:-1]
- curr_text = ""
- mode = 0
- else:
- curr_tag += ch
- if len(curr_text) > 0:
- widget.insert(tkinter.INSERT, curr_text, \
- tuple(reversed([x for x in tags for x in x])))
+ self.parser_tags.append(self.color(color))
+ def handle_endtag(self, tag):
+ self.parser_tags = self.parser_tags[:-1]
+
+ def handle_data(self, data):
+ self.parser_widget.insert(tkinter.INSERT, data, \
+ tuple(reversed([x for x in self.parser_tags for x in x])))
+
+ def add_markup(self, text, widget, handler):
+ self.parser_tags = []
+ self.parser_widget = widget
+ self.parser_handler = handler
+ self.parser.reset()
+ self.parser.feed(text)
+ return
+
# thanx http://tkinter.unpythonic.net/wiki/ReadOnlyText
class ReadOnlyText(tkinter.Text):
Commit: bfb4aa50586d04f5655903812bcf33260da9fa3e
https://github.com/scummvm/scummvm-tools/commit/bfb4aa50586d04f5655903812bcf33260da9fa3e
Author: Roman Kharin (romiq.kh at gmail.com)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Add new dump function - for automatic testing generated data
Changed paths:
engines/petka/p12explore.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 72bf52d84..3dea0aea6 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -157,6 +157,8 @@ class App(TkBrowser):
print("DEBUG: stop opening after " + arg)
repath = ""
break
+ elif cmd == "dump":
+ self.dump_pages(arg)
if repath:
self.open_path(repath)
@@ -2361,6 +2363,144 @@ class App(TkBrowser):
self.add_info("Error saving \"{}\" \n\n{}".\
format(hlesc(fn), hlesc(traceback.format_exc())))
+ def dump_pages(self, path):
+ print("Dumping pages")
+ import json
+ import urllib
+
+ def normalize_link(dest):
+ self.dumpaddr = None
+ def open_path(path):
+ print(" catch " + path)
+ self.dumpaddr = path
+ if callable(dest):
+ # hook self.open_path
+ orig = self.open_path
+ self.open_path = open_path
+ try:
+ dest()
+ dest = self.dumpaddr
+ except Exception:
+ traceback.print_exc()
+ return
+ finally:
+ self.open_path = orig
+ elif isinstance(dest, (list, tuple)):
+ dest = "/" + "/".join([str(x) for x in dest])
+ return dest
+
+ def normalize_link_html(dest, curr):
+ lnk = normalize_link(dest)
+ if lnk[:1] == "/":
+ lnk = lnk[1:]
+ rel = os.path.relpath(os.path.join(path, lnk), os.path.dirname(curr))
+ if rel == ".":
+ return rel
+ return rel + ".html"
+
+ def save_data(fn, data, outline):
+ print(" save " + fn)
+ if not os.path.exists(path):
+ os.makedirs(path)
+ # raw
+ with open(fn + ".dat", "wb") as f:
+ f.write(json.dumps(data, indent = 4).encode("UTF-8"))
+ # html
+ head = "<html><head><meta http-equiv=\"Content-Type\" " +\
+ "content=\"text/html; charset=utf-8\">\n</head>"
+ with open(fn + ".html", "w") as f:
+ f.write(head)
+ f.write("<body><table><tr><td width=\"20%\" valign=top>\n")
+
+ f.write("<ul>\n")
+ for name, act in outline:
+ if act:
+ f.write("<li><a href=\"%s\">%s</a></li>\n" % (
+ normalize_link_html(act, fn), name))
+ else:
+ f.write("<li>%s</li>\n" % name)
+ f.write("</ul>\n")
+
+ f.write("</td><td valign=top>\n")
+
+ f.write("<pre>")
+ for tp, text, idx in self.text_view.dump("0.0", "end-1c"):
+ if tp == "tagon":
+ if text.startswith("hyper-"):
+ lnk = normalize_link_html(self.text_hl.links[text], fn)
+ f.write("<a href=\"%s\">" % lnk)
+ elif text == "bold":
+ f.write("<b>")
+ elif text == "italic":
+ f.write("<i>")
+ elif text == "underline":
+ f.write("<u>")
+ if text.startswith("color-"):
+ f.write("<font color=\"%s\">" % text[6:])
+ if tp == "tagoff":
+ if text.startswith("hyper-"):
+ f.write("</a>")
+ elif text == "bold":
+ f.write("</b>")
+ elif text == "italic":
+ f.write("</i>")
+ elif text == "underline":
+ f.write("</u>")
+ if text.startswith("color-"):
+ f.write("</font>")
+ elif tp == "text":
+ f.write(text)
+ f.write("</pre>\n")
+
+ f.write("</td></tr><table>\n")
+ f.write("</body></html>\n")
+
+ def save_curr():
+ fn = "/".join([str(x) for x in self.curr_path])
+ fn = os.path.join(path, fn)
+ if not os.path.exists(os.path.dirname(fn)):
+ os.makedirs(os.path.dirname(fn))
+ save_data(fn, self.text_view.dump("0.0", "end-1c"),
+ self.curr_lb_acts)
+
+ parsed = []
+ queue = []
+ def addaddr(dest):
+ lnk = normalize_link(dest)
+ if lnk not in parsed + queue:
+ queue.append(lnk)
+
+ def scan_page(dest):
+ print(" scan " + str(dest))
+ if dest.startswith("/parts/"): return # avoid changing part
+ if dest.startswith("/files/"): return # avoid too big files data
+ #if dest.startswith("/res/"): return
+ if dest in parsed:
+ return
+ parsed.append(dest)
+ self.open_path(dest)
+ self.update()
+ if self.curr_main == 0:
+ save_curr()
+ # scan text contain
+ for tp, text, idx in self.text_view.dump("0.0", "end-1c"):
+ if tp == "tagon" and text.startswith("hyper-"):
+ addaddr(self.text_hl.links[text])
+ #print(self.text_hl.links[text])
+ else:
+ pass
+ # scan from outline
+ for name, act in self.curr_lb_acts:
+ if act:
+ addaddr(act)
+ queue.append("/")
+ queue.append("/help")
+ queue.append("/info")
+ while len(queue) > 0:
+ addr = queue[0]
+ queue = queue[1:]
+ scan_page(addr)
+
def main():
root = tkinter.Tk()
@@ -2379,6 +2519,9 @@ def main():
elif argv[0] == "-t": # open translation
app.start_act.append(["tran", argv[1]])
argv = argv[2:]
+ elif argv[0] == "-dump": # dump to folder
+ app.start_act.append(["dump", argv[1]])
+ argv = argv[2:]
else:
app.start_act.append(["open", argv[0]])
argv = argv[1:]
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index efa9dfdce..2fd4aeb58 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -108,7 +108,7 @@ class HyperlinkManager(HTMLParser):
return (tag,)
def colorbg(self, color, bg):
- tag = "colorbg-{}".format(color, bg)
+ tag = "colorbg-{}|{}".format(color, bg)
if tag not in self.colorbgs:
self.colorbgs.append(tag)
self.text.tag_config(tag, foreground = color, background = bg)
@@ -664,6 +664,7 @@ class TkBrowser(tkinter.Frame):
self.add_text("\n" + "="*20 + "\n" + traceback.format_exc())
res = True
self.end_markup()
+ return res
def path_default(self, path):
self.switch_view(0)
Commit: 0225608fd336683d8dcbc1a0cf519859cac9a2e5
https://github.com/scummvm/scummvm-tools/commit/0225608fd336683d8dcbc1a0cf519859cac9a2e5
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
TOOLS: PETKA: Bring to modern python3
Changed paths:
engines/petka/tkguibrowser.py
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index 2fd4aeb58..fe17d6d9a 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -9,7 +9,7 @@ from html.parser import HTMLParser
import tkinter
from tkinter import ttk, font, filedialog, messagebox
-from idlelib.WidgetRedirector import WidgetRedirector
+from idlelib.redirector import WidgetRedirector
# Image processing
try:
Commit: 12ca962b150f2eca76785827c361ede3cbbde29b
https://github.com/scummvm/scummvm-tools/commit/12ca962b150f2eca76785827c361ede3cbbde29b
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2020-12-06T18:07:15+01:00
Commit Message:
JANITORIAL: Remove trailing spaces
Changed paths:
engines/petka/p12explore.py
engines/petka/p12script.py
engines/petka/petka/__init__.py
engines/petka/petka/engine.py
engines/petka/petka/fman.py
engines/petka/petka/imgbmp.py
engines/petka/petka/imgflc.py
engines/petka/petka/imgleg.py
engines/petka/petka/imgmsk.py
engines/petka/petka/saves.py
engines/petka/testtkgui.py
engines/petka/tkguibrowser.py
diff --git a/engines/petka/p12explore.py b/engines/petka/p12explore.py
index 3dea0aea6..990c6ea47 100755
--- a/engines/petka/p12explore.py
+++ b/engines/petka/p12explore.py
@@ -23,9 +23,9 @@ import petka
APPNAME = "Petka Explorer"
VERSION = "v0.4 2015-06-20"
-HOME_URLS = ["http://petka-vich.com/petkaexplorer/",
+HOME_URLS = ["http://petka-vich.com/petkaexplorer/",
"https://bitbucket.org/romiq/p12simtran"]
-
+
def translit(text):
ru = "абвгдеÑзийклмнопÑÑÑÑÑÑ
ÑÑÑÑÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐÐРСТУФХЪЫЬÐ"
en = "abvgdeezijklmnoprstufh'y'eABVGDEEZIJKLMNOPRSTUFH'Y'E"
@@ -64,7 +64,7 @@ class App(TkBrowser):
def __init__(self, master):
super().__init__(master)
-
+
def init_gui(self):
self.master.title(APPNAME)
self.clear_data()
@@ -74,7 +74,7 @@ class App(TkBrowser):
else:
self.app_path = __file__
self.app_path = os.path.abspath(os.path.dirname(self.app_path))
-
+
def clear_data(self):
self.sim = None
self.last_fn = ""
@@ -85,13 +85,13 @@ class App(TkBrowser):
self.last_savefn = ""
# translation
self.tran = None
-
+
def create_widgets(self):
super().create_widgets()
def desc_def(aname, name, lst = {}):
def desc(path):
if len(path) > 1:
- return "{} {}".format(name, lst.get(path[1],
+ return "{} {}".format(name, lst.get(path[1],
"#{}".format(path[1])))
else:
return aname
@@ -114,7 +114,7 @@ class App(TkBrowser):
self.path_handler["casts"] = [self.path_casts,
desc_def("Casts", "Cast")]
self.path_handler["opcodes"] = [self.path_opcodes,
- desc_def("Opcodes", "Opcode",
+ desc_def("Opcodes", "Opcode",
{k:v[0] for k, v in petka.engine.OPCODES.items()})]
self.path_handler["dlgops"] = [self.path_dlgops,
desc_def("Dialog opcodes", "Dialog opcode",
@@ -160,11 +160,11 @@ class App(TkBrowser):
elif cmd == "dump":
self.dump_pages(arg)
if repath:
- self.open_path(repath)
+ self.open_path(repath)
def create_menu(self):
super().create_menu()
- def mkmenupaths(parent, items):
+ def mkmenupaths(parent, items):
for n in items:
if n is None:
parent.add_separator()
@@ -190,17 +190,17 @@ class App(TkBrowser):
self.menufile.add_separator()
self.menufile.add_command(
command = self.on_exit,
- label = "Quit")
+ label = "Quit")
self.menuedit = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menuedit,
label = "Edit")
-
- editnav = ["/parts", None, "/res", "/objs", "/scenes", "/names",
- "/invntr", "/casts", "/msgs", "/dlgs", "/opcodes", "/dlgops",
+
+ editnav = ["/parts", None, "/res", "/objs", "/scenes", "/names",
+ "/invntr", "/casts", "/msgs", "/dlgs", "/opcodes", "/dlgops",
"/strs", "/files", "/save"]
mkmenupaths(self.menuedit, editnav)
-
+
self.menunav = tkinter.Menu(self.master, tearoff = 0)
self.menubar.add_cascade(menu = self.menunav,
label = "Navigation")
@@ -247,8 +247,8 @@ class App(TkBrowser):
def open_http(self, path):
if path not in HOME_URLS:
- if not messagebox.askokcancel(parent = self, title = "Visit URL?",
- message = "Would you like to open external URL:\n" + path +
+ if not messagebox.askokcancel(parent = self, title = "Visit URL?",
+ message = "Would you like to open external URL:\n" + path +
" ?"): return
webbrowser.open(path)
@@ -265,7 +265,7 @@ class App(TkBrowser):
pass
self.master.title(capt)
return res
-
+
def on_help(self):
self.open_path(["help", self.curr_help])
@@ -299,13 +299,13 @@ class App(TkBrowser):
fmt = fmt_hl("/{}/{}".format(pref, rec_id), str(rec_id))
if full:
try:
- fmt += " (0x{:X}) - {}".format(rec_id,
+ fmt += " (0x{:X}) - {}".format(rec_id,
hlesc(self._t(lst_idx[rec_id].name, tt)))
except:
fmt += " (0x{:X})".format(rec_id)
return fmt
return "{} (0x{:X})".format(rec_id, rec_id)
-
+
def fmt_hl_res(self, resid, full = True):
if resid in self.sim.res:
lnk = fmt_hl("/res/all/{}".format(resid), resid)
@@ -313,10 +313,10 @@ class App(TkBrowser):
lnk += " (0x{:X}) - {}".format(resid,
hlesc(self.sim.res[resid]))
return lnk
-
+
def fmt_hl_obj(self, obj_id, full = False):
return self.fmt_hl_rec(self.sim.obj_idx, "objs", obj_id, full, "obj")
-
+
def fmt_hl_scene(self, scn_id, full = False):
return self.fmt_hl_rec(self.sim.scn_idx, "scenes", scn_id, full, "scn")
@@ -325,7 +325,7 @@ class App(TkBrowser):
return self.fmt_hl_rec(self.sim.obj_idx, "objs", rec_id,
full, "obj")
return self.fmt_hl_rec(self.sim.scn_idx, "scenes", rec_id, full, "scn")
-
+
def find_path_name(self, key):
for name_id, name in enumerate(self.sim.namesord):
if name == key:
@@ -358,7 +358,7 @@ class App(TkBrowser):
capt = capt or fn
fid = urllib.parse.quote_plus(fnl)
return fmt_hl("/files/{}".format(fid), capt)
-
+
def path_info_outline(self):
if self.sim is None and self.strfm is None:
self.add_info("No data loaded. Open PARTS.INI or SCRIPT.DAT first.")
@@ -366,25 +366,25 @@ class App(TkBrowser):
if self.sim:
self.add_info("Current part {} chapter {}\n\n".\
format(self.sim.curr_part, self.sim.curr_chap))
- self.add_info(" Resources: " + fmt_hl("/res",
+ self.add_info(" Resources: " + fmt_hl("/res",
len(self.sim.res)) + "\n")
- self.add_info(" Objects: " + fmt_hl("/objs",
+ self.add_info(" Objects: " + fmt_hl("/objs",
len(self.sim.objects)) + "\n")
- self.add_info(" Scenes: " + fmt_hl("/scenes",
+ self.add_info(" Scenes: " + fmt_hl("/scenes",
len(self.sim.scenes)) + "\n")
- self.add_info(" Names: " + fmt_hl("/names",
+ self.add_info(" Names: " + fmt_hl("/names",
len(self.sim.names)) + "\n")
- self.add_info(" Invntr: " + fmt_hl("/invntr",
+ self.add_info(" Invntr: " + fmt_hl("/invntr",
len(self.sim.invntr)) + "\n")
- self.add_info(" Casts: " + fmt_hl("/casts",
+ self.add_info(" Casts: " + fmt_hl("/casts",
len(self.sim.casts)) + "\n")
- self.add_info(" Messages " + fmt_hl("/msgs",
+ self.add_info(" Messages " + fmt_hl("/msgs",
len(self.sim.msgs)) + "\n")
- self.add_info(" Dialog groups: " + fmt_hl("/dlgs",
+ self.add_info(" Dialog groups: " + fmt_hl("/dlgs",
len(self.sim.dlgs)) + "\n")
- self.add_info(" Opened stores: " + fmt_hl("strs",
+ self.add_info(" Opened stores: " + fmt_hl("strs",
len(self.strfm.strfd)) + "\n")
- self.add_info(" Files: " + fmt_hl("/files",
+ self.add_info(" Files: " + fmt_hl("/files",
len(self.strfm.strtable)) + "\n")
scn = hlesc(self.sim.start_scene)
for scene in self.sim.scenes:
@@ -397,9 +397,9 @@ class App(TkBrowser):
self.add_info(" " + fmt_hl("/dlgops", "Dialog opcodes") + "\n")
elif self.strfm:
self.add_info("Single store mode\n\n")
- self.add_info(" Opened stores: " + fmt_hl("/strs",
+ self.add_info(" Opened stores: " + fmt_hl("/strs",
len(self.strfm.strfd)) + "\n")
- self.add_info(" Files: " + fmt_hl("/files",
+ self.add_info(" Files: " + fmt_hl("/files",
len(self.strfm.strtable)) + "\n")
if self.save:
self.add_info(" " + fmt_hl("/save", "Save") + "\n")
@@ -412,13 +412,13 @@ class App(TkBrowser):
fmt = fmt_dec(sz, 1)
fmt = " " + fmt + ") {}\n"
for idx, h in enumerate(self.hist[:-1]):
- self.add_info(fmt.format(idx - len(self.hist) + 1,
+ self.add_info(fmt.format(idx - len(self.hist) + 1,
self.desc_path(h[0])))
- self.add_info(" {} {}\n".format("=" * fmt_dec_len(sz, 2) + ">",
+ self.add_info(" {} {}\n".format("=" * fmt_dec_len(sz, 2) + ">",
self.desc_path(self.curr_path)))
for idx, h in enumerate(self.histf):
self.add_info(fmt.format(idx + 1, self.desc_path(h[0])))
-
+
def desc_default(self, path):
desc = ""
for item in path:
@@ -426,7 +426,7 @@ class App(TkBrowser):
if not desc:
desc = "Outline"
return desc
-
+
def path_default(self, path):
self.switch_view(0)
self.update_gui("Outline")
@@ -550,7 +550,7 @@ class App(TkBrowser):
format(part[0], part[1], hlesc(traceback.format_exc())))
return False
return True
-
+
def desc_res(self, path):
if path == ("res",):
path = ("res", "all")
@@ -580,8 +580,8 @@ class App(TkBrowser):
return self.path_default(path)
def path_res_open(self, pref, res_id, mode):
- self.curr_help = "res_view" # help override
- if res_id not in self.sim.res:
+ self.curr_help = "res_view" # help override
+ if res_id not in self.sim.res:
self.switch_view(0)
self.clear_info()
self.add_info("<b>Resource</b> \"{}\" not found\n".format(res_id))
@@ -608,7 +608,7 @@ class App(TkBrowser):
self.add_info(" Mode: {}\n Size: {}x{}".\
format(bmp.image.mode, \
bmp.image.size[0], bmp.image.size[1]))
- else:
+ else:
self.add_info("internal BMP loader\n"\
" Mode: 16-bit\n Size: {}x{}".\
format(bmp.width, bmp.height))
@@ -625,7 +625,7 @@ class App(TkBrowser):
format(flc.image.mode, \
flc.image.size[0], flc.image.size[1],
flc.frame_num, flc.image.info["duration"]))
- else:
+ else:
self.add_info("internal FLC loader\n "\
" Mode: P\n Size: {}x{}\n"\
" Frames: {}\nDelay: {}".\
@@ -644,7 +644,7 @@ class App(TkBrowser):
if ru: break
for op in act.ops:
if res_id == op.op_arg1:
- self.add_info(" " +
+ self.add_info(" " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
ru = True
break
@@ -654,12 +654,12 @@ class App(TkBrowser):
self.add_info("\n<b>Used by scenes</b>:\n")
usedby(self.sim.scenes)
self.add_info("\nFile: {}\n".format(self.fmt_hl_file(fn)))
-
-
+
+
elif mode[0] == "view":
self.path_res_view(res_id)
return True
-
+
def path_res_view(self, res_id):
fn = self.sim.res[res_id]
try:
@@ -698,7 +698,7 @@ class App(TkBrowser):
def path_res_status(self):
self.switch_view(0)
self.clear_info()
- self.add_info("<b>Resources</b>: " + fmt_hl("/res", len(self.sim.res))
+ self.add_info("<b>Resources</b>: " + fmt_hl("/res", len(self.sim.res))
+ "\nFiletypes:\n")
fts = {}
for res in self.sim.res.values():
@@ -713,10 +713,10 @@ class App(TkBrowser):
ft, ft, fts[ft]))
self.select_lb_item(None)
return True
-
+
def on_path_res_info(self):
self.switch_view(0)
-
+
def on_path_res_view(self):
self.switch_view(1)
@@ -728,7 +728,7 @@ class App(TkBrowser):
for res_id in self.sim.resord:
self.insert_lb_act("{} - {}".format(\
res_id, self.sim.res[res_id]), ["res", "all", res_id], res_id)
- # change
+ # change
if len(path) > 2:
return self.path_res_open(path[:3], path[2], path[3:])
else:
@@ -745,9 +745,9 @@ class App(TkBrowser):
self.insert_lb_act("-", None)
for res_id in lst:
self.insert_lb_act("{} - {}".format(\
- res_id, self.sim.res[res_id]), ["res", "flt", path[2], res_id],
+ res_id, self.sim.res[res_id]), ["res", "flt", path[2], res_id],
res_id)
- # change
+ # change
if len(path) > 3:
return self.path_res_open(path[:4], path[3], path[4:])
else:
@@ -770,10 +770,10 @@ class App(TkBrowser):
else:
self.update_gui("Scenes ({})".format(len(lst)))
for rec in lst:
- self.insert_lb_act("{} - {}".format(rec.idx,
+ self.insert_lb_act("{} - {}".format(rec.idx,
self._t(rec.name, "obj" if isobj else "scn")),\
[self.curr_path[0], rec.idx], rec.idx)
- # change
+ # change
rec = None
if len(path) > 1:
# index
@@ -805,49 +805,49 @@ class App(TkBrowser):
self.add_info(" Name(t): {}\n".\
format(hlesc(self._t(rec.name, "obj" if isobj else "scn"))))
if rec.name in self.sim.names:
- self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
"Alias") + "(t): {}\n".format(
hlesc(self._t(self.sim.names[rec.name], "obj"))))
if rec.name in self.sim.invntr:
- self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
+ self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
"Invntr") + "(t): {}\n".format(
hlesc(self._t(self.sim.invntr[rec.name], "inv"))))
else:
if rec.name in self.sim.names:
- self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
+ self.add_info(" " + fmt_hl(self.find_path_name(rec.name),
"Alias") + ": {}\n".format(
hlesc(self.sim.names[rec.name])))
if rec.name in self.sim.invntr:
- self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
+ self.add_info(" " + fmt_hl(self.find_path_invntr(rec.name),
"Invntr") + ": {}\n".format(
hlesc(self.sim.invntr[rec.name])))
if rec.cast:
bg = 0
- r = rec.cast[0]
+ r = rec.cast[0]
g = rec.cast[1]
b = rec.cast[2]
- if (r + g * 2 + b) // 3 < 160:
+ if (r + g * 2 + b) // 3 < 160:
bg = 255
- self.add_info(" " + fmt_hl(self.find_path_cast(rec.name),
+ self.add_info(" " + fmt_hl(self.find_path_cast(rec.name),
"Cast") + ": <font bg=\"#{bg:02x}{bg:02x}{bg:02x}\">"
"<font color=\"#{r:02x}{g:02x}{b:02x}\">"\
"<b> #{r:02x}{g:02x}{b:02x} </b></font></font>\n".\
format(bg = bg, r = r, g = g, b = b))
-
- # references / backreferences
+
+ # references / backreferences
if isobj:
# search where object used
self.add_info("\n<b>Refered by scenes</b>:\n")
for scn in self.sim.scenes:
for ref in scn.refs:
if ref[0].idx == rec.idx:
- self.add_info(" " +
+ self.add_info(" " +
self.fmt_hl_scene(scn.idx, True) + "\n")
break
else:
if rec.refs is None:
self.add_info("\nNo references\n")
- else:
+ else:
if len(rec.refs) == 0:
self.add_info("\nEmpty references\n")
else:
@@ -855,7 +855,7 @@ class App(TkBrowser):
format(len(rec.refs)))
fmtd = " " + fmt_dec(len(rec.refs)) + ") "
for idx, ref in enumerate(rec.refs):
- self.add_info(fmtd.format(idx) +
+ self.add_info(fmtd.format(idx) +
self.fmt_hl_obj(ref[0].idx))
msg = ""
for arg in ref[1:]:
@@ -866,7 +866,7 @@ class App(TkBrowser):
msg += "-1"
else:
msg += "0x{:X}".format(arg)
- self.add_info(msg + self.fmt_cmt(" // " +
+ self.add_info(msg + self.fmt_cmt(" // " +
self.fmt_hl_obj(ref[0].idx, True)) + "\n")
resused = []
@@ -916,7 +916,7 @@ class App(TkBrowser):
if op.op_code == 0x11: # DIALOG
if op.op_ref not in dlgused:
dlgused.append(op.op_ref)
-
+
if len(resused) > 0:
self.add_info("\n<b>Used resources</b>: {}\n".\
format(len(resused)))
@@ -928,7 +928,7 @@ class App(TkBrowser):
for grp_id in dlgused:
self.add_info(" " + self.fmt_hl_dlg(grp_id, True)+ "\n")
- # messages used by this object
+ # messages used by this object
if isobj:
wasmsg = False
for msg in self.sim.msgs:
@@ -958,16 +958,16 @@ class App(TkBrowser):
if k not in oplst: continue
self.add_info("\n<b>Used in " + self.fmt_opcode(k) + "</b>:\n")
for oid, htp, hid in oplst[k]:
- self.add_info(" " + self.fmt_hl_obj_scene(oid) +
- " on " + self.fmt_opcode(htp) +
- " #{}".format(hid) + self.fmt_cmt(" // " +
+ self.add_info(" " + self.fmt_hl_obj_scene(oid) +
+ " on " + self.fmt_opcode(htp) +
+ " #{}".format(hid) + self.fmt_cmt(" // " +
self.fmt_hl_obj_scene(oid, True)) + "\n")
# perspective
if not isobj and rec.persp:
self.add_info("\n<b>Perspective</b>:\n {}, {}, {}, {}, {}\n".
format(*rec.persp))
-
+
# enter areas
if not isobj and rec.entareas:
self.add_info("\n<b>Enter areas</b>: {}\n".format(
@@ -978,8 +978,8 @@ class App(TkBrowser):
self.add_info(" <i>on</i>: {}\n".format(
self.fmt_hl_obj(oo.idx, True)))
return True
-
- def path_std_items(self, path, level, guiname, guiitem, tt, lst, lst_idx,
+
+ def path_std_items(self, path, level, guiname, guiitem, tt, lst, lst_idx,
lbmode, cb):
self.switch_view(0)
if self.last_path[:level] != path[:level]:
@@ -1008,7 +1008,7 @@ class App(TkBrowser):
# info
cb(name)
return True
-
+
def path_names(self, path):
if self.sim is None:
return self.path_default([])
@@ -1026,9 +1026,9 @@ class App(TkBrowser):
for obj in self.sim.objects:
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
- return self.path_std_items(path, 1, "Names", "name", "obj",
+ return self.path_std_items(path, 1, "Names", "name", "obj",
self.sim.names, self.sim.namesord, 0, info)
-
+
def path_invntr(self, path):
if self.sim is None:
return self.path_default([])
@@ -1046,7 +1046,7 @@ class App(TkBrowser):
for obj in self.sim.objects:
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
- return self.path_std_items(path, 1, "Invntr", "invntr", "obj",
+ return self.path_std_items(path, 1, "Invntr", "invntr", "obj",
self.sim.invntr, self.sim.invntrord, 0, info)
def path_casts(self, path):
@@ -1075,7 +1075,7 @@ class App(TkBrowser):
for idx, obj in enumerate(self.sim.objects):
if obj.name == name:
self.add_info(" " + self.fmt_hl_obj(obj.idx, True) + "\n")
- return self.path_std_items(path, 1, "Cast", "cast", "obj",
+ return self.path_std_items(path, 1, "Cast", "cast", "obj",
self.sim.casts, self.sim.castsord, 0, info)
def path_msgs(self, path):
@@ -1118,7 +1118,7 @@ class App(TkBrowser):
lst.sort()
fmtlen = fmt_dec_len(len(lst))
for _, wav, idx, capt in lst:
- self.add_info(" " + fmt_hl_len("/msgs/{}".format(idx),
+ self.add_info(" " + fmt_hl_len("/msgs/{}".format(idx),
"{}".format(idx), fmtlen))
self.add_info(" - {} - {}\n".format(
self.fmt_hl_file("speech{}/{}".format(
@@ -1129,7 +1129,7 @@ class App(TkBrowser):
self.add_info(" wav: {}\n".
format(self.fmt_hl_file("speech{}/{}".format(
self.sim.curr_part, msg.msg_wav), msg.msg_wav)))
- self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx,
+ self.add_info(" object: " + self.fmt_hl_obj(msg.obj.idx,
True) + "\n")
self.add_info(" arg2: {a} (0x{a:X})\n".format(
a = msg.msg_arg2))
@@ -1146,9 +1146,9 @@ class App(TkBrowser):
for op in dlg.ops:
if not op.msg: continue
if op.msg.idx == msg.idx and op.opcode == 7:
- self.add_info(" " +
+ self.add_info(" " +
self.fmt_hl_dlg(grp.idx, True) + "\n")
-
+
if self.last_path[:1] != ("msgs",):
self.update_gui("Messages ({})".format(len(self.sim.msgs)))
for idx, msg in enumerate(self.sim.msgs):
@@ -1159,7 +1159,7 @@ class App(TkBrowser):
capt = capt[:40] + "|"
self.insert_lb_act("{} - {}".format(msg.idx, capt),
["msgs", idx], idx)
- self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
+ self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
"msgs.sort", {0: "wav", 1: "order", 2: "text"}, upd_msgs)
# change
upd_msgs()
@@ -1205,14 +1205,14 @@ class App(TkBrowser):
fmtga = " " + fmt_dec(len(grp.acts)) + \
") <u>on {} {} 0x{:X} 0x{:X}</u>, dlgs: {}{}\n"
for idx, act in enumerate(grp.acts):
- self.add_info(fmtga.format(idx, self.fmt_opcode(act.opcode),
+ self.add_info(fmtga.format(idx, self.fmt_opcode(act.opcode),
self.fmt_hl_obj(act.ref), act.arg1, act.arg2, \
- len(act.dlgs), self.fmt_cmt(" // " +
+ len(act.dlgs), self.fmt_cmt(" // " +
self.fmt_hl_obj(act.ref, True))))
fmtad = " " + fmt_dec(len(act.dlgs)) + \
") <i>0x{:X} 0x{:X}</i>, ops: {}\n"
for didx, dlg in enumerate(act.dlgs):
- self.add_info(fmtad.format(didx, dlg.arg1, dlg.arg2,
+ self.add_info(fmtad.format(didx, dlg.arg1, dlg.arg2,
len(dlg.ops)))
# scan for used adreses
usedadr = []
@@ -1287,9 +1287,9 @@ class App(TkBrowser):
opref = self.fmt_hl_msg(op.ref)
objref = self.fmt_hl_obj(op.msg.obj.idx)
cmt = self.fmt_cmt(" // obj={}, msg={}".\
- format(objref,
+ format(objref,
self.fmt_hl_msg(op.ref, True)))
-
+
oparg = " 0x{:X} ".format(op.arg)
if (op.opcode == 0x1 or op.opcode == 0x6) and \
op.arg == 0 and op.ref == 0:
@@ -1306,7 +1306,7 @@ class App(TkBrowser):
if not hdr:
self.add_info(hl)
hdr = True
- self.add_info(" linked " +
+ self.add_info(" linked " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
continue
ru = False
@@ -1314,11 +1314,11 @@ class App(TkBrowser):
if ru: break
for op in act.ops:
if op.op_code == 0x11 and \
- op.op_ref == grp.idx: # DIALOG
+ op.op_ref == grp.idx: # DIALOG
if not hdr:
self.add_info(hl)
hdr = True
- self.add_info(" " +
+ self.add_info(" " +
self.fmt_hl_obj_scene(rec.idx, True) + "\n")
ru = True
break
@@ -1327,7 +1327,7 @@ class App(TkBrowser):
usedby(self.sim.objects, "\n<b>Used by objects</b>:\n")
usedby(self.sim.scenes, "\n<b>Used by scenes</b>:\n")
return True
-
+
def path_opcodes(self, path):
if self.sim is None:
return self.path_default([])
@@ -1344,7 +1344,7 @@ class App(TkBrowser):
if act.act_op not in keys:
keys.append(act.act_op)
for op in act.ops:
- opstat[op.op_code] = opstat.get(op.op_code,
+ opstat[op.op_code] = opstat.get(op.op_code,
0) + 1
if op.op_code not in keys:
keys.append(op.op_code)
@@ -1360,7 +1360,7 @@ class App(TkBrowser):
keys, opstat, acstat, dastat = keyslist()
self.update_gui("Opcodes ({})".format(len(keys)))
for key in keys:
- self.insert_lb_act("{} - {}".format(key, self.fmt_opcode(key,
+ self.insert_lb_act("{} - {}".format(key, self.fmt_opcode(key,
True)), ["opcodes", key], key)
# change
opcode = None
@@ -1390,7 +1390,7 @@ class App(TkBrowser):
mcnt = len(msg)
msg += " - {}".format(fmt_hl("/opcodes/{}".format(
key), opname))
- mcnt += len(self.fmt_opcode(key, True))
+ mcnt += len(self.fmt_opcode(key, True))
while mcnt < 23:
msg += " "
mcnt += 1
@@ -1420,43 +1420,43 @@ class App(TkBrowser):
# display
if len(ops) == 0:
self.add_info("<i>Not used in scripts</i>\n\n")
- else:
+ else:
self.add_info("<i>Used in scripts</i>: {}\n".format(len(ops)))
fmtops = " " + fmt_dec(len(ops)) + \
") obj={}, act={}, op={} {}\n"
for idx, (obj_idx, aidx, oidx) in enumerate(ops):
self.add_info(fmtops.format(
idx, self.fmt_hl_obj_scene(obj_idx, False), aidx, oidx,
- self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
+ self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
True))))
- self.add_info("\n")
+ self.add_info("\n")
if len(acts) == 0:
self.add_info("<i>Not used in handlers</i>\n\n")
- else:
+ else:
self.add_info("<i>Used in handlers</i>: {}\n".format(len(acts)))
fmtacts = " " + fmt_dec(len(acts)) + \
") obj={}, act={} {}\n"
for idx, (obj_idx, aidx) in enumerate(acts):
self.add_info(fmtacts.format(
- idx, self.fmt_hl_obj_scene(obj_idx, False), aidx,
- self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
+ idx, self.fmt_hl_obj_scene(obj_idx, False), aidx,
+ self.fmt_cmt("// " + self.fmt_hl_obj_scene(obj_idx,
True))))
- self.add_info("\n")
+ self.add_info("\n")
if len(dacts) == 0:
self.add_info("<i>Not used in dialog handlers</i>\n\n")
- else:
+ else:
self.add_info("<i>Used in dialog handlers</i>: {}\n".format(
len(dacts)))
fmtdacts = " " + fmt_dec(len(dacts)) + \
") obj={}, group=<a href=\"/dlgs/{}\">{}</a>, act={} {}\n"
for idx, (obj_idx, gidx, aidx) in enumerate(dacts):
self.add_info(fmtdacts.format(
- idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
+ idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
aidx, self.fmt_cmt("// " + self.fmt_hl_obj_scene(
obj_idx, True))))
- self.add_info("\n")
+ self.add_info("\n")
return True
def path_dlgops(self, path):
@@ -1481,7 +1481,7 @@ class App(TkBrowser):
keys, dlstat = keyslist()
self.update_gui("Dialog opcodes ({})".format(len(keys)))
for key in keys:
- self.insert_lb_act("{} - {}".format(key, self.fmt_dlgop(key,
+ self.insert_lb_act("{} - {}".format(key, self.fmt_dlgop(key,
True)), ["dlgops", key], key)
# change
opcode = None
@@ -1510,7 +1510,7 @@ class App(TkBrowser):
mcnt = len(msg)
msg += " - {}".format(fmt_hl("/dlgops/{}".format(
key), opname))
- mcnt += len(self.fmt_dlgop(key, True))
+ mcnt += len(self.fmt_dlgop(key, True))
while mcnt < 20:
msg += " "
mcnt += 1
@@ -1530,19 +1530,19 @@ class App(TkBrowser):
# display
if len(dls) == 0:
self.add_info("<i>Not used in dialogs</i>\n\n")
- else:
+ else:
self.add_info("<i>Used in dialogs</i>: {}\n".format(len(dls)))
fmtdls = " " + fmt_dec(len(dls)) + \
") obj={}, group=<a href=\"/dlgs/{}\">{}" + \
"</a>, act={}, dlg={}, op={} {}\n"
for idx, (obj_idx, gidx, aidx, didx, oidx) in enumerate(dls):
self.add_info(fmtdls.format(
- idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
- aidx, didx, oidx, self.fmt_cmt("// " +
+ idx, self.fmt_hl_obj_scene(obj_idx, False), gidx, gidx,
+ aidx, didx, oidx, self.fmt_cmt("// " +
self.fmt_hl_obj_scene(obj_idx, True))))
- self.add_info("\n")
+ self.add_info("\n")
return True
-
+
def path_stores(self, path):
if self.strfm is None:
return self.path_default([])
@@ -1585,7 +1585,7 @@ class App(TkBrowser):
if len(strlst):
flnk = self.fmt_hl_file(strlst[0][0], flnk)
self.add_info(" Files: {}, Tag: {}\n\n".format(flnk, tag))
-
+
lst = []
for idx, (fname, _, _, _) in enumerate(strlst):
if sm == 0:
@@ -1596,9 +1596,9 @@ class App(TkBrowser):
lst.sort()
fmt = " " + fmt_dec(len(lst)) + ") {}\n"
for _, idx, fname in lst:
- self.add_info(fmt.format(idx + 1,
+ self.add_info(fmt.format(idx + 1,
self.fmt_hl_file(fname)))
-
+
self.switch_view(0)
keys = None
if self.last_path[:1] != ("strs",):
@@ -1618,7 +1618,7 @@ class App(TkBrowser):
return
# extract to folder
sdir = filedialog.askdirectory(parent = self,
- title = "Select folder for extract",
+ title = "Select folder for extract",
initialdir = self.strfm.root, mustexist = True)
if not sdir: return
# extract store to sdir
@@ -1644,7 +1644,7 @@ class App(TkBrowser):
format(hlesc(fname), hlesc(traceback.format_exc())))
return
self.curr_state["btnext"] = self.add_toolbtn("Extract STR", ext_str)
- self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
+ self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
"strs.sortfiles", {0: "order", 1: "filename"}, upd_strs)
upd_strs()
return True
@@ -1698,7 +1698,7 @@ class App(TkBrowser):
format(hlesc(fnl)))
return
self.add_info("<b>File</b>: {}\n\n".format(fnl))
-
+
# search in loaded stores
if fnl in self.strfm.strtable:
# in store
@@ -1720,7 +1720,7 @@ class App(TkBrowser):
self.add_info("\n<b>Used in resources</b>:\n")
wascapt = True
self.add_info(" {} - <a href=\"/res/all/{}\">"\
- "{}</a>\n".format(resid, resid,
+ "{}</a>\n".format(resid, resid,
hlesc(self.sim.res[resid])))
wavpref = "speech{}/".format(self.sim.curr_part)
if fnl[-4:] == ".wav" and fnl.startswith(wavpref):
@@ -1780,9 +1780,9 @@ class App(TkBrowser):
if sa:
self.add_info("\n<b>See also</b>:\n")
for p in sa:
- self.add_info(" " + fmt_hl(p, self.desc_path(p))
+ self.add_info(" " + fmt_hl(p, self.desc_path(p))
+ "\n")
-
+
if fnl[-4:] in [".leg", ".off"]:
legf = petka.LEGLoader()
legf.load_data(self.strfm.read_file_stream(fnl))
@@ -1791,7 +1791,7 @@ class App(TkBrowser):
fmt = " " + fmt_dec(len(legf.coords)) + ") {}, {}\n"
for idx, (x, y) in enumerate(legf.coords):
self.add_info(fmt.format(idx + 1, x, y))
-
+
if fnl[-4:] == ".msk":
mskf = petka.MSKLoader()
mskf.load_data(self.strfm.read_file_stream(fnl))
@@ -1806,7 +1806,7 @@ class App(TkBrowser):
fmtr = " " + fmt_dec(len(rs)) + ") {}, {} - {}, {}\n"
for idxr, r in enumerate(rs):
self.add_info(fmtr.format(idxr + 1, *r))
-
+
if fnl[-4:] == ".flc":
flcf = petka.FLCLoader()
flcf.load_info(self.strfm.read_file_stream(fnl))
@@ -1818,13 +1818,13 @@ class App(TkBrowser):
format(flcf.image.mode, \
flcf.image.size[0], flcf.image.size[1],
flcf.frame_num, flcf.image.info["duration"]))
- else:
+ else:
self.add_info("\n<b>FLC data</b> (internal)\n")
self.add_info(" Mode: P\n Size: {}x{}\n"\
" Frames: {}\nDelay: {}".\
format(flcf.width, flcf.height, \
flcf.frame_num, flcf.delay))
-
+
self.switch_view(0)
keys = None
if self.last_path[:1] != ("files",):
@@ -1834,7 +1834,7 @@ class App(TkBrowser):
fnl = fn.lower().replace("\\", "/")
fnl = urllib.parse.quote_plus(fnl)
self.insert_lb_act(fn, ["files", fnl], fnl)
- self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
+ self.curr_state["btnsort"] = self.add_toolgrp("Sort by",
"files.sort", {0: "order", 1: "filename"}, upd_files)
upd_files()
return True
@@ -1842,7 +1842,7 @@ class App(TkBrowser):
def path_save(self, path):
if self.sim is None:
return self.path_default([])
-
+
def upd_save():
path = self.curr_path
fid = None
@@ -1850,7 +1850,7 @@ class App(TkBrowser):
if self.save is None:
self.add_info("<b>Saved state</b>: not loaded\n\n")
return
-
+
if path == ("save",):
path = ("save", "info")
if path[1] == "shot":
@@ -1870,24 +1870,24 @@ class App(TkBrowser):
self.add_info(" cursor: {} - {}\n".format(self.save.cursor,
petka.ACTIONS.get(self.save.cursor, ["ACT{:2X}".format(
self.save.cursor), 0])[0]))
- self.add_info(" " + self.fmt_hl_res(self.save.cursor_res,
+ self.add_info(" " + self.fmt_hl_res(self.save.cursor_res,
True) + "\n")
if self.save.cursor_obj == 0xffffffff:
self.add_info(" object: <i>none</i>\n")
else:
self.add_info(" object: " + self.fmt_hl_obj(
self.save.cursor_obj, True) + "\n")
- self.add_info(" char 1: {}, {} ".format(self.save.char1[0],
+ self.add_info(" char 1: {}, {} ".format(self.save.char1[0],
self.save.char1[1]) + self.fmt_hl_res(
self.save.char1[2], True) + "\n")
- self.add_info(" char 2: {}, {} ".format(self.save.char2[0],
+ self.add_info(" char 2: {}, {} ".format(self.save.char2[0],
self.save.char2[1]) + self.fmt_hl_res(
self.save.char2[2], True) + "\n")
-
+
self.add_info(" invntr: {}\n".format(len(self.save.invntr)))
fmt = " " + fmt_dec(len(self.save.invntr)) + ") "
for idx, inv in enumerate(self.save.invntr):
- self.add_info(fmt.format(idx + 1) +
+ self.add_info(fmt.format(idx + 1) +
self.fmt_hl_obj_scene(inv, True) + "\n")
self.add_info("\n objects: {}\n".format(len(
@@ -1895,7 +1895,7 @@ class App(TkBrowser):
fmt = " " + fmt_dec(len(self.save.objects)) + ") \"{}\" {}\n"
for idx, obj in enumerate(self.save.objects):
- self.add_info(fmt.format(idx + 1, obj["name"],
+ self.add_info(fmt.format(idx + 1, obj["name"],
obj["alias"]))
fndobj = None
for sobj in self.sim.objects + self.sim.scenes:
@@ -1903,12 +1903,12 @@ class App(TkBrowser):
fndobj = sobj
break
if fndobj:
- self.add_info(" " +
+ self.add_info(" " +
self.fmt_hl_obj_scene(fndobj.idx, True) + "\n")
self.add_info(" {}, {}, {}, {}, {}, {}, {}, {}, {}\n".
format(*obj["recs"]))
if obj["res"] in self.sim.res:
- self.add_info(" " + self.fmt_hl_res(obj["res"],
+ self.add_info(" " + self.fmt_hl_res(obj["res"],
True) + "\n")
elif path[1] == "dlgops":
self.clear_info()
@@ -1920,7 +1920,7 @@ class App(TkBrowser):
self.add_info(fmt.format(idx + 1, self.fmt_dlgop(code), arg, ref))
else:
self.select_lb_item("info")
-
+
if self.last_path[:1] != ("save",):
# calc statistics
self.update_gui("Save")
@@ -1964,7 +1964,7 @@ class App(TkBrowser):
self.add_info("<i>no tranlation file</i>\n")
else:
self.add_info(hlesc(self.tran_fn) + "\n")
-
+
self.add_info("<b>Engine</b>: ")
if not self.sim:
self.add_info("<i>not initialized</i>\n")
@@ -1997,14 +1997,14 @@ class App(TkBrowser):
self.path_info_outline()
return True
-
+
def desc_help(self, path):
if path == ("help",):
path = ("help", "index")
if path == ("help", "index"):
return "Index"
return "Help for " + self.desc_path(path[1])
-
+
def path_help(self, path):
self.switch_view(0)
if path == ("help",):
@@ -2019,16 +2019,16 @@ class App(TkBrowser):
item = item.decode("UTF-8").strip()
if not item: continue
try:
- hf = open(os.path.join(self.app_path,
+ hf = open(os.path.join(self.app_path,
"help", item + ".txt"), "rb")
try:
for line in hf.readlines():
- line = line.decode("UTF-8").strip()
+ line = line.decode("UTF-8").strip()
break
finally:
hf.close()
except:
- line = item
+ line = item
self.insert_lb_act(line, ["help", item], item)
finally:
f.close()
@@ -2046,10 +2046,10 @@ class App(TkBrowser):
hf = open(hfn, "rb")
try:
for idx, line in enumerate(hf.readlines()):
- line = line.decode("UTF-8").rstrip()
+ line = line.decode("UTF-8").rstrip()
if idx == 0:
self.add_info("<b>" + line + "</b>\n")
- else:
+ else:
self.add_info(line + "\n")
finally:
hf.close()
@@ -2060,7 +2060,7 @@ class App(TkBrowser):
self.select_lb_item(None)
return True
-
+
def path_info(self, path):
self.switch_view(0)
if self.last_path[:1] != ("info",):
@@ -2088,7 +2088,7 @@ class App(TkBrowser):
k.sort()
for key in k:
self.add_info(" {} (0x{:X}) - {}\n".format(key, key,
- petka.OPCODES[key][0]))
+ petka.OPCODES[key][0]))
elif name == "dlgops":
self.add_info("<b>Dialog opcodes<b>\n\n")
k = list(petka.DLGOPS.keys())
@@ -2103,9 +2103,9 @@ class App(TkBrowser):
for key in k:
self.add_info(" {} (0x{:X}) - {}\n".format(key, key,
petka.ACTIONS[key][0]))
- self.add_info(" " +
+ self.add_info(" " +
self.fmt_hl_res(petka.ACTIONS[key][1]) + "\n")
- else:
+ else:
self.add_info("Unknown data type \"{}\"\n".format(hlesc(name)))
return True
@@ -2113,7 +2113,7 @@ class App(TkBrowser):
def on_open_data(self):
ft = [\
('all files', '.*')]
- fn = filedialog.askopenfilename(parent = self,
+ fn = filedialog.askopenfilename(parent = self,
title = "Open PARTS.INI or SCRIPT.DAT",
filetypes = ft,
initialdir = os.path.abspath(os.curdir))
@@ -2123,7 +2123,7 @@ class App(TkBrowser):
if self.open_data_from(os.path.dirname(fn)):
self.open_path("")
self.clear_hist()
-
+
def open_data_from(self, folder):
self.last_fn = folder
self.clear_data()
@@ -2146,7 +2146,7 @@ class App(TkBrowser):
ft = [\
('STR files', '.STR'),
('all files', '.*')]
- fn = filedialog.askopenfilename(parent = self,
+ fn = filedialog.askopenfilename(parent = self,
title = "Open STR file",
filetypes = ft,
initialdir = os.path.abspath(os.curdir))
@@ -2176,7 +2176,7 @@ class App(TkBrowser):
ft = [\
('Save files (*.dat)', '.DAT'),
('all files', '.*')]
- fn = filedialog.askopenfilename(parent = self,
+ fn = filedialog.askopenfilename(parent = self,
title = "Open SAVEx.DAT file",
filetypes = ft,
initialdir = os.path.abspath(os.curdir))
@@ -2190,21 +2190,21 @@ class App(TkBrowser):
self.switch_view(0)
self.update_gui("")
self.clear_info()
- self.add_info("Open data before loading saves")
+ self.add_info("Open data before loading saves")
return
self.save = None
try:
self.last_savefn = fn
self.save = petka.SaveLoader("cp1251")
with open(fn, "rb") as f:
- self.save.load_data(f, self.sim.curr_part,
+ self.save.load_data(f, self.sim.curr_part,
len(self.sim.objects) + len(self.sim.scenes))
if self.save.part != self.sim.curr_part:
# load
print("DEBUG: change part {}".format(self.save.part))
self.sim.open_part(self.save.part, 0)
f.seek(0)
- self.save.load_data(f, self.sim.curr_part,
+ self.save.load_data(f, self.sim.curr_part,
len(self.sim.objects) + len(self.sim.scenes))
return True
except:
@@ -2215,18 +2215,18 @@ class App(TkBrowser):
self.clear_info()
self.add_info("Error opening \"{}\" \n\n{}".\
format(hlesc(fn), hlesc(traceback.format_exc())))
-
+
def on_tran_save(self):
self.on_tran_save_real()
def on_tran_save_tlt(self):
self.on_tran_save_real(True)
-
+
def on_tran_save_real(self, tlt = False):
# save dialog
fn = filedialog.asksaveasfilename(parent = self,
- title = "Save translate template (.pot)" +
+ title = "Save translate template (.pot)" +
" (transliterate)" if tlt else "",
filetypes = [('PO Template', ".pot"), ('all files', '.*')],
initialdir = os.path.abspath(os.curdir))
@@ -2248,19 +2248,19 @@ class App(TkBrowser):
ts = translit(text)
entry = polib.POEntry(
msgid = text, msgstr = ts, comment = cmt)
- po.append(entry)
+ po.append(entry)
for rec in self.sim.objects:
saveitem(rec.name, "obj_{}".format(rec.idx))
for rec in self.sim.scenes:
saveitem(rec.name, "scn_{}".format(rec.idx))
for idx, name in enumerate(self.sim.namesord):
- saveitem(self.sim.names[name],
+ saveitem(self.sim.names[name],
"name_{}, {}".format(idx, name))
for idx, name in enumerate(self.sim.invntrord):
saveitem(self.sim.invntr[name],
"inv_{}, {}".format(idx, name))
for idx, msg in enumerate(self.sim.msgs):
- saveitem(msg.name,
+ saveitem(msg.name,
"msg_{}, {} - {}".format(idx, msg.obj.idx, msg.obj.name))
po.save(fn)
except:
@@ -2273,14 +2273,14 @@ class App(TkBrowser):
ft = [\
('PO files', '.po'),
('all files', '.*')]
- fn = filedialog.askopenfilename(parent = self,
+ fn = filedialog.askopenfilename(parent = self,
title = "Open translation for current part",
filetypes = ft,
initialdir = os.path.abspath(os.curdir))
if not fn: return
os.chdir(os.path.dirname(fn))
self.open_tran_from(fn)
-
+
def open_tran_from(self, fn):
self.tran_fn = fn
try:
@@ -2307,7 +2307,7 @@ class App(TkBrowser):
self.switch_view(0)
self.clear_info()
self.add_info("No messages or translations loaded")
- return
+ return
fn = filedialog.asksaveasfilename(parent = self,
title = "Save DIALOGUE.LOD",
filetypes = [('DIALOGUE.LOD', ".lod"), ('all files', '.*')],
@@ -2318,7 +2318,7 @@ class App(TkBrowser):
sim2 = petka.Engine()
sim2.init_empty("cp1251")
for msg in self.sim.msgs:
- nmsg = petka.engine.MsgObject(msg.idx, msg.msg_wav,
+ nmsg = petka.engine.MsgObject(msg.idx, msg.msg_wav,
msg.msg_arg1, msg.msg_arg2, msg.msg_arg3)
nmsg.name = self._t(msg.name, "msg")
sim2.msgs.append(nmsg)
@@ -2340,7 +2340,7 @@ class App(TkBrowser):
self.switch_view(0)
self.clear_info()
self.add_info("No messages or translations loaded")
- return
+ return
fn = filedialog.asksaveasfilename(parent = self,
title = "Save NAMES.INI",
filetypes = [('NAMES.INI', ".ini"), ('all files', '.*')],
@@ -2367,7 +2367,7 @@ class App(TkBrowser):
print("Dumping pages")
import json
import urllib
-
+
def normalize_link(dest):
self.dumpaddr = None
def open_path(path):
@@ -2387,8 +2387,8 @@ class App(TkBrowser):
self.open_path = orig
elif isinstance(dest, (list, tuple)):
dest = "/" + "/".join([str(x) for x in dest])
- return dest
-
+ return dest
+
def normalize_link_html(dest, curr):
lnk = normalize_link(dest)
if lnk[:1] == "/":
@@ -2397,7 +2397,7 @@ class App(TkBrowser):
if rel == ".":
return rel
return rel + ".html"
-
+
def save_data(fn, data, outline):
print(" save " + fn)
if not os.path.exists(path):
@@ -2453,28 +2453,28 @@ class App(TkBrowser):
f.write("</pre>\n")
f.write("</td></tr><table>\n")
- f.write("</body></html>\n")
-
+ f.write("</body></html>\n")
+
def save_curr():
fn = "/".join([str(x) for x in self.curr_path])
fn = os.path.join(path, fn)
if not os.path.exists(os.path.dirname(fn)):
os.makedirs(os.path.dirname(fn))
- save_data(fn, self.text_view.dump("0.0", "end-1c"),
+ save_data(fn, self.text_view.dump("0.0", "end-1c"),
self.curr_lb_acts)
-
+
parsed = []
queue = []
def addaddr(dest):
lnk = normalize_link(dest)
if lnk not in parsed + queue:
queue.append(lnk)
-
+
def scan_page(dest):
print(" scan " + str(dest))
if dest.startswith("/parts/"): return # avoid changing part
if dest.startswith("/files/"): return # avoid too big files data
- #if dest.startswith("/res/"): return
+ #if dest.startswith("/res/"): return
if dest in parsed:
return
parsed.append(dest)
@@ -2500,7 +2500,7 @@ class App(TkBrowser):
addr = queue[0]
queue = queue[1:]
scan_page(addr)
-
+
def main():
root = tkinter.Tk()
@@ -2527,6 +2527,6 @@ def main():
argv = argv[1:]
app.mainloop()
-
+
if __name__ == "__main__":
main()
diff --git a/engines/petka/p12script.py b/engines/petka/p12script.py
index 107e272c7..389c96cc0 100755
--- a/engines/petka/p12script.py
+++ b/engines/petka/p12script.py
@@ -29,7 +29,7 @@ def find_in_folder(folder, name, ifnot = True):
class P12Compiler:
def __init__(self):
pass
-
+
# =======================================================================
# compiler utils
# =======================================================================
@@ -62,7 +62,7 @@ class P12Compiler:
nitemesc = False
continue
nitem += ch
- else:
+ else:
if ch == "\"":
nmode = 1
elif ch == "#":
@@ -76,9 +76,9 @@ class P12Compiler:
if len(nitem) > 0:
nline.append(nitem)
-
+
yield lineno, nline
-
+
def check8(self, value, name, lineno):
if value == -1:
@@ -90,7 +90,7 @@ class P12Compiler:
raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
"big - {} > 0xff".format(lineno, name, value))
return value
-
+
def check16(self, value, name, lineno):
if value == -1:
return 0xffff
@@ -112,7 +112,7 @@ class P12Compiler:
raise ScriptSyntaxError("Error at {}: value for \"{}\" too "\
"big - {} > 0xffffffff".format(lineno, name, value))
return value
-
+
def convertnum(self, value):
num = None
if value[:2].upper() == "0X":
@@ -120,7 +120,7 @@ class P12Compiler:
num = int(value[2:], 16)
except:
pass
- else:
+ else:
try:
num = int(value, 10)
except:
@@ -133,7 +133,7 @@ class P12Compiler:
"already used at line {}".format(lineno, ident, \
self.usedid[ident][0]))
self.usedid[ident] = [lineno, None]
-
+
def setidentvalue(self, ident, value):
if self.usedid[ident][1] is None:
self.usedid[ident][1] = value
@@ -141,10 +141,10 @@ class P12Compiler:
raise ScriptSyntaxError("Redefine value for \"{}\" ({}) from "\
"\"{}\" to \"{}\"".format(ident, self.usedid[ident][0], \
self.usedid[ident][0], value))
-
+
def getidentvalue(self, ident):
return self.usedid[ident][1]
-
+
def checkident(self, ident, name, lineno):
if ident.upper() in self.reservedid:
raise ScriptSyntaxError("Error at {}: identificator \"{}\" "\
@@ -190,7 +190,7 @@ class P12Compiler:
pe = petka.Engine()
pe.init_empty("cp1251")
-
+
mode = 0 # 0 - common, 1 - object/scene, 2 - on
mode1tp = None
@@ -208,7 +208,7 @@ class P12Compiler:
compitemused = {}
# current action
compact = None
-
+
revOPS = {}
for ok, ov in petka.OPCODES.items():
revOPS[ov[0]] = ok
@@ -259,7 +259,7 @@ class P12Compiler:
else:
raise ScriptSyntaxError("Error at {}: unknown syntax "\
"\"{}\"".format(lineno, cmd))
- elif mode == 1:
+ elif mode == 1:
# accept: REF, ON, ENDOBJ, ENDSCENE
cmd = tokens[0].upper()
if cmd == "REF" and mode1tp == "SCENE":
@@ -307,9 +307,9 @@ class P12Compiler:
mode = 2
elif cmd == "END" + mode1tp and len(tokens) == 1:
if mode1tp == "OBJ":
- compobj.append(compitem)
+ compobj.append(compitem)
else:
- compscene.append(compitem)
+ compscene.append(compitem)
compitem = None
# return
mode = 0
@@ -322,7 +322,7 @@ class P12Compiler:
cmd = tokens[0].upper()
if cmd == "ENDON" and len(tokens) == 1:
compitem["acts"].append(compact)
- compact = None
+ compact = None
mode = 1
else:
# check format
@@ -352,7 +352,7 @@ class P12Compiler:
if mode != 0:
raise ScriptSyntaxError("Error at {}: unfinished structure".\
format(lineno))
-
+
# second stage - RES
# 1. capture res with numbers
resused = {}
@@ -384,7 +384,7 @@ class P12Compiler:
# else:
# self.setidentvalue(ident, num)
# resused[num] = lineno
- # break
+ # break
# if autoresnum <= 0:
# raise ScriptSyntaxError("Error at {}: out of resources "\
# "number".format(lineno))
@@ -404,7 +404,7 @@ class P12Compiler:
if destfolder is not None:
f.close()
print("RESOURCE.QRC saved: {} items".format(len(resused)))
-
+
# second stage - OBJ
def makerec(citem):
item = petka.engine.ScrObject(citem["num"], citem["name"])
@@ -416,14 +416,14 @@ class P12Compiler:
sonref = self.convertnum(act["sonref"])
if sonref is not None:
# direct number
- sonref = self.check16(sonref, "ON object ref",
+ sonref = self.check16(sonref, "ON object ref",
act["lineno"])
else:
# get by ident
self.checkident(act["sonref"], "ON object ref",
act["lineno"])
sonref = self.getidentvalue(act["sonref"])
- onrec = petka.engine.ScrActObject(act["son"],
+ onrec = petka.engine.ScrActObject(act["son"],
act["status"], sonref)
onrec.ops = []
for op in act["ops"]:
@@ -446,17 +446,17 @@ class P12Compiler:
fmt.append(("OP argument {}".format(i + 1),
self.check16, True))
argnum = self.convertargs(fmt, op["args"], op["lineno"])
- oprec = petka.engine.ScrOpObject(opref, op["opcode"],
+ oprec = petka.engine.ScrOpObject(opref, op["opcode"],
argnum[0], argnum[1], argnum[2])
onrec.ops.append(oprec)
item.acts.append(onrec)
return item
-
+
for citem in compobj:
objrec = makerec(citem)
pe.objects.append(objrec)
pe.obj_idx[objrec.idx] = objrec
-
+
# second stage - SCENE
backgrnd = []
num_bkg = 0
@@ -518,10 +518,10 @@ class P12Compiler:
mode = 0 # 0 - common, 1 - grp, 2 - act, 3 - dlg
# 10 - msg (autoreset to 0)
-
+
# used identificators
self.usedid = {}
-
+
revOPS = {}
for ok, ov in petka.OPCODES.items():
revOPS[ov[0]] = ok
@@ -559,8 +559,8 @@ class P12Compiler:
while len(tokens) < 6:
tokens.append("0")
# check ident
- self.checkusedid(tokens[1], lineno)
- self.setidentvalue(tokens[1], len(compmsg))
+ self.checkusedid(tokens[1], lineno)
+ self.setidentvalue(tokens[1], len(compmsg))
# check wavfile name (1..12)
if len(tokens[2]) < 1 or len(tokens[2]) > 12:
raise ScriptSyntaxError("Error at {}: bad filename "\
@@ -613,7 +613,7 @@ class P12Compiler:
"OPREF ""\"{}\" in ON".\
format(lineno, tokens[1]))
don = self.check16(don, "ON opref", lineno)
- compactitem = {"don": don, "donref": tokens[2],
+ compactitem = {"don": don, "donref": tokens[2],
"args": tokens[3:], "dlgs": [], "lineno": lineno}
elif cmd == "ENDDLGGRP" and len(tokens) == 1:
mode = 0
@@ -680,7 +680,7 @@ class P12Compiler:
else:
raise ScriptSyntaxError("Error at {}: unknown parser mode {}".\
format(lineno, mode))
-
+
# check unclosed objects
if mode != 0:
raise ScriptSyntaxError("Error at {}: unfinished structure".\
@@ -728,7 +728,7 @@ class P12Compiler:
donref = self.convertnum(act["donref"])
if donref is not None:
# direct number
- donref = self.check16(donref, "ON object ref",
+ donref = self.check16(donref, "ON object ref",
act["lineno"])
else:
# get by ident
@@ -753,7 +753,7 @@ class P12Compiler:
self.check32, True))
argnum = self.convertargs(fmt, dlg["args"], dlg["lineno"])
# build DLG
- dlgrec = petka.engine.DlgObject(len(pe.dlgops),
+ dlgrec = petka.engine.DlgObject(len(pe.dlgops),
argnum[0], argnum[1])
for op in dlg["dlgops"]:
fmt = [("DLGOP argument", self.check8, False),
@@ -840,7 +840,7 @@ class P12Compiler:
if num in pe.scn_idx:
return "scene_{}".format(num)
return self.fmtnum16(num)
-
+
def printres(resid):
pprint("RES res_{} 0x{:x} \"{}\"".format(resid, resid,
self.escstr(pe.res[resid])))
@@ -857,7 +857,7 @@ class P12Compiler:
def printitem(item, itemtype):
pprint("{} {}_{} 0x{:x} \"{}\"".format(itemtype.upper(), itemtype,
item.idx, item.idx, self.escstr(item.name)))
-
+
# sub objects
if itemtype == "scene":
if len(item.refs) == 0:
@@ -871,11 +871,11 @@ class P12Compiler:
pprint(" # unknown reference to 0x{:x}".format(
obj.idx))
ref = "0x{:x}".format(obj.idx)
- pprint(" REF {} {} {} {} {} {}".format(ref,
- self.fmtnum32(a1), self.fmtnum32(a2),
- self.fmtnum32(a3), self.fmtnum32(a4),
+ pprint(" REF {} {} {} {} {} {}".format(ref,
+ self.fmtnum32(a1), self.fmtnum32(a2),
+ self.fmtnum32(a3), self.fmtnum32(a4),
self.fmtnum32(a5)))
-
+
for act in item.acts:
actif = ""
if act.act_status != 0xff or act.act_ref != 0xffff:
@@ -897,14 +897,14 @@ class P12Compiler:
self.fmtnum16(op.op_arg2),
self.fmtnum16(op.op_arg3)))
pprint(" ENDON")
-
+
pprint("END{} # {}_{}".format(itemtype.upper(), itemtype, item.idx))
pprint("")
-
+
pprint("# Decompile SCRIPT \"{}\"".format(scrname))
pprint("# Version: {}".format(VERSION))
pprint("# Encoding: {}".format(enc))
-
+
if decsort:
for idx, scene in enumerate(pe.scenes):
pprint("# Scene {} / {}".format(idx + 1, len(pe.scenes)))
@@ -912,7 +912,7 @@ class P12Compiler:
if len(scene.idx.refs) > 0:
pprint("# referenced objects {}:".format(len(scene.refs)))
for ref in scene.refs:
- if ref[0].idx in used_obj:
+ if ref[0].idx in used_obj:
pprint("# object 0x{:x} already defined".\
format(ref[0].idx))
continue
@@ -920,14 +920,14 @@ class P12Compiler:
if ref[0].idx in pe.obj_idx:
for act in ref[0].acts_array:
for op in act.ops_array:
- printrescheck(op.op_arg1, op.op_code)
- printitem(obj, "obj")
- else:
+ printrescheck(op.op_arg1, op.op_code)
+ printitem(obj, "obj")
+ else:
pprint("# No referenced objects")
# display res
for act in scene.acts:
for op in act.ops:
- printrescheck(op.op_arg1, op.op_code)
+ printrescheck(op.op_arg1, op.op_code)
printitem(scene, "scene")
# list unused
msg = False
@@ -977,14 +977,14 @@ class P12Compiler:
msg.idx, msg.msg_wav, msg.msg_arg1, msg.msg_arg2, msg.msg_arg3))
pprint(" \"{}\"".format(self.escstr(msg.name)))
pprint("")
-
+
for gidx, grp in enumerate(pe.dlgs, 1):
pprint("# {} = 0x{:x}".format(gidx, gidx))
pprint("DLGGRP 0x{:x} {}".format(grp.idx, \
self.fmtnum32(grp.grp_arg1)))
for sidx, act in enumerate(grp.acts, 1):
pprint(" ON {} 0x{:x} 0x{:x} 0x{:x} # {}".format(\
- self.fmtop(act.opcode), act.ref, act.arg1,
+ self.fmtop(act.opcode), act.ref, act.arg1,
act.arg2, sidx))
# print code
for didx, dlg in enumerate(act.dlgs, 1):
@@ -1094,27 +1094,27 @@ def checksame(f1, n1, f2, n2):
format(f1))
return True
return False
-
-
+
+
def action_dec(args):
print("Decompile SCRIPT.DAT file")
destpath = args.destpath
encoding = args.encoding
-
+
if destpath:
if ckeckoverwrite(destpath, args): return -1
- if checksame(args.sourcepath, "source", destpath, "destination"):
+ if checksame(args.sourcepath, "source", destpath, "destination"):
return -2
if not encoding:
encoding = "UTF-8"
-
+
print("Input:\t{}".format(args.sourcepath))
print("Output:\t{}".format(destpath or "-"))
if destpath:
print("Enc:\t{}".format(encoding))
if args.decompile_sorted:
print("Flag decompile_sorted enabled")
-
+
dcs = P12Compiler()
if destpath:
f = open(destpath, "wb")
@@ -1158,21 +1158,21 @@ def action_decd(args):
print("Decompile DIALOGUE.FIX file")
destpath = args.destpath
encoding = args.encoding
-
+
if destpath:
if ckeckoverwrite(destpath, args): return -1
if checksame(args.sourcepath, "source", destpath, "destination"):
return -2
if not encoding:
encoding = "UTF-8"
-
+
print("Input:\t{}".format(args.sourcepath))
print("Output:\t{}".format(destpath or "-"))
if destpath:
print("Enc:\t{}".format(encoding))
if args.verbose:
print("Flag verbose enabled")
-
+
dcs = P12Compiler()
if destpath:
f = open(destpath, "wb")
@@ -1230,13 +1230,13 @@ def internaltest(folder):
hm = hashlib.md5()
hm.update(mem.read())
return hm.hexdigest() == hf.hexdigest()
-
+
for test in test_arr:
print("=== Test: " + test + " ===")
testbase = os.path.join(folder, test)
path = find_in_folder(testbase, "script.dat")
dcs = P12Compiler()
- mems = io.BytesIO()
+ mems = io.BytesIO()
dcs.pretty_print_scr(path, mems)
print("Decompiled script:", mems.tell())
# compile back
@@ -1261,8 +1261,8 @@ def internaltest(folder):
if not os.path.exists(path):
print("All ok - no dialogue")
continue
-
- mems = io.BytesIO()
+
+ mems = io.BytesIO()
dcs.pretty_print_dlg(path, mems)
print("Decompiled dialogue:", mems.tell())
# compile back
@@ -1284,23 +1284,23 @@ def internaltest(folder):
def action_version(args):
print("Version: " + VERSION)
-
+
def main():
print(APPNAME + ", " + VERSION)
print("\tRoman Kharin (romiq.kh at gmail.com)")
if len(sys.argv) < 2:
print("Use -h for help.")
return
-
+
if len(sys.argv) >= 3:
if sys.argv[1] == "test":
internaltest(sys.argv[2])
return
-
+
parser = argparse.ArgumentParser(epilog = \
"For actions help try: <action> -h")
subparsers = parser.add_subparsers(title = 'actions')
-
+
# decompile - <script.dat> [[--enc <encoding>] -o <decompiled.txt>]
parser_dec = subparsers.add_parser("decompile", aliases = ['d'], \
help = "decompile script.dat")
diff --git a/engines/petka/petka/__init__.py b/engines/petka/petka/__init__.py
index 7c2864ce2..f552ef9c6 100644
--- a/engines/petka/petka/__init__.py
+++ b/engines/petka/petka/__init__.py
@@ -8,4 +8,3 @@ from .imgflc import FLCLoader
from .imgleg import LEGLoader
from .imgmsk import MSKLoader
from .saves import SaveLoader
-
diff --git a/engines/petka/petka/engine.py b/engines/petka/petka/engine.py
index afe725c62..18d524af4 100644
--- a/engines/petka/petka/engine.py
+++ b/engines/petka/petka/engine.py
@@ -88,7 +88,7 @@ ACTIONS = {
4: ("TALK", 5006),
5: ("CHAPAY", 5007),
6: ("INVNTR", -1),
-
+
}
class ScrObject:
@@ -157,7 +157,7 @@ class DlgOpObject:
self.ref = ref # message idx
self.msg = None # message
self.pos = None
-
+
class Engine:
def __init__(self):
self.fman = None
@@ -168,11 +168,11 @@ class Engine:
self.curr_part = None
self.curr_chap = None
-
+
self.curr_path = None
self.curr_speech = None
self.curr_diskid = None
-
+
def init_empty(self, enc):
self.enc = enc
self.objects = []
@@ -183,7 +183,7 @@ class Engine:
self.dlgs = []
self.dlg_idx = {}
self.dlgops = []
-
+
def parse_ini(self, f):
# parse ini settings
curr_sect = None
@@ -210,7 +210,7 @@ class Engine:
ini["__ordersect__"] = order_sect
ini["__order__"] = orders
return ini
-
+
def parse_res(self, f):
res = {}
resord = []
@@ -228,7 +228,7 @@ class Engine:
res[res_id] = value
resord.append(res_id)
return res, resord
-
+
def load_data(self, folder, enc):
self.init_empty(enc)
self.fman = FileManager(folder)
@@ -252,7 +252,7 @@ class Engine:
else:
# load BGS.INI only (e.g. DEMO)
self.parts_ini = None
-
+
# std stores
self.fman.load_store("patch.str")
self.fman.load_store("main.str")
@@ -278,7 +278,7 @@ class Engine:
self.curr_path = ""
self.curr_speech = ""
self.curr_diskid = None
-
+
# load .STR
strs = ["Flics", "Background", "Wav", "Music", "SFX", "Speech"]
for strf in strs:
@@ -292,7 +292,7 @@ class Engine:
self.load_names()
# load dialogs
self.load_dialogs()
-
+
# current state
self.curr_scene = None
self.curr_obj = None
@@ -301,13 +301,13 @@ class Engine:
self.curr_char1 = None
self.curr_char2 = None
self.curr_invntr = None
-
+
def load_script(self, scrname = None, bkgname = None, resname = None):
self.objects = []
self.scenes = []
self.obj_idx = {}
self.scn_idx = {}
-
+
if scrname is None:
try:
data = self.fman.read_file(self.curr_path + "script.dat")
@@ -347,7 +347,7 @@ class Engine:
rec = ScrObject(obj_id, name)
rec.acts = acts
return off, rec
-
+
for i in range(num_obj):
off, obj = read_rec(off)
self.objects.append(obj)
@@ -358,9 +358,9 @@ class Engine:
scn.refs = None
self.scenes.append(scn)
self.scn_idx[scn.idx] = scn
-
+
if bkgname is None:
- try:
+ try:
data = self.fman.read_file(self.curr_path + "backgrnd.bg")
except:
data = None
@@ -374,7 +374,7 @@ class Engine:
finally:
f.close()
- if data:
+ if data:
num_rec = struct.unpack_from("<I", data[:4])[0]
else:
num_rec = 0
@@ -383,7 +383,7 @@ class Engine:
scn_ref, num_ref = struct.unpack_from("<HI", data[off:off + 6])
off += 6
if scn_ref in self.scn_idx:
- scn = self.scn_idx[scn_ref]
+ scn = self.scn_idx[scn_ref]
scn.refs = []
else:
raise EngineError("DEBUG: Scene ID = 0x{:x} not found".\
@@ -398,7 +398,7 @@ class Engine:
else:
raise EngineError("DEBUG: Scene ref 0x{:x} not found".\
format(obj[0]))
-
+
if resname is None:
try:
f = self.fman.read_file_stream(self.curr_path + "resource.qrc")
@@ -409,8 +409,8 @@ class Engine:
f = open(resname, "rb")
except:
f = None
- try:
- if f:
+ try:
+ if f:
self.res, self.resord = self.parse_res(f)
else:
self.res = {}
@@ -418,7 +418,7 @@ class Engine:
finally:
if f:
f.close()
-
+
def load_names(self):
self.names = {}
self.namesord = []
@@ -463,7 +463,7 @@ class Engine:
except:
r, g, b = 255, 255, 255
obj.cast = (r, g, b)
-
+
def load_bgs(self):
# load BGS.INI
self.bgs_ini = {}
@@ -475,7 +475,7 @@ class Engine:
self.bgs_ini = self.parse_ini(f)
finally:
f.close()
-
+
settings = self.bgs_ini.get("Settings", {})
self.start_scene = settings.get("StartRoom", None)
@@ -511,14 +511,14 @@ class Engine:
except:
persp = None
scene.persp = persp
-
-
+
+
def load_dialogs(self, fixname = None, lodname = None, noobjref = False):
self.msgs = []
# DIALOGUES.LOD
-
+
if lodname is None:
- try:
+ try:
f = self.fman.read_file_stream(self.curr_path + "dialogue.lod")
except:
f = None
@@ -556,7 +556,7 @@ class Engine:
self.dlg_idx = {}
self.dlgops = []
if fixname is None:
- try:
+ try:
f = self.fman.read_file_stream(self.curr_path + "dialogue.fix")
except:
f = None
@@ -624,13 +624,13 @@ class Engine:
dlg.ops = oparr
oparr = []
dlg = opref[idx]
- oparr.append(oprec)
+ oparr.append(oprec)
if len(oparr) > 0:
dlg.ops = oparr
finally:
if f:
f.close()
-
+
def write_script(self, f):
f.write(struct.pack("<II", len(self.objects), len(self.scenes)))
@@ -640,24 +640,24 @@ class Engine:
f.write(ename)
f.write(struct.pack("<I", len(rec.acts)))
for act in rec.acts:
- f.write(struct.pack("<HBHI", act.act_op, act.act_status,
+ f.write(struct.pack("<HBHI", act.act_op, act.act_status,
act.act_ref, len(act.ops)))
for op in act.ops:
f.write(struct.pack("<5H", op.op_ref, op.op_code,
op.op_arg1, op.op_arg2, op.op_arg3))
-
+
for rec in self.objects + self.scenes:
write_rec(rec)
-
+
def write_backgrnd(self, f):
lst = [scn for scn in self.scenes if scn.refs is not None]
f.write(struct.pack("<I", len(lst)))
for scn in lst:
f.write(struct.pack("<HI", scn.idx, len(scn.refs)))
for ref in scn.refs:
- f.write(struct.pack("<H5I", ref[0].idx, ref[1], ref[2],
+ f.write(struct.pack("<H5I", ref[0].idx, ref[1], ref[2],
ref[3], ref[4], ref[5]))
-
+
def write_lod(self, f):
f.write(struct.pack("<I", len(self.msgs)))
@@ -665,7 +665,7 @@ class Engine:
wav = msg.msg_wav.encode(self.enc)
while len(wav) < 12:
wav += b"\0"
- f.write(struct.pack("<I12sII", msg.msg_arg1, wav, msg.msg_arg2,
+ f.write(struct.pack("<I12sII", msg.msg_arg1, wav, msg.msg_arg2,
msg.msg_arg3))
for msg in self.msgs:
txt = msg.name.encode(self.enc)
@@ -677,11 +677,11 @@ class Engine:
f.write(struct.pack("<3I", grp.idx, len(grp.acts), grp.grp_arg1))
for grp in self.dlgs:
for act in grp.acts:
- f.write(struct.pack("<2H3I", act.opcode, act.ref,
+ f.write(struct.pack("<2H3I", act.opcode, act.ref,
len(act.dlgs), act.arg1, act.arg2))
for act in grp.acts:
for dlg in act.dlgs:
- f.write(struct.pack("<3I", dlg.op_start, dlg.arg1,
+ f.write(struct.pack("<3I", dlg.op_start, dlg.arg1,
dlg.arg2))
f.write(struct.pack("<I", len(self.dlgops)))
for op in self.dlgops:
@@ -693,23 +693,23 @@ class Engine:
# create current state from initial state
def init_game(self):
self.curr_scene = self.scene_to_id(self.start_scene)
-
+
self.curr_obj = []
for obj in self.objects + self.scenes:
state = ScrObjectState(obj)
self.curr_obj.append(state)
state.prop
-
+
self.curr_dlg = []
for dlgop in self.dlgops:
dlgstate = DlgOpObject(dlgop.code, dlgop.arg, dlgop.ref)
dlgstate.pos = dlgop.pos
self.curr_dlg.append(dlgstate)
-
+
self.curr_cursor = None
self.curr_char1 = None
self.curr_char2 = None
- self.curr_invntr = []
+ self.curr_invntr = []
def load_save(self, ls):
self.curr_scene = self.scene_to_id(ls.scene)
@@ -720,4 +720,3 @@ class Engine:
self.curr_char1 = None
self.curr_char2 = None
self.curr_invntr = None
-
diff --git a/engines/petka/petka/fman.py b/engines/petka/petka/fman.py
index e83d68682..e69f1867f 100644
--- a/engines/petka/petka/fman.py
+++ b/engines/petka/petka/fman.py
@@ -12,11 +12,11 @@ from . import EngineError
class FileManager:
def __init__(self, root):
self.root = os.path.abspath(root)
-
+
self.strfd = []
self.strtable = {}
self.strtableord = []
-
+
def find_path(self, path):
# search case insensive from root
dpath = []
@@ -32,7 +32,7 @@ class FileManager:
break
if not ok: return None
return npath
-
+
def load_store(self, name, tag = 0):
path = self.find_path(name)
if path is None:
@@ -54,7 +54,7 @@ class FileManager:
index_len = struct.unpack_from("<I", temp)[0]
index_table = []
for iref in range(index_len):
- temp = f.read(12)
+ temp = f.read(12)
data = struct.unpack_from("<III", temp)
index_table.append((data[1], data[2]))
strlst = []
@@ -93,21 +93,21 @@ class FileManager:
finally:
f.close()
return data
-
+
def read_file_stream(self, fname):
data = self.read_file(fname)
mems = io.BytesIO()
mems.write(data)
mems.seek(0)
- return mems
-
+ return mems
+
def exists(self, fname):
sf = fname.lower().replace("\\", "/")
if sf in self.strtable:
return True
else:
- return self.find_path(fname) is not None
-
+ return self.find_path(fname) is not None
+
def unload_stores(self, flt = None):
strfd = []
strtable = {}
@@ -129,5 +129,3 @@ class FileManager:
self.strfd = strfd
self.strtable = strtable
self.strtableord = strtableord
-
-
diff --git a/engines/petka/petka/imgbmp.py b/engines/petka/petka/imgbmp.py
index 26e8261ba..dc8e40904 100644
--- a/engines/petka/petka/imgbmp.py
+++ b/engines/petka/petka/imgbmp.py
@@ -17,18 +17,18 @@ class BMPLoader:
self.image = None
self.width = 0
self.height = 0
-
+
def load_data_int16(self, f):
# check magic string "BM"
temp = f.read(2)
if temp != b"BM":
raise EngineError("Bad magic string")
off = 2
-
+
temp = f.read(12)
f_sz, res1, res2, data_offset = struct.unpack_from("<IHHI", temp)
off += 12
-
+
# read next 40 bytes, BITMAPINFOHEADER
temp = f.read(40)
pict = struct.unpack_from("<IiiHHIIiiII", temp)
@@ -37,7 +37,7 @@ class BMPLoader:
raise EngineError("Unsupported InfoHeader")
pictw = pict[1]
picth = pict[2]
-
+
# read data_offset - 40 - 6 bytes
delta = data_offset - 40 - 6
if delta < 0:
@@ -50,7 +50,7 @@ class BMPLoader:
bsz = pictw * picth * 2
picture_data = f.read(bsz)
-
+
off += bsz
if len(picture_data) != bsz:
raise EngineError("Bitmap truncated, need {}, got {}".format(bsz, \
@@ -66,9 +66,9 @@ class BMPLoader:
if len(temp) > 0:
if temp != b"\x00\x00":
raise EngineError("BMP read error, some data unparsed")
-
+
return pictw, picth, picture_data
-
+
def pixelswap16ud(self, pw, ph, pd):
# convert 16 bit to 24 + vertical reverse
b16arr = array.array("H") # unsigned short
@@ -107,22 +107,22 @@ class BMPLoader:
except:
f.seek(0)
self.image = Image.open(f)
-
+
def load_raw(self, pw, ph, pd):
if Image:
pd = self.pixelswap16(pw, ph, pd).tobytes()
- self.image = Image.frombytes("RGB", (pw, ph), pd)
+ self.image = Image.frombytes("RGB", (pw, ph), pd)
else:
self.width = pw
self.height = ph
self.rgb = self.pixelswap16(pw, ph, pd)
-
+
def load_data(self, f):
try:
pw, ph, pd = self.load_data_int16(f)
if Image:
pd = self.pixelswap16ud(pw, ph, pd).tobytes()
- self.image = Image.frombytes("RGB", (pw, ph), pd)
+ self.image = Image.frombytes("RGB", (pw, ph), pd)
else:
self.width = pw
self.height = ph
@@ -130,4 +130,3 @@ class BMPLoader:
except:
f.seek(0)
self.image = Image.open(f)
-
diff --git a/engines/petka/petka/imgflc.py b/engines/petka/petka/imgflc.py
index 1af7377a2..9da0b4ff7 100644
--- a/engines/petka/petka/imgflc.py
+++ b/engines/petka/petka/imgflc.py
@@ -52,7 +52,7 @@ class FLCLoader:
self.height = 0
self.frame_num = 0
self.delay = 0
-
+
def load_info(self, f):
self.image = Image.open(f)
@@ -63,23 +63,23 @@ class FLCLoader:
self.frame_num += 1
except EOFError:
pass # end of sequence
-
-
+
+
def parseflcchunks(self, f, offset, limit, level = 0, maxchunks = None,):
def check_hdr(size, delta, name, offset):
if delta < size:
raise EngineError("Incorrect FLC %s chunk at 0x{:08x}".format(
(name, offset)))
-
+
chunks = []
while True:
if limit is not None:
- if offset >= limit:
+ if offset >= limit:
break
if maxchunks is not None:
- if len(chunks) >= maxchunks:
+ if len(chunks) >= maxchunks:
break
- chunk = {"offset": offset}
+ chunk = {"offset": offset}
temp = f.read(6)
sz, tp = struct.unpack_from("<IH", temp)
offset += 6
@@ -90,7 +90,7 @@ class FLCLoader:
if delta < 0:
raise EngineError("Incorrect FLC chunk at 0x{:08x}".format(
chunk["offset"]))
-
+
raw_chunks = [
0x4, # COLOR_256
0x7, # DELTA_FLC
@@ -114,7 +114,7 @@ class FLCLoader:
delta -= 6
height, width, xlate = struct.unpack_from("<3H", temp)
offset += 6
- offset, subchunks = self.parseflcchunks(f, offset,
+ offset, subchunks = self.parseflcchunks(f, offset,
offset + delta, level + 1, 1)
chunk["chunks"] = subchunks
#print(subchunks)
@@ -129,17 +129,17 @@ class FLCLoader:
chunk["delay"] = delay
chunk["width"] = width
chunk["height"] = height
- offset, subchunks = self.parseflcchunks(f, offset,
+ offset, subchunks = self.parseflcchunks(f, offset,
offset + delta, level + 1, sub_num)
chunk["chunks"] = subchunks
else:
raise Exception("Unknown FLC chunk type 0x{:04x} at 0x{:x08x}".\
format(tp, offset))
-
+
chunks.append(chunk)
-
+
return offset, chunks
-
+
def load_data(self, f):
# parse header
offset = 0
@@ -151,32 +151,32 @@ class FLCLoader:
hdr_struct += htp
else:
hdr_struct += "%d" % hsz + htp
-
+
header = {}
temp = f.read(128)
hdr = struct.unpack_from(hdr_struct, temp)
-
+
offset += 128
-
+
if len(hdr) != len(hdr_keys):
raise EngineError("Incorrect FLC header {} != {}".format(
len(hdr), len(hdr_keys)))
for hid in range(len(hdr)):
header[hdr_keys[hid]] = hdr[hid]
-
+
if header["ftype"] != 0xAF12:
raise EngineError("Unsupported FLC type (0x{:04x})".format(
header["ftype"]))
-
+
# check if not EGI ext
if header["creator"] == 0x45474900:
if header["ext_flags"] != 0:
- raise EngineError("Unsupported FLC EGI extension")
-
+ raise EngineError("Unsupported FLC EGI extension")
+
# NOTE: we recreate FLC to avoid Pilllow bug
# 1. remove 0xf100 chunk (PREFIX, implementation specific)
# 2. remobe 0x12 subchunk (PSTAMP) from 1st frame
-
+
# read chunks
_, chunks = self.parseflcchunks(f, offset, header["fsize"])
@@ -189,7 +189,7 @@ class FLCLoader:
elif chunk["type"] == 0xF1FA:
rebuild = False
nchunks = []
- nsz = 16 # I6H - type, size, sub_num, delay,
+ nsz = 16 # I6H - type, size, sub_num, delay,
# reserved, width, height
for schunk in chunk["chunks"]:
if schunk["type"] == 0x12: # detect mailformed PSTAMP
@@ -198,7 +198,7 @@ class FLCLoader:
nchunks.append(schunk)
nsz += schunk["size"]
if rebuild:
- buf.write(struct.pack("<I6H", nsz, 0xF1FA, len(nchunks),
+ buf.write(struct.pack("<I6H", nsz, 0xF1FA, len(nchunks),
chunk["delay"], 0, chunk["width"], chunk["height"]))
for schunk in nchunks:
f.seek(schunk["offset"])
@@ -209,4 +209,3 @@ class FLCLoader:
buf.seek(0)
self.image = Image.open(buf)
-
diff --git a/engines/petka/petka/imgleg.py b/engines/petka/petka/imgleg.py
index cc6c9398e..ee340e56b 100644
--- a/engines/petka/petka/imgleg.py
+++ b/engines/petka/petka/imgleg.py
@@ -9,10 +9,10 @@ from . import EngineError
class LEGLoader:
def __init__(self):
self.coords = []
-
+
def load_info(self, f):
return self.load_data(f)
-
+
def load_data(self, f):
hdr = f.read(4)
if hdr != b"xyof":
@@ -21,7 +21,6 @@ class LEGLoader:
rest = f.read()
if len(rest) % 8:
raise EngineError("Bad LEG/OFF size {}".format(len(rest)))
-
+
sf = struct.unpack("<{}l".format(len(rest) // 4), rest)
self.coords = [[sf[i * 2], sf[i * 2 + 1]] for i in range(len(rest) // 8)]
-
diff --git a/engines/petka/petka/imgmsk.py b/engines/petka/petka/imgmsk.py
index cfd20dd9f..239c65616 100644
--- a/engines/petka/petka/imgmsk.py
+++ b/engines/petka/petka/imgmsk.py
@@ -10,10 +10,10 @@ class MSKLoader:
def __init__(self):
self.bound = [0, 0, 0, 0]
self.rects = []
-
+
def load_info(self, f):
return self.load_data(f)
-
+
def load_data(self, f):
rest = f.read()
f.seek(0)
@@ -31,10 +31,10 @@ class MSKLoader:
rec.append([l, t, r, b])
rects.append(rec)
delta -= 4
-
+
if delta != 0:
raise EngineError("Bad MSK file")
-
+
temp = f.read(len(rects) * 4)
frms = struct.unpack_from("<{}I".format(len(rects)), temp)
@@ -45,4 +45,3 @@ class MSKLoader:
self.bound = struct.unpack_from("<4i", temp)
self.rects = list(zip(reversed(frms), rects))
-
diff --git a/engines/petka/petka/saves.py b/engines/petka/petka/saves.py
index 2f5ebda0c..9fcea40d6 100644
--- a/engines/petka/petka/saves.py
+++ b/engines/petka/petka/saves.py
@@ -15,7 +15,7 @@ class SaveLoader:
self.stamp = None
self.enc = enc
self.objects = []
-
+
def load_data(self, f, part, objnum):
data = f.read(8)
self.part, self.chap = struct.unpack("<2I", data)
@@ -25,7 +25,7 @@ class SaveLoader:
stamp = f.read(30)
stamp = stamp.split(b"\x00")[0]
self.stamp = stamp.decode(self.enc)
-
+
# read screenshot
sl = 108 * 81 * 2
rgb = f.read(sl)
@@ -33,24 +33,24 @@ class SaveLoader:
raise EngineError("Bad SAVE length (no screenshot)")
self.shot = BMPLoader()
self.shot.load_raw(108, 81, rgb)
-
+
hz2 = f.read(216)
if hz2 != b"\x00" * 216:
raise EngineError("Bad SAVE error in HZ2 field")
-
+
data = f.read(4)
hz3 = struct.unpack("<I", data)[0]
if hz3 != objnum + 3:
raise EngineError("Bad SAVE objects number")
-
+
def readstr():
data = f.read(4)
strlen = struct.unpack("<I", data)[0]
s = f.read(strlen)
#print("STR", strlen, data, s)
return s.decode(self.enc)
-
+
for i in range(objnum):
s1 = readstr()
s2 = readstr()
@@ -61,8 +61,8 @@ class SaveLoader:
obj["res"] = recs[2]
self.objects.append(obj)
#print(i, s1, s2)
-
- # invntr
+
+ # invntr
data = f.read(4)
invlen = struct.unpack("<I", data)[0]
data = f.read(invlen * 2)
@@ -70,11 +70,11 @@ class SaveLoader:
# scene
self.scene = readstr()
-
+
# char positions
data = f.read(16)
charpos = struct.unpack("<4I", data)
-
+
# arr dialog opcodes
data = f.read(4)
dlgoplen = struct.unpack("<I", data)[0]
@@ -83,7 +83,7 @@ class SaveLoader:
data = f.read(4)
ref, arg, code = struct.unpack_from("<HBB", data)
self.dlgops.append([code, arg, ref])
-
+
data = f.read(20)
self.cursor_res, self.cursor, self.cursor_obj, c1res, c2res = \
struct.unpack("<5I", data)
@@ -98,5 +98,3 @@ class SaveLoader:
if f.read():
raise EngineError("Bad SAVE length (extra data)")
-
-
diff --git a/engines/petka/testtkgui.py b/engines/petka/testtkgui.py
index 56a953a71..ff43aee6d 100755
--- a/engines/petka/testtkgui.py
+++ b/engines/petka/testtkgui.py
@@ -15,8 +15,8 @@ VERSION = "v0.1 2015-06-20"
class App(TkBrowser):
def __init__(self, master):
- super().__init__(master)
-
+ super().__init__(master)
+
def init_gui(self):
self.master.title(APPNAME)
# path
@@ -25,7 +25,7 @@ class App(TkBrowser):
else:
self.app_path = __file__
self.app_path = os.path.abspath(os.path.dirname(self.app_path))
-
+
def create_widgets(self):
super().create_widgets()
@@ -40,7 +40,7 @@ class App(TkBrowser):
repath = ""
break
if repath:
- self.open_path(repath)
+ self.open_path(repath)
def create_menu(self):
@@ -51,7 +51,7 @@ class App(TkBrowser):
self.menufile.add_separator()
self.menufile.add_command(
command = self.on_exit,
- label = "Quit")
+ label = "Quit")
def path_default(self, path):
self.switch_view(0)
@@ -64,14 +64,14 @@ class App(TkBrowser):
self.add_info("\n\n<b>This is multi-")
self.add_info("line\nbold</b> text\n")
self.add_info("\n\n<u>This is multi-")
- self.add_info("line\nunderline</u> text\n")
+ self.add_info("line\nunderline</u> text\n")
self.add_info("\n\n<font color=\"#ff00FF\">This is multi-")
self.add_info("line\ncolor</font> text\n")
self.add_info("\n<font bg=\"red\" color=\"white\"> <b>White</b> on <i>red</i> </font>\n")
- self.insert_lb_act("Testing", "/test")
- return True
+ self.insert_lb_act("Testing", "/test")
+ return True
def path_test(self, path):
if len(path) > 1:
@@ -84,7 +84,7 @@ class App(TkBrowser):
self.insert_lb_act("Image", "/test/image")
self.switch_view(0)
self.clear_info()
- self.add_info("Select test from outline")
+ self.add_info("Select test from outline")
return True
def path_test_item(self, path):
@@ -114,13 +114,13 @@ class App(TkBrowser):
self.gl_state.get("test.info.mode", None)))
for i in range(100):
self.add_info(" Item {}\n".format(i))
-
+
if self.last_path[:2] != ("test", path[1]):
self.update_gui("Test %s" % path[1])
self.insert_lb_act("Testing", "/test")
self.insert_lb_act("-", None)
for i in range(15):
- self.insert_lb_act("{} #{}".format(path[1], i),
+ self.insert_lb_act("{} #{}".format(path[1], i),
path[:2] + (i,), i)
# create mode buttons
def sw_mode1():
@@ -165,6 +165,6 @@ def main():
app.start_act.append(["open", argv[0]])
argv = argv[1:]
app.mainloop()
-
+
if __name__ == "__main__":
main()
diff --git a/engines/petka/tkguibrowser.py b/engines/petka/tkguibrowser.py
index fe17d6d9a..a5d05cb7c 100644
--- a/engines/petka/tkguibrowser.py
+++ b/engines/petka/tkguibrowser.py
@@ -44,10 +44,10 @@ def fmt_arg(value):
return "-1"
else:
return "0x{:X}".format(value)
-
+
def fmt_dec(value, add = 0):
return "{{:{}}}".format(fmt_dec_len(value, add))
-
+
def fmt_dec_len(value, add = 0):
if value == 0:
d = 1
@@ -55,7 +55,7 @@ def fmt_dec_len(value, add = 0):
d = int(math.log10(value)) + 1
d += add
return d
-
+
# thanx to http://effbot.org/zone/tkinter-text-hyperlink.htm
class HyperlinkManager(HTMLParser):
@@ -151,7 +151,7 @@ class HyperlinkManager(HTMLParser):
self.parser_tags.append(self.bg(bg))
else:
self.parser_tags.append(self.color(color))
-
+
def handle_endtag(self, tag):
self.parser_tags = self.parser_tags[:-1]
@@ -184,7 +184,7 @@ class TkBrowser(tkinter.Frame):
def __init__(self, master):
tkinter.Frame.__init__(self, master)
- self.pack(fill = tkinter.BOTH, expand = 1)
+ self.pack(fill = tkinter.BOTH, expand = 1)
self.pad = None
# gui
@@ -210,9 +210,9 @@ class TkBrowser(tkinter.Frame):
self.main_image = tkinter.PhotoImage(width = 1, height = 1)
# add on_load handler
self.after_idle(self.on_first_display)
-
+
def init_gui(self):
- pass
+ pass
def update_after(self):
if not self.need_update:
@@ -267,20 +267,20 @@ class TkBrowser(tkinter.Frame):
]
for text, cmd in btns:
if text is None:
- frm = ttk.Frame(self.toolbar, width = self.pad,
+ frm = ttk.Frame(self.toolbar, width = self.pad,
height = self.pad)
frm.pack(side = tkinter.LEFT)
- continue
+ continue
btn = ttk.Button(self.toolbar, text = text, \
style = "Tool.TButton", command = cmd)
btn.pack(side = tkinter.LEFT)
frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
frm.pack(side = tkinter.LEFT)
-
+
# main panel
self.pan_main = ttk.PanedWindow(self, orient = tkinter.HORIZONTAL)
self.pan_main.pack(fill = tkinter.BOTH, expand = 1)
-
+
# leftpanel
self.frm_left = ttk.Frame(self.pan_main)
self.pan_main.add(self.frm_left)
@@ -289,7 +289,7 @@ class TkBrowser(tkinter.Frame):
self.pan_main.add(self.frm_view)
self.frm_view.grid_rowconfigure(0, weight = 1)
self.frm_view.grid_columnconfigure(0, weight = 1)
- self.scr_view_x = ttk.Scrollbar(self.frm_view,
+ self.scr_view_x = ttk.Scrollbar(self.frm_view,
orient = tkinter.HORIZONTAL)
self.scr_view_x.grid(row = 1, column = 0, \
sticky = tkinter.E + tkinter.W)
@@ -297,22 +297,22 @@ class TkBrowser(tkinter.Frame):
self.scr_view_y.grid(row = 0, column = 1, sticky = \
tkinter.N + tkinter.S)
# canvas
- self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
- bd = 0, highlightthickness = 0,
+ self.canv_view = tkinter.Canvas(self.frm_view, height = 150,
+ bd = 0, highlightthickness = 0,
scrollregion = (0, 0, 50, 50),
)
# don't forget
# canvas.config(scrollregion=(left, top, right, bottom))
self.canv_view.bind('<Configure>', self.on_resize_view)
self.canv_view.bind('<ButtonPress-1>', self.on_mouse_view)
-
+
# text
self.text_view = ReadOnlyText(self.frm_view,
highlightthickness = 0,
)
self.text_hl = HyperlinkManager(self.text_view)
self.text_view.bind('<Configure>', self.on_resize_view)
-
+
def create_menu(self):
self.menubar = tkinter.Menu(self.master)
self.master.configure(menu = self.menubar)
@@ -322,10 +322,10 @@ class TkBrowser(tkinter.Frame):
def on_mouse_view(self, event):
self.update_after()
-
+
def on_resize_view(self, event):
self.update_after()
-
+
def parse_path(self, loc):
if isinstance(loc, str):
path = []
@@ -342,8 +342,8 @@ class TkBrowser(tkinter.Frame):
path = tuple(path)
while path[-1:] == ("",):
path = path[:-1]
- return path
-
+ return path
+
def desc_path(self, loc):
path = self.parse_path(loc)
if len(path) > 0:
@@ -362,11 +362,11 @@ class TkBrowser(tkinter.Frame):
c = self.canv_view
c.delete(tkinter.ALL)
- w = self.canv_view.winfo_width()
+ w = self.canv_view.winfo_width()
h = self.canv_view.winfo_height()
- if (w == 0) or (h == 0):
+ if (w == 0) or (h == 0):
return
-
+
scale = 0
# Preview image
@@ -429,7 +429,7 @@ class TkBrowser(tkinter.Frame):
c.config(scrollregion = (0, 0, cw - 2, ch - 2))
#print("Place c %d %d, p %d %d" % (cw, ch, w, h))
c.create_image(cw // 2, ch // 2, image = self.canv_image)
-
+
def make_image(self, imgobj):
if imgobj.image is not None:
return imgobj.image
@@ -456,13 +456,13 @@ class TkBrowser(tkinter.Frame):
if ch > 0x7f:
p += bytes((0b11000000 |\
ch >> 6, 0b10000000 |\
- (ch & 0b00111111)))
+ (ch & 0b00111111)))
else:
p += bytes((ch,))
image = tkinter.PhotoImage(width = width, height = height, \
data = bytes(p))
- return image
-
+ return image
+
def update_gui(self, text = "<Undefined>"):
self.last_path = self.curr_path
# cleanup
@@ -518,7 +518,7 @@ class TkBrowser(tkinter.Frame):
)
self.scr_view_x.config(command = self.text_view.xview)
self.scr_view_y.config(command = self.text_view.yview)
- else:
+ else:
if last == 0:
rw = self.text_view.winfo_width()
rh = self.text_view.winfo_height()
@@ -546,7 +546,7 @@ class TkBrowser(tkinter.Frame):
def add_info(self, text):
self.curr_markup += text
-
+
def end_markup(self):
if not self.curr_markup: return
def make_cb(path):
@@ -557,7 +557,7 @@ class TkBrowser(tkinter.Frame):
return cb
self.text_hl.add_markup(self.curr_markup, self.text_view, make_cb)
self.curr_markup = ""
-
+
def insert_lb_act(self, name, act, key = None):
if key is not None:
self.curr_lb_idx[key] = len(self.curr_lb_acts)
@@ -580,7 +580,7 @@ class TkBrowser(tkinter.Frame):
self.curr_lb.selection_set(idxs)
if idx is not None:
self.curr_lb.see(idxs)
-
+
def on_left_listbox(self, event):
def currsel():
try:
@@ -599,14 +599,14 @@ class TkBrowser(tkinter.Frame):
if text is None:
frm = ttk.Frame(self.toolbar, width = self.pad, height = self.pad)
frm.pack(side = tkinter.LEFT)
- self.curr_gui.append(lambda:frm.pack_forget())
+ self.curr_gui.append(lambda:frm.pack_forget())
return
btn = ttk.Button(self.toolbar, text = text, \
style = "Tool.TButton", command = cmd)
btn.pack(side = tkinter.LEFT)
self.curr_gui.append(lambda:btn.pack_forget())
return btn
-
+
def add_toollabel(self, text):
lab = ttk.Label(self.toolbar, text = text)
lab.pack(side = tkinter.LEFT)
@@ -635,16 +635,16 @@ class TkBrowser(tkinter.Frame):
btn.config(state = tkinter.NORMAL)
else:
btn.config(state = tkinter.DISABLED)
-
+
def clear_hist(self):
self.hist = self.hist[-1:]
self.histf = []
def open_http(self, path):
messagebox.showinfo(parent = self, title = "URL", message = path)
-
+
def open_path(self, loc, withhist = True):
- path = self.parse_path(loc)
+ path = self.parse_path(loc)
if withhist:
self.hist.append([path])
self.histf = []
@@ -671,5 +671,3 @@ class TkBrowser(tkinter.Frame):
self.clear_info()
self.add_info("Open path\n\n" + str(path))
return True
-
-
More information about the Scummvm-git-logs
mailing list