Update part 2
import numpy as np import os BLOAD_HEADER = ('bload_header', (np.uint8, 7)) BLOAD_SIZE = 7
H = np.int16 def fieldlist_to_dtype (fields): fields = fields.split() return [(field,H) for field in fields] def mmap (fname, dtype, offset = 0, shape = None): return np.memmap (fname, dtype = dtype, mode = 'r', offset = offset, shape = shape) def from_fieldnames (*allnames, **corrections): names = [] formats = [] for somenames in allnames: somenames = somenames.split() names.extend (somenames) formats.extend ([H] * len (somenames)) for name, format in corrections.items(): formats[names.index(name)] = format return {'names': names, 'formats': formats} make = from_fieldnames def fvstr (maxlen): return [('length', H), ('value', (np.character, maxlen))] # some formats have all the x, then all the y, .. def planar_dtype (fieldnames, num, dtype, bload = False): dt = [] if bload: dt.append (BLOAD_HEADER) for field in fieldnames.split(): dt.append ((field, (dtype, num))) return np.dtype (dt) def fix_stringjunk (arr, fields = None, doubled = False): fields = fields or arr.dtype.names for name in fields: for item in arr[name]: if doubled: tmp = str(item['value'])[:item['length'] * 2] tmp = list(tmp) tmp[1::2] = ['.'] * (len (tmp) / 2) tmp = "".join (tmp) else: tmp = str(item['value'])[:item['length']] item['value'] = tmp def pad (filename, granularity, groupsize = 1, headersize = 0): filesize = os.path.getsize (filename) nrecordsets = (filesize - headersize) / float (granularity * groupsize) padding = '' fullrecordsize = (int (nrecordsets) * (granularity * groupsize)) + headersize if fullrecordsize < filesize: nrecordsets = round (nrecordsets + 0.499999999999) padding = '\x00' * (int (nrecordsets) * (granularity * groupsize) - filesize) if padding == '': return int (nrecordsets) / groupsize f = open (filename, 'ab') f.seek (1, 2) f.write (padding) f.close () filesize = os.path.getsize (filename) nrecords = (filesize - headersize) / granularity return nrecords class fixBits (object): fields = ['attackitems', 'weappoints', 'stuncancel', 'defaultdissolve', 'defaultdissolveenemy', 'pushnpcbug_compat', 'default_maxitem', 'blankdoorlinks', 'shopsounds', 'extended_npcs', 'heroportrait', 'textbox_portrait', 'npclocation_format', ] def __init__ (self, filename, **kwargs): self.file = open (filename, 'rwb+') for k, v in kwargs.items(): setattr (self, k, v) def save (self, f): self.file.seek (0) f.write (self.file.read()) def tostring (self): self.file.seek (0) return self.file.read() def __getitem__ (self, k): return self.__getattr__ (self.fields[k]) def __setitem__ (self, k, v): self.__setattr__ (self.fields[k], v) def __getattr__ (self, k): try: k = object.__getattribute__ (self, 'fields').index (k) except ValueError: return object.__getattribute__ (self, k) self.file.seek (k / 8) result = ord (self.file.read(1)) & (1 << k % 8) if result > 0: return 1 else: return 0 def __setattr__ (self, k, v): try: k = object.__getattribute__ (self, 'fields').index (k) except ValueError: object.__setattr__ (self, k, v) return self.file.seek (k / 8) value = ord (self.file.read (1)) if value & (1 << k % 8): value ^= (1 << k % 8) if v: value |= (1 << k % 8) self.file.seek (k / 8) self.file.write (chr (value)) def __repr__ (self): kwargs = ", ".join (['%s = %d' % (name, v) for name, v in zip (self.fields, self)]) return "%s (%r, %s)" % (self.__class__.__name__, self.file.name, kwargs) def __iter__ (self): return [getattr (self, k) for k in self.fields].__iter__() def __gc__ (self): self.file.close() class archiNym (object): def __init__ (self, filename, **args): self.file = open (filename, 'rwb+') for k, v in enumerate (args): self[k] = v def __getitem__ (self, k): assert (-1 < k < 2) self.file.seek (0) for i in range (k): self.file.readline() return self.file.readline().rstrip() def __setitem__ (self, k, v): assert (-1 < k < 2) everything = [self[0], self[1]] self.file.seek (0) everything [k] = v for value in everything: self.file.write (value + '\x0d\x0a') def __repr__ (self): return '%s (%r, %r, %r)' % (self.__class__.__name__, self.file.name, self[0], self[1]) def _getprefix (self): return self[0] def _setprefix (self, v): self[0] = v def _getversion (self): return self[1] def _setversion (self, v): self[1] = v prefix = property (_getprefix, _setprefix) version = property (_getversion, _setversion) def set_str16 (dest, src): # 16bit/8bit len, 16bit chars assert len (src) <= (len (dest['value']) / 2) dest['length'] = len(src) dest['value'] = "".join([char + '.' for char in src] + ['\x00\x00']) def set_str8 (dest, src): # 16 or 8bit header, 8bit chars assert len (src) <= len (dest['value']) dest['length'] = len(src) dest['value'] = src + '\x00' def get_str16 (src): return src['value'][::2] def get_str8 (src): return src['value'] # set_str?? zero 'junk' bytes (happens automatically courtesy of numpy.) def adjust_for_binsize (dtype, binsize): dtsize = np.dtype (dtype).itemsize while dtsize > binsize: dtype['names'].pop() dtype['formats'].pop() dtsize = np.dtype (dtype).itemsize if dtsize != binsize: raise ValueError ('dtype is misaligned with binsize!') def vstr (len): "dtype of an OHRRPGCE string (BYTE length, BYTE-based characters) totaling ``len`` bytes" return [('length', np.uint8),('value', (np.character, len - 1))] def vstr2 (len): "dtype of an OHRRPGCE string (SHORT length, SHORT-based characters) totaling ``len`` bytes" return [('length', np.uint16),('data', (np.character, (len - 1) * 2))] _statlist = 'hp mp str acc def dog mag wil spd ctr foc xhits'.split() STATS_DTYPE = [(name, H) for name in _statlist] STATS0_99_DTYPE = [(name, (H, 2)) for name in _statlist] xycoord_dtype = [('x', H), ('y',H)] _browse_base_dtype = [('length', H), ('value', (np.character, 38))] _rgb16_dtype = [('r', np.uint16,), ('g', np.uint16), ('b', np.uint16)] _saychoice_dtype = [('name' , [('length', 'B'), ('value', 'S14')]), ('tag', H)] _saytagpair_dtype = [('tagcheck', H), ('param', H)] _say_conditionals_dtype = [('jumptoinstead', _saytagpair_dtype), ('settag', [('tagcheck', H), ('tagset1', H), ('tagset2', H)])] _say_conditionals_dtype += [('fight', _saytagpair_dtype), ('shop', _saytagpair_dtype)] _say_conditionals_dtype += [('hero', _saytagpair_dtype), ('jumptoafter', _saytagpair_dtype)] _say_conditionals_dtype += [('money', _saytagpair_dtype), ('usedoor', _saytagpair_dtype)] _say_conditionals_dtype += [('items', [('tagcheck', H), ('item', H), ('heroswap', H), ('herolock', H)])] ptshapes = ((32,40,8), (34, 34, 1), (50, 50, 1), (80, 80, 1), (20, 20, 8), (24, 24, 2), (50, 50, 3), (16, 16, 16), (50, 50, 1)) """Shapes of pt? graphics data.""" _spell_list = ([('attack', H), ('level', H)], (4, 24)) dtypes = { # the totality of attack data (concatenated from DT0 and ATTACK.BIN) '_attack' : make ('picture palette animpattern targetclass targetsetting', 'damage_eq aim_math baseatk_stat cost xdamage chainto chain_percent', 'attacker_anim attack_anim attack_delay nhits target_stat', 'preftarget bitsets1 name captiontime caption basedef_stat', 'settag tagcond tagcheck settag2 tagcond2 tagcheck2 bitsets2', 'description consumeitem nitems_consumed soundeffect', 'stat_preftarget', bitsets1 = ('B', 64 / 8), bitsets2 = ('B', 128 / 8), cost = [('hp', H), ('mp', H), ('money', H)], name = [('length', H), ('unused', H), ('value', (H, 10))], caption = fvstr (38), description = fvstr (38)), 'attack.bin' : make ('captionpt2 basedef_stat', 'settag tagcond tagcheck settag2 tagcond2 tagcheck2 bitsets2', 'description consumeitem nitems_consumed soundeffect', 'stat_preftarget', bitsets2 = ('B', 128 / 8), captionpt2 = 'S36', description = fvstr (38), consumeitem = (H, 3), nitems_consumed = (H, 3)), 'binsize.bin' : make ('attack.bin stf songdata.bin sfxdata.bin map', 'menus.bin menuitem.bin uicolors.bin say'), 'browse.txt' : [('longname', _browse_base_dtype), ('about', _browse_base_dtype)], 'defpass.bin' : [('passability', (H, 160)), ('magic', H)], 'defpal%d.bin' : [('palette', H)], 'd' : planar_dtype ('srcdoor destdoor destmap condtag1 condtag2', 100, H), 'dox' : planar_dtype ('x y bitsets',100, H), 'dt0' : make ('name battlesprite battlepalette walksprite walkpalette defaultlevel defaultweapon', 'stats spells portrait bitsets spelllist_name portrait_palette spelllist_type', 'have_tag alive_tag leader_tag active_tag', 'maxnamelength handcoord', " ".join (["%sframe" % name for name in 'stand step attacka attackb cast hurt weak dead \ dead2 targetting victorya victoryb'.split()]), 'unused', name = vstr2 (17), stats = STATS0_99_DTYPE, spells = _spell_list, bitsets = (np.uint8, 48 / 8), spelllist_name = ([('length', H), ('value', (np.character, 10*2))], 4), spelllist_type = (H, 4), handcoord = (xycoord_dtype, 2), unused = (H, 5)), 'dt1' : make ('name thievability stealable_item stealchance', 'raresteal_item raresteal_chance dissolve dissolvespeed', 'deathsound unused picture palette picsize rewards stats', 'bitsets spawning attacks unused2', name = vstr2 (17), rewards = make ('gold exp item itemchance rareitem rareitemchance'), bitsets = ('B', 10), spawning = make ('death non_e_death alone non_e_hit', 'elemhit n_tospawn', elemhit = (H, 8)), attacks = [('regular', (H, 5)), ('desperation', (H, 5)), ('alone', (H, 5)), ('counter', (H, 8))], stats = STATS_DTYPE, unused = (H, 28), unused2 = (H, 45)), 'dt6' : make ('picture palette animpattern targetclass targetsetting', 'damage_eq aim_math baseatk_stat cost xdamage chainto chain_percent', 'attacker_anim attack_anim attack_delay nhits target_stat', 'preftarget bitsets1 name captiontime captionpt1', bitsets1 = ('B', 64 / 8), cost = [('hp', H), ('mp', H), ('money', H)], name = [('length', H), ('unused', H), ('value', 'S20')], captionpt1 = fvstr (4)), 'efs' : [('frequency', H),('formations',(H, 20)), ('wasted', (H, 4))], 'for' : make ('enemies background music backgroundframes backgroundspeed unused', enemies = (make ('type x y unused'), 8), unused = (H, 4)), 'fnt' : (np.uint8, (256, 8)), 'gen' : make ('maxmap title titlemusic victorymusic battlemusic', 'passcodeversion passcoderotator newpasscode newpasscode_unused', 'oldpasscode', " ".join(['max%spic' % name for name in 'hero','enemy1','enemy2','enemy3','npc','weapon','attack']), " ".join(['max%s' % name for name in 'tileset','attack','hero', 'enemy', 'formation','palette','textbox','plotscript']), 'newgamescript gameoverscript max_regularscript suspendbits cameramode', 'camera_args scriptbackdrop time maxvehicle maxtagname', 'loadgamescript textbox_backdrop enemydissolve enablejoy', 'poison stun damagecap mute statcap maxsfx masterpal', 'maxmasterpal maxmenu maxmenuitem maxitem max_boxborder', 'maxportrait maxinventory reserved', 'oldpassword2_offset oldpassword2_length version startmoney', 'maxshop oldpassword1_offset oldpassword1_length maxbackdrop', 'bitsets startx starty startmap onetimenpc_indexer', 'onetimenpc_bits', 'def_deathsfx maxsong acceptsfx cancelsfx choosesfx textboxletter', 'morebitsets itemlearnsfx cantlearnsfx buysfx hiresfx sellsfx', 'cantbuysfx cantsellsfx wastedspace oldsctable_head oldsctable', 'unused', newpasscode = (np.uint8, 17), newpasscode_unused = np.uint8, oldpasscode = (H, 10), suspendbits = np.uint16, camera_args = (H, 4), time = (H, 4), statcap = (H, 12), reserved = (H, 7), bitsets = np.uint16, onetimenpc_bits = (np.uint8, 130), morebitsets = (np.uint8,4), wastedspace = (H,13), oldsctable_head = np.uint16, oldsctable = (np.uint16, 160), unused = (np.uint16, 140)), 'itm' : make ('name info value attack weaponattack equippable teach oobuse weaponpic weaponpal', 'bonuses equippableby bitsets consumability own_tag in_inventory_tag equipped_tag', 'equippedby_active_tag frame2handle frame1handle unused', name = vstr2 (9), info = vstr2(36), bonuses = STATS_DTYPE, equippableby = ('B', 8), bitsets = ('B', 6), frame2handle = xycoord_dtype, frame1handle = xycoord_dtype, unused = (H, 19)), 'l' : planar_dtype ('x y id dir walkframe',300,H, bload = True), 'map' : make ('tileset music minimap_available save_anywhere display_name_time', 'edge_mode edge_tile autorun_trigger autorun_arg harmtile_damage', 'harmtile_flash foot_offset afterbattle_trigger', 'insteadofbattle_trigger each_step_trigger keypress_trigger draw_herosfirst', 'npcanddoor_loading tileandwall_loading bitsets savoffset layer_tilesets', 'n_npc_instances', savoffset = xycoord_dtype, bitsets = ('B', 2), layer_tilesets = (H, 3)), 'mas' : _rgb16_dtype, 'mxs' : [('planes', (np.uint8, (4, 16000)))], 'menuitem.bin' : make ('membership caption sort_order type subtype', 'tagcond1 tagcond2 settag toggletag bitsets extra', extra = (H,3), bitsets = ('B',2), caption = fvstr (38)), 'menus.bin' : make ('name boxstyle default_textcolor maxrows bitsets offset anchor', 'textalign minwidth maxwidth border_thickness', name = fvstr (20), bitsets = ('B', 2), offset = xycoord_dtype, anchor = xycoord_dtype), 'mn' : [('name', [('length', 'B'), ('value', 'S79')])], 'n' : [BLOAD_HEADER, ('npcs', (make ('picture palette movetype speed showtext', 'activate_action giveitem pushability activation', 'appear_if_tag1 appear_if_tag2 usability trigger', 'script_arg vehicle'), 100))], 'pal' : ('B', 16), 'palettes.bin' : [('color', ([('r', np.uint8,), ('g', np.uint8), ('b', np.uint8)], 256))], 'plotscr.lst' : [('id', H), ('name', fvstr(36))], 'say' : make ('text reserved1 conditional reserved2 choicebitsets choice1 wasted choice2', 'menuconditional verticalpos shrink textcolor bordercolor backdrop music menu', 'portraittype portraitpic portraitpal portraitx portraity', text = ('S38', 8), reserved1 = 'B', conditional = _say_conditionals_dtype, reserved2 = 'B', choicebitsets = 'B', choice1 = _saychoice_dtype, wasted = 'B', choice2 = _saychoice_dtype), 'sfxdata.bin' : [('name', fvstr (30)), ('streaming', H)], 'sho' : [('name', vstr2 (16)), ('nitems', H), ('bitsets', ('B',2)), ('inncost', H), ('innscript', H)], 'songdata.bin' : [('name', fvstr (30))], '_stf_item' : make ('name type number in_stock buyreq_tag sellreq_tag buyset_tag sellset_tag', 'buyprice req_tradeitem1 selltype sellprice tradefor tradefor_amount', 'req_tradeitem1_n req_tradeitem2 req_tradeitem2_n req_tradeitem3', 'req_tradeitem3_n req_tradeitem4 req_tradeitem4_n', 'buyprice_defaulter sellprice_defaulter unused', name = vstr2 (17), unused = (H, 3)), 'tap' : [('starttile', H), ('disable_if_tag', H), ('actiontype', (H,9)), ('actionparam', (H,9))], 'tmn' : vstr2 (21), 'uicolors.bin' : make ('background menuitem disableditem selecteditem selecteddisabled', 'highlight timebar timebarfull healthbar healthbarflash text', 'outline description gold shadow textbox textboxframe', selecteditem = (H, 2), selecteddisabled = (H, 2), highlight = (H, 2), textbox = ([('bg', H), ('border', H)], 15), textboxframe = (H, 15)), 'veh' : make ('name speed bitsets randbattles usebutton menubutton ridingtag onmount', 'ondismount overridewalls blockedby mountfrom dismount_to elevation reserved', name = vstr (16), bitsets = (np.uint8, 4), reserved = (H, 18)), } del _browse_base_dtype dtypes['til'] = dtypes['mxs'] for i, data in enumerate (ptshapes): w, h, frames = data dtypes['pt%d' % i] = [('pixels', (np.uint8, (w/2) * h * frames))] del w, h, frames, i, data STT_LENGTHS = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 1, 2, 1, 2, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 1, 3, 3, 3, 2, 2, 1, 1, 1, 1, 1, 1, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1] STT_NAMES = ['Health_Points', 'Spell_Points', 'Attack_Power', 'Accuracy', 'Extra_Hits', 'Blocking_Power', 'Dodge_Rate', 'Counter_Rate', 'Speed', 'Enemy_Type_1', 'Enemy_Type_2', 'Enemy_Type_3', 'Enemy_Type_4', 'Enemy_Type_5', 'Enemy_Type_6', 'Enemy_Type_7', 'Enemy_Type_8', 'Elemental_1', 'Elemental_2', 'Elemental_3', 'Elemental_4', 'Elemental_5', 'Elemental_6', 'Elemental_7', 'Elemental_8', 'Armor_1', 'Armor_2', 'Armor_3', 'Armor_4', 'Spell_Skill', 'Spell_Block', 'Spell_cost__', 'Money', 'Experience', 'Item', 'DONE', 'AUTOSORT', 'TRASH', 'Weapon', '_REMOVE_', '_EXIT_', 'Discard', 'Cannot', 'Level', 'Yes', 'No', 'EXIT', 'for_next', 'REMOVE', 'Pay', 'Cancel', 'CANCEL', 'NEW_GAME', 'EXIT2', 'PAUSE', 'Quit_Playing_', 'Yes2', 'No2', 'CANCEL2', 'Items', 'Spells', 'Status', 'Equip', 'Order', 'Team', 'Save', 'Quit', 'Map', 'Volume', 'Buy', 'Sell', 'Inn', 'Hire', 'Exit', 'CANNOT_SELL', 'Worth', 'Trade_for', 'and_a', 'Worth_Nothing', 'Sold', 'Trade_for2', 'Joins_for', 'Cannot_Afford', 'Cannot_Hire', 'Purchased', 'Joined_', 'in_stock', 'Equip_', 'No_Room_In_Party', 'Replace_Old_Data_', "Who's_Status_", "Who's_Spells_", 'Equip_Who_', 'Nothing', 'Has_Nothing', 'Cannot_Steal', 'Stole', 'miss', 'fail', 'learned', 'Found', 'Gained', 'Weak_to', 'Strong_to', 'Absorbs', 'No_Elemental_Effects', 'has_no_spells', 'Which_Hero_', 'Name_the_Hero', 'Found_a', 'Found2', 'THE_INN_COSTS', 'You_have', 'CANNOT_RUN_', 'Level_up_for', 'levels_for', 'and', 'day', 'days', 'hour', 'hours', 'minute', 'minutes'] dtypes['stt'] = [(name, [('length','B'),('value', 'S%d' % (10 + ((length - 1) * 11)))]) for name, length in zip (STT_NAMES, STT_LENGTHS)] dtypes['stf'] = [('items', (dtypes['_stf_item'], 50))] #>>> fields += fieldlist_to_dtype ('randbattles usebutton menubutton ridingtag') #>>> fields += fieldlist_to_dtype ('onmount ondismount overridewalls blockedby') #>>> fields += fieldlist_to_dtype ('mountfrom dismount_to elevation') #>>> fields += [('reserved', (H, 18))]
_______________________________________________ Ohrrpgce mailing list ohrrpgce@lists.motherhamster.org http://lists.motherhamster.org/listinfo.cgi/ohrrpgce-motherhamster.org