1+
2+
3+
4+ # python -m pip install Pillow
5+ import pathlib
6+ import struct
7+ from sourcehold .tool .memory .map .common import get_process_handle , validate_path
8+ from sourcehold .world import create_selection_matrix
9+ import cv2 as cv # type: ignore
10+
11+ def get_image_data_grayscale (img_path ):
12+ img = cv .imread (img_path )
13+ img = cv .cvtColor (img , cv .COLOR_BGR2GRAY )
14+ return img
15+
16+ selection = create_selection_matrix ()
17+
18+ # (Little endian) unsigned bytes
19+ def get_raw_height (process ):
20+ return struct .unpack ("<80400B" , process .read_section ('1045' ))
21+
22+ def set_raw_height (process , data ):
23+ bytes_data = struct .pack ("<80400B" , * data )
24+ # ChangedLayer
25+ process .write_bytes (0x01c5ad88 , b'\x02 ' * 80400 ) # TODO: fix
26+ # Logical terrain height layer: DefaultHeightLayer
27+ process .write_section ('1045' , bytes_data )
28+ # Visual height layer, I think also includes walls and towers: HeightLayer
29+ process .write_section ('1005' , bytes_data )
30+ # LogicLayer
31+ process .write_section ('1003' , struct .pack ("<80400I" , * ((v & 0xffffff7f ) for v in struct .unpack ("<80400I" , process .read_section ('1003' )))))
32+ # Logic2Layer
33+ process .write_section ('1037' , b'\x04 ' * 80400 )
34+
35+ # def post_process_raw_height():
36+ # # MiscDisplayLayer
37+ # process.write_section('1007', struct.pack("<80400H", *(((v & 0xffdf) & 0xf83f) for v in struct.unpack("<80400H", process.read_section('1007')))))
38+ # # LogicLayer, what a hot mess, probably not all required
39+ # process.write_section('1003', struct.pack("<80400I", *(((((v & 0x5f81c436) & 0xffffff7f) & 0xbfffbfff) | 32768) for v in struct.unpack("<80400I", process.read_section('1003')))))
40+ # # Logic2Layer
41+ # process.write_section('1037', b'\x04' * 80400)
42+ # # TODO: wall owner layer, and special logic2layer set to 4 or 8 depending on plateau
43+ # # ChangedLayer
44+ # process.write_bytes(0x01c5ad88, b'\x02' * 80400)
45+
46+
47+ # post_process_raw_height()
48+
49+
50+ def set_height (args ):
51+ #' returns None in case of non applicable
52+ if args .what != 'height' :
53+ return None
54+
55+ if args .action != "set" :
56+ return None
57+
58+ img_path = args .input
59+ validate_path (img_path )
60+
61+ img = get_image_data_grayscale (img_path )
62+
63+ process = get_process_handle (args .game )
64+
65+ set_raw_height (process , img [selection ].flat )
66+
67+ return True
0 commit comments