From 4f6633db18e2213a151782d995486491c8db3ff7 Mon Sep 17 00:00:00 2001 From: Treeki Date: Mon, 25 Jul 2011 03:16:21 +0200 Subject: Random tiles added. Untested. --- NewerProject.yaml | 1 + include/game.h | 57 ++++++++++++++++++++ kamek_ntsc.x | 7 +++ kamek_ntsc2.x | 7 +++ kamek_pal.x | 7 +++ kamek_pal2.x | 7 +++ randtilegen.rb | 95 ++++++++++++++++++++++++++++++++ randtiles.yaml | 26 +++++++++ src/randtiles.cpp | 158 ++++++++++++++++++++++++++++++++++++++++++++++++------ src/randtiles.h | 80 ++++++++++++--------------- 10 files changed, 381 insertions(+), 64 deletions(-) create mode 100644 randtilegen.rb create mode 100644 randtiles.yaml diff --git a/NewerProject.yaml b/NewerProject.yaml index ee2ee77..3af233a 100644 --- a/NewerProject.yaml +++ b/NewerProject.yaml @@ -7,6 +7,7 @@ modules: - processed/worldmap.yaml - processed/levelnames.yaml - processed/animtiles.yaml +# - processed/randtiles.yaml - processed/spritetex.yaml # - processed/gakenoko.yaml - processed/poweruphax.yaml diff --git a/include/game.h b/include/game.h index 7f8dba6..3c631c6 100755 --- a/include/game.h +++ b/include/game.h @@ -40,6 +40,8 @@ inline void *GetDVDClass2() { void *DVD_GetFile(void *dvdclass2, const char *arc, const char *file); void *DVD_GetFile(void *dvdclass2, const char *arc, const char *file, u32 *length); +int MakeRandomNumber(int count); + extern int Player_Active[4]; extern int Player_ID[4]; @@ -2012,5 +2014,60 @@ namespace m2d { } + +/* Tilemap related stuff */ +class TilemapClass { + public: + virtual ~TilemapClass(); + + u16 *allocatedBlocks[256]; + u32 _404; + + u8 blockLookup[2048]; + + u16 blockCount; + + u32 _C0C; + u32 ts1ID, ts2ID, ts3ID, layerID, areaID, frmHeap, is2Castle; + + // Only the public API is listed + u16 *getPointerToTile(int x, int y, u32 *blockNum = 0, bool unkBool = 0); + // TODO: more? +}; + +class BGDatClass { + public: + BGDatClass(); + virtual ~BGDatClass(); + + u8 *bgData[4][3]; + TilemapClass *tilemaps[4][3]; + u8 *tsObjIndexData[4][4]; + u8 *tsObjData[4][4]; + char tsNames[4][4][0x20]; + // this is fucked up! + // the parent heap is frmHeaps[0][0] + // each tileset's heap is frmHeaps[AREA][LAYER+1] + void *frmHeaps[4][4]; + + static BGDatClass *instance; // 8042A0D0 + + // I've only listed the public API because other stuff isn't really needed atm. + const char *getTilesetName(int area, int number); + // TODO: more? +}; + +struct BGRender { + u8 unk[0xC00]; + u8 *objectData; + u8 _C04, _C05; + u16 _C06, _C08; + u16 blockNumber; + u16 curX, curY; + u16 tileToPlace; + u16 objDataOffset, objType, objX, objY, objWidth, objHeight; + u16 tileNumberWithinBlock, areaID; +}; + #endif diff --git a/kamek_ntsc.x b/kamek_ntsc.x index 8620d1c..da5f3dd 100644 --- a/kamek_ntsc.x +++ b/kamek_ntsc.x @@ -520,8 +520,13 @@ SECTIONS { GameHeaps = 0x80377C48; BGDatClass = 0x80429DF0; + instance__10BGDatClass = 0x80429DF0; GetTilesetName__FPvii = 0x800813F0; + getTilesetName__10BGDatClassFii = 0x800813F0; + + getPointerToTile__12TilemapClassFiiPUib = 0x80083B40; + IsWideScreen__Fv = 0x800B54B0; Player_Active = 0x80354E50; @@ -998,6 +1003,8 @@ SECTIONS { GetRandomSeed = 0x800B2EC0; RandomSeed = 0x80429F44; + MakeRandomNumber__Fi = 0x800B2EE0; + StrangeReplayValue1 = 0x8042792E; StrangeReplayValue2 = 0x80429D69; StrangeReplayValue3 = 0x80429D6A; diff --git a/kamek_ntsc2.x b/kamek_ntsc2.x index 5a2f6b6..5fc9d3b 100644 --- a/kamek_ntsc2.x +++ b/kamek_ntsc2.x @@ -520,8 +520,13 @@ SECTIONS { GameHeaps = 0x80377C48; BGDatClass = 0x80429DF0; + instance__10BGDatClass = 0x80429DF0; GetTilesetName__FPvii = 0x800813F0; + getTilesetName__10BGDatClassFii = 0x800813F0; + + getPointerToTile__12TilemapClassFiiPUib = 0x80083B40; + IsWideScreen__Fv = 0x800B54B0; Player_Active = 0x80354E50; @@ -998,6 +1003,8 @@ SECTIONS { GetRandomSeed = 0x800B2EC0; RandomSeed = 0x80429F44; + MakeRandomNumber__Fi = 0x800B2EE0; + StrangeReplayValue1 = 0x8042792E; StrangeReplayValue2 = 0x80429D69; StrangeReplayValue3 = 0x80429D6A; diff --git a/kamek_pal.x b/kamek_pal.x index 72adf91..c7a2fb7 100644 --- a/kamek_pal.x +++ b/kamek_pal.x @@ -520,8 +520,13 @@ SECTIONS { GameHeaps = 0x80377F48; BGDatClass = 0x8042A0D0; + instance__10BGDatClass = 0x8042A0D0; GetTilesetName__FPvii = 0x800813F0; + getTilesetName__10BGDatClassFii = 0x800813F0; + + getPointerToTile__12TilemapClassFiiPUib = 0x80083B40; + IsWideScreen__Fv = 0x800B5500; Player_Active = 0x80355150; @@ -998,6 +1003,8 @@ SECTIONS { GetRandomSeed = 0x800B2EC0; RandomSeed = 0x8042A224; + MakeRandomNumber__Fi = 0x800B2EE0; + StrangeReplayValue1 = 0x80427C2E; StrangeReplayValue2 = 0x8042A049; StrangeReplayValue3 = 0x8042A04A; diff --git a/kamek_pal2.x b/kamek_pal2.x index 8f9b2ca..8e1321a 100644 --- a/kamek_pal2.x +++ b/kamek_pal2.x @@ -520,8 +520,13 @@ SECTIONS { GameHeaps = 0xDEADBEEF; BGDatClass = 0xDEADBEEF; + instance__10BGDatClass = 0xDEADBEEF; GetTilesetName__FPvii = 0xDEADBEEF; + getTilesetName__10BGDatClassFii = 0xDEADBEEF; + + getPointerToTile__12TilemapClassFiiPUib = 0xDEADBEEF; + IsWideScreen__Fv = 0xDEADBEEF; Player_Active = 0xDEADBEEF; @@ -998,6 +1003,8 @@ SECTIONS { GetRandomSeed = 0xDEADBEEF; RandomSeed = 0xDEADBEEF; + MakeRandomNumber__Fi = 0xDEADBEEF; + StrangeReplayValue1 = 0xDEADBEEF; StrangeReplayValue2 = 0xDEADBEEF; StrangeReplayValue3 = 0xDEADBEEF; diff --git a/randtilegen.rb b/randtilegen.rb new file mode 100644 index 0000000..f77d333 --- /dev/null +++ b/randtilegen.rb @@ -0,0 +1,95 @@ +class RandTileGenerator + def initialize + @sections = {} + end + + def section(name) + @sections[name] ||= {entries: []} + @current_section = @sections[name] + + yield + end + + def random(range, type=:both, numbers=nil) + numbers = range if numbers.nil? + + @current_section[:entries] << {range: range, type: type, numbers: numbers.to_a} + end + + def pack + # first, work out an offset for every section and entry + # also, collect the data for each individual entry into an Array + current_offset = 8 + (@sections.count * 4) + all_entry_data = [] + + @sections.each_pair do |name, section| + section[:offset] = current_offset + current_offset += 8 + + section[:entries].each do |entry| + entry[:offset] = current_offset + all_entry_data << entry[:numbers] + current_offset += 8 + end + end + + # assign an offset to each piece of entry data + data_offsets = {} + all_entry_data.uniq! + + all_entry_data.each do |data| + data_offsets[data] = current_offset + current_offset += data.size + end + + # assign an offset to each section name + name_offsets = {} + @sections.keys.each do |name| + name_offsets[name] = current_offset + current_offset += name.size + 1 + end + + # now pack it all together + header = ['NwRT', @sections.count].pack('a4 N') + offsets = @sections.each_value.map{|s| s[:offset]}.pack('N*') + + section_data = @sections.each_pair.map do |name, section| + name_offset = name_offsets[name] - section[:offset] + entry_count = section[:entries].count + + entry_data = section[:entries].map do |entry| + lower_bound = entry[:range].min + upper_bound = entry[:range].max + + count = entry[:numbers].count + type = [:none, :horz, :vert, :both].index(entry[:type]) + + num_offset = data_offsets[entry[:numbers]] - entry[:offset] + + [lower_bound, upper_bound, count, type, num_offset].pack('CCCC N') + end + + [name_offset, entry_count].pack('NN') + entry_data.join + end + + output = [header, offsets] + output += section_data + output += all_entry_data.map{|data| data.pack('C*')} + output << @sections.keys.join("\0") + output << "\0" + output.join + end +end + + +g = RandTileGenerator.new +g.section('TestTileset') do + g.random(1..20) + g.random(21..24, :none) + g.random(250..255, :vert, 0..5) +end + +File.open('/home/me/Games/Newer/DolphinPatch/NewerRes/RandTiles.bin', 'wb') do |f| + f.write g.pack +end + diff --git a/randtiles.yaml b/randtiles.yaml new file mode 100644 index 0000000..5ee73aa --- /dev/null +++ b/randtiles.yaml @@ -0,0 +1,26 @@ +--- +source_files: [../src/randtiles.cpp] +hooks: + - name: ModifyTilemapClassSize + type: patch + addr_pal: 0x80083598 + data: '3860 0C3C' + + - name: LoadRandTiles + type: branch_insn + branch_type: b + src_addr_pal: 0x8015BCD0 + target_func: 'RandTileLoadHook' + + - name: HookIdentifyTilesets + type: branch_insn + branch_type: bl + src_addr_pal: 0x800838AC + target_func: 'IdentifyTilesets' + + - name: HookTilePlacer + type: branch_insn + branch_type: bl + src_addr_pal: 0x80086B48 + target_func: 'TryAndRandomise' + diff --git a/src/randtiles.cpp b/src/randtiles.cpp index c7388dd..4af3bf7 100644 --- a/src/randtiles.cpp +++ b/src/randtiles.cpp @@ -1,22 +1,146 @@ -#include "randtiles.h" - -u32 djb2(u8 *str) { - u32 hash = 5381; - int c; - - while (c = *str++) - hash = ((hash << 5) + hash) + c; - - return hash; -} +#include + +class RandomTileData { +public: + enum Type { + CHECK_NONE = 0, + CHECK_HORZ = 1, + CHECK_VERT = 2, + CHECK_BOTH = 3 + }; + + class Entry { + public: + u8 lowerBound, upperBound; + u8 count, type; + u32 tileNumOffset; + + u8 *getTileNums() { + return ((u8*)this) + tileNumOffset; + } + }; + + class Section { + public: + u32 nameOffset; + u32 entryCount; + Entry entries[1]; // variable size + + const char *getName() { + return ((char*)this) + nameOffset; + } + }; + + u32 magic; + u32 sectionCount; + u32 offsets[1]; // variable size + + Section *getSection(int id) { + return (Section*)(((char*)this) + offsets[id]); + } + + Section *getSection(const char *name); + + static RandomTileData *instance; +}; -RandTiles_Section *RandTiles_Search(void *file, u32 nameHash) { - for (int i = 0; i < RandTiles_GetSectionCount(file); i++) { - RandTiles_Section *sect = RandTiles_GetSection(file, i); - - if (sect->nameHash == nameHash) +class RTilemapClass : public TilemapClass { +public: + // NEWER ADDITIONS + RandomTileData::Section *sections[4]; +}; + +RandomTileData::Section *RandomTileData::getSection(const char *name) { + for (int i = 0; i < sectionCount; i++) { + RandomTileData::Section *sect = getSection(i); + + if (strcmp(name, sect->getName()) == 0) { return sect; + } } - + return 0; } + + +// Real tile handling code + +RandomTileData *RandomTileData::instance = 0; + +dDvdLoader_c RandTileLoader; + +extern "C" bool RandTileLoadHook() { + OSReport("Trying to load..."); + void *buf = RandTileLoader.load("/NewerRes/RandTiles.bin"); + if (buf == 0) { + OSReport("Failed.\n"); + return false; + } else { + OSReport("Successfully loaded RandTiles.bin.\n"); + RandomTileData::instance = (RandomTileData*)buf; + return true; + } +} + + +extern "C" void IdentifyTilesets(RTilemapClass *self) { + self->_C0C = 0xFFFFFFFF; + + for (int i = 0; i < 4; i++) { + const char *tilesetName = BGDatClass::instance->getTilesetName(self->areaID, i); + + self->sections[i] = RandomTileData::instance->getSection(tilesetName); + } +} + +extern "C" void TryAndRandomise(RTilemapClass *self, BGRender *bgr) { + int fullTile = bgr->tileToPlace & 0x3FF; + int tile = fullTile & 0xFF; + int tileset = fullTile >> 8; + + RandomTileData::Section *rtSect = self->sections[tileset]; + if (rtSect == 0) + return; + + for (int i = 0; i < rtSect->entryCount; i++) { + RandomTileData::Entry *entry = &rtSect->entries[i]; + + if (tile >= entry->lowerBound && tile <= entry->upperBound) { + // Found it!! + // Try to make one until we meet the conditions + u8 *tileNums = entry->getTileNums(); + u8 chosen = 0xFF; + + u16 *top = 0, *left = 0, *right = 0, *bottom = 0; + if (entry->type == RandomTileData::CHECK_HORZ || entry->type == RandomTileData::CHECK_BOTH) { + left = self->getPointerToTile(bgr->curX - 1, bgr->curY); + right = self->getPointerToTile(bgr->curX + 1, bgr->curY); + } + + if (entry->type == RandomTileData::CHECK_VERT || entry->type == RandomTileData::CHECK_BOTH) { + top = self->getPointerToTile(bgr->curX, bgr->curY - 1); + bottom = self->getPointerToTile(bgr->curX, bgr->curY + 1); + } + + while (true) { + chosen = tileNums[MakeRandomNumber(entry->count)]; + + if (top != 0 && *top == chosen) + continue; + if (bottom != 0 && *bottom == chosen) + continue; + if (left != 0 && *left == chosen) + continue; + if (right != 0 && *right == chosen) + continue; + break; + } + + bgr->tileToPlace = chosen; + + return; + } + } +} + + diff --git a/src/randtiles.h b/src/randtiles.h index ab2553d..03005b2 100644 --- a/src/randtiles.h +++ b/src/randtiles.h @@ -2,62 +2,48 @@ #define __NEWER_RANDTILES_H #include -#include "fileload.h" -#define RAND_CHECK_HORZ -#define RAND_CHECK_VERT -#define RAND_CHECK_BOTH +class RandomTileData { + enum Type { + CHECK_NONE = 0, + CHECK_HORZ = 1, + CHECK_VERT = 2, + CHECK_BOTH = 3 + }; + + class Entry { + u8 startTile, endTile; + u8 count, type; + u32 dataOffset; + + u8 *getData() { + return ((u8*)this) + dataOffset; + } + }; + + class Section { + u32 nameHash; + u32 nameOffset; + u32 entryCount; + Entry entries[1]; // variable size + + const char *getName() { + return ((char*)this) + nameOffset; + } + }; -struct RandTiles_Header { u32 magic; u32 sectionCount; -}; - -struct RandTiles_Section { - u32 nameHash; - u32 entryCount; -}; - -struct RandTiles_Entry { - u16 startTile; - u16 endTile; - u8 count; - u8 type; - u16 reserved; - u32 dataOffset; -}; + u32 offsets[1]; // variable size -inline u32 RandTiles_GetSectionCount(void *file) { - return ((RandTiles_Header*)file)->sectionCount; -} + Section *getSection(int id) { + return (Section*)(((char*)this) + offsets[id]); + } -inline u32 *RandTiles_GetOffsets(void *file) { - return (u32*)(((RandTiles_Header*)file)+1); -} - -inline RandTiles_Section *RandTiles_GetSection(void *file, int id) { - u32 offs = RandTiles_GetOffsets(file)[id]; - return (RandTiles_Section*)(((char*)file)+offs); + Section *getSection(char *name); }; -inline RandTiles_Entry *RandTiles_GetTiles(void *file, RandTiles_Section *section) { - return (RandTiles_Entry*)(section+1); -} - -inline RandTiles_Entry *RandTiles_GetTiles(void *file, int sectionID) { - return (RandTiles_Entry*)(RandTiles_GetSection(file, sectionID)+1); -} - -inline char *RandTiles_GetName(void *file, RandTiles_Section *section) { - return ((char*)file)+section->nameOffset; -} - -inline u16 *RandTiles_GetData(void *file, RandTiles_Entry *entry) { - return (u16*)(((char*)file)+entry->dataOffset); -} - u32 djb2(u8 *str); -RandTiles_Section *RandTiles_Search(void *file, u32 nameHash); #endif -- cgit v1.2.3