summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--NewerProject.yaml1
-rwxr-xr-xinclude/game.h57
-rw-r--r--kamek_ntsc.x7
-rw-r--r--kamek_ntsc2.x7
-rw-r--r--kamek_pal.x7
-rw-r--r--kamek_pal2.x7
-rw-r--r--randtilegen.rb95
-rw-r--r--randtiles.yaml26
-rw-r--r--src/randtiles.cpp158
-rw-r--r--src/randtiles.h80
10 files changed, 381 insertions, 64 deletions
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 <game.h>
+
+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 <common.h>
-#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