diff --git a/src/platform/gba/common.cpp b/src/platform/gba/common.cpp index 75bf0a7..dccb102 100644 --- a/src/platform/gba/common.cpp +++ b/src/platform/gba/common.cpp @@ -9,6 +9,7 @@ int32 matrixStackIndex = 0; const FloorData* gLastFloorData; FloorData gLastFloorSlant; +TargetInfo tinfo; EWRAM_DATA SaveGame gSaveGame; EWRAM_DATA Settings gSettings; diff --git a/src/platform/gba/common.h b/src/platform/gba/common.h index 5bc14bd..3bead04 100644 --- a/src/platform/gba/common.h +++ b/src/platform/gba/common.h @@ -640,6 +640,14 @@ struct Room { Room** getVisibleRooms(); }; +enum NodeFlag { + NODE_FLAG_POP = (1 << 0), + NODE_FLAG_PUSH = (1 << 1), + NODE_FLAG_ROTX = (1 << 2), + NODE_FLAG_ROTY = (1 << 3), + NODE_FLAG_ROTZ = (1 << 4), +}; + struct Node { uint16 flags; vec3s pos; @@ -1159,24 +1167,29 @@ struct Item { uint16 frameIndex; uint8 state; - uint8 nextState; + uint8 nextState; // enemies only uint8 goalState; uint8 waterState; + int16 headOffset; // enemies only + int16 aggression; + int16 health; union { int16 timer; - int16 oxygen; + int16 oxygen; // Lara only + int16 radius; // enemies only }; - uint16 input; + uint16 input; // Lara only int16 turnSpeed; uint8 type; uint8 intensity; int16 roomFloor; - int32 hitMask; + uint32 hitMask; + uint32 visibleMask; union { uint8* extra; @@ -1606,6 +1619,17 @@ struct Level { const int32* soundOffsets; }; +// used by enemies +struct TargetInfo +{ + Item* target; + int16 angle; + int16 rotHead; + bool aim; +}; + +extern TargetInfo tinfo; + extern Level level; struct IMA_STATE { diff --git a/src/platform/gba/draw.h b/src/platform/gba/draw.h index 0fa5249..c93204e 100644 --- a/src/platform/gba/draw.h +++ b/src/platform/gba/draw.h @@ -103,7 +103,7 @@ void drawNumber(int32 number, int32 x, int32 y) } } -void drawMesh(int16 meshIndex) +void drawMesh(int32 meshIndex) { const uint8* ptr = (uint8*)meshes[meshIndex] + sizeof(Mesh); @@ -224,22 +224,41 @@ void drawNodes(const Item* item, const AnimFrame* frameA) { const Model* model = models + item->type; const Node* node = level.nodes + model->nodeIndex; + int32 meshIndex = model->start; + int32 meshCount = model->count; + uint32 visibleMask = item->visibleMask; const uint32* angles = (uint32*)(frameA->angles + 1); + const int16* extraAngles = (int16*)item->extra; matrixFrame(frameA->pos, angles); + if (visibleMask & 1) { + drawMesh(meshIndex); + } - drawMesh(model->start); - - for (int32 i = 1; i < model->count; i++) + while (meshCount > 1) { - if (node->flags & 1) matrixPop(); - if (node->flags & 2) matrixPush(); + meshIndex++; + visibleMask >>= 1; + angles++; - matrixFrame(node->pos, ++angles); + if (node->flags & NODE_FLAG_POP) matrixPop(); + if (node->flags & NODE_FLAG_PUSH) matrixPush(); - drawMesh(model->start + i); + matrixFrame(node->pos, angles); + if (extraAngles) + { + if (node->flags & NODE_FLAG_ROTY) matrixRotateY(*extraAngles++); + if (node->flags & NODE_FLAG_ROTX) matrixRotateX(*extraAngles++); + if (node->flags & NODE_FLAG_ROTZ) matrixRotateZ(*extraAngles++); + } + + if (visibleMask & 1) { + drawMesh(meshIndex); + } + + meshCount--; node++; } } @@ -254,9 +273,13 @@ void drawNodesLerp(const Item* item, const AnimFrame* frameA, const AnimFrame* f const Model* model = models + item->type; const Node* node = level.nodes + model->nodeIndex; + int32 meshIndex = model->start; + int32 meshCount = model->count; + uint32 visibleMask = item->visibleMask; const uint32* anglesA = (uint32*)(frameA->angles + 1); const uint32* anglesB = (uint32*)(frameB->angles + 1); + const int16* extraAngles = (int16*)item->extra; int32 t = FixedInvU(frameRate) * frameDelta; @@ -266,18 +289,34 @@ void drawNodesLerp(const Item* item, const AnimFrame* frameA, const AnimFrame* f posLerp.z = frameA->pos.z + ((frameB->pos.z - frameA->pos.z) * t >> 16); matrixFrameLerp(posLerp, anglesA, anglesB, frameDelta, frameRate); + if (visibleMask & 1) { + drawMesh(meshIndex); + } - drawMesh(model->start); - - for (int32 i = 1; i < model->count; i++) + while (meshCount > 1) { - if (node->flags & 1) matrixPop(); - if (node->flags & 2) matrixPush(); + meshIndex++; + visibleMask >>= 1; + anglesA++; + anglesB++; - matrixFrameLerp(node->pos, ++anglesA, ++anglesB, frameDelta, frameRate); + if (node->flags & NODE_FLAG_POP) matrixPop(); + if (node->flags & NODE_FLAG_PUSH) matrixPush(); - drawMesh(model->start + i); + matrixFrameLerp(node->pos, anglesA, anglesB, frameDelta, frameRate); + if (extraAngles) + { + if (node->flags & NODE_FLAG_ROTY) matrixRotateY(*extraAngles++); + if (node->flags & NODE_FLAG_ROTX) matrixRotateX(*extraAngles++); + if (node->flags & NODE_FLAG_ROTZ) matrixRotateZ(*extraAngles++); + } + + if (visibleMask & 1) { + drawMesh(meshIndex); + } + + meshCount--; node++; } } diff --git a/src/platform/gba/enemy.h b/src/platform/gba/enemy.h index 244a9b4..6c11a35 100644 --- a/src/platform/gba/enemy.h +++ b/src/platform/gba/enemy.h @@ -1,13 +1,22 @@ #ifndef H_ENEMY #define H_ENEMY +#include "common.h" #include "item.h" EWRAM_DATA ExtraInfoEnemy enemiesExtra[MAX_ENEMIES]; +enum AggressionLevel +{ + AGGRESSION_LVL_1 = 0x400, + AGGRESSION_LVL_2 = 0x2000, + AGGRESSION_LVL_3 = 0x4000, + AGGRESSION_LVL_MAX = 0x7FFF, +}; + struct Enemy : Item { - Enemy(Room* room, int32 hp) : Item(room) + Enemy(Room* room, int32 _health, int32 _radius, int32 _headOffset, uint32 _aggression) : Item(room) { flags.shadow = true; @@ -15,7 +24,10 @@ struct Enemy : Item angle.y += (rand_logic() - 0x4000) >> 1; #endif - health = hp; + health = _health; + radius = _radius; + headOffset = _headOffset; + aggression = _aggression; } void setExtra(ExtraInfoEnemy* extra) @@ -99,6 +111,31 @@ struct Enemy : Item extraE = NULL; } + void updateTargetInfo() + { + tinfo.target = getLara(pos); + + if (health <= 0) + { + tinfo.angle = 0; + tinfo.rotHead = 0; + tinfo.aim = false; + return; + } + + int32 dx = tinfo.target->pos.x - pos.x; + int32 dz = tinfo.target->pos.z - pos.z; + + if (headOffset) { + dx -= phd_sin(angle.y) * headOffset >> FIXED_SHIFT; + dz -= phd_cos(angle.y) * headOffset >> FIXED_SHIFT; + } + + tinfo.angle = phd_atan(dz, dx) - angle.y; + tinfo.aim = (tinfo.angle > -ANGLE_90) && (tinfo.angle < ANGLE_90); + tinfo.rotHead = tinfo.aim ? tinfo.angle : 0; + } + virtual void activate() { Item::activate(); @@ -110,31 +147,26 @@ struct Enemy : Item virtual void hit(int32 damage, const vec3i &point, int32 soundId) { - if (health > 0) { - health -= damage; + ASSERT(health > 0); - if (health <= 0) { - gSaveGame.kills++; - } - } + health -= damage; if (health > 0) { - if (type != ITEM_MUMMY) { - fxBlood(point, 0, 0); - } - if (soundId) { soundPlay(soundId, pos); } + } else { + gSaveGame.kills++; + } + + if (type != ITEM_MUMMY) { + fxBlood(point, 0, 0); } } virtual void collide(Lara* lara, CollisionInfo* cinfo) { - if (health <= 0) // TODO T-Rex still collide after death - return; - if (!extraE) // disabled return; @@ -159,11 +191,29 @@ struct Enemy : Item flags.status = ITEM_FLAGS_STATUS_ACTIVE; } - if (extraE) { - logic(); - } + if (!extraE) + return; + + updateTargetInfo(); + + logic(); + + extraE->rotHead = angleLerp(extraE->rotHead, tinfo.rotHead, ANGLE(5)); animProcess(); + + if (flags.status == ITEM_FLAGS_STATUS_INACTIVE) + { + flags.collision = false; + health = NOT_ENEMY; + disable(); + deactivate(); + return; + } + + // TODO collision, pathfinding + + updateRoom(); } virtual void logic() {} @@ -172,51 +222,166 @@ struct Enemy : Item struct Doppelganger : Enemy { - Doppelganger(Room* room) : Enemy(room, LARA_MAX_HEALTH) {} + Doppelganger(Room* room) : Enemy(room, LARA_MAX_HEALTH, 10, 0, 0) {} }; struct Wolf : Enemy { - Wolf(Room* room) : Enemy(room, 6) {} + enum { + HIT_MASK = 0x774F, // body, head, front legs + }; + + enum { + ANIM_DEATH = 20, + ANIM_DEATH_RUN, + ANIM_DEATH_JUMP, + }; + + enum { + STATE_NONE, + STATE_STOP, + STATE_WALK, + STATE_RUN, + STATE_JUMP, // unused + STATE_STALK, + STATE_ATTACK, + STATE_HOWL, + STATE_SLEEP, + STATE_GROWL, + STATE_TURN, // unused + STATE_DEATH, + STATE_BITE, + }; + + Wolf(Room* room) : Enemy(room, 6, 341, 375, AGGRESSION_LVL_2) + { + frameIndex = level.anims[animIndex].frameEnd; + } virtual void hit(int32 damage, const vec3i &point, int32 soundId) { Enemy::hit(damage, point, SND_HIT_WOLF); + + if (health <= 0) { + animSet(models[type].animIndex + ANIM_DEATH + (rand_logic() % 3), true); + } + } + + virtual void logic() + { + if (health <= 0) + return; + + // TODO + + if (state == STATE_SLEEP) { + goalState = STATE_STOP; + } } }; struct Bear : Enemy { - Bear(Room* room) : Enemy(room, 20) {} + enum { + HIT_MASK = 0x2406C, // front legs and head + }; + + enum { + STATE_WALK, + STATE_STOP, + STATE_HIND, + STATE_RUN, + STATE_STAND, + STATE_GROWL, + STATE_BITE, + STATE_ATTACK, + STATE_EAT, + STATE_DEATH, + }; + + Bear(Room* room) : Enemy(room, 20, 341, 500, AGGRESSION_LVL_3) {} virtual void hit(int32 damage, const vec3i &point, int32 soundId) { Enemy::hit(damage, point, SND_HIT_BEAR); } + + virtual void logic() + { + if (health <= 0) + { + switch (state) + { + case STATE_HIND: + goalState = STATE_STAND; + break; + case STATE_WALK: + case STATE_RUN: + goalState = STATE_STOP; + break; + case STATE_STOP: + case STATE_STAND: + goalState = STATE_DEATH; + break; + } + return; + } + + // TODO + } }; struct Bat : Enemy { - Bat(Room* room) : Enemy(room, 1) {} + enum { + STATE_NONE, + STATE_AWAKE, + STATE_FLY, + STATE_ATTACK, + STATE_CIRCLING, + STATE_DEATH, + }; + + Bat(Room* room) : Enemy(room, 1, 102, 0, AGGRESSION_LVL_1) {} + + virtual void logic() + { + if (health <= 0) + { + hSpeed = 0; + flags.gravity = (pos.y < roomFloor); + + if (flags.gravity) { + goalState = STATE_CIRCLING; + } else { + goalState = STATE_DEATH; + pos.y = roomFloor; + } + + return; + } + + // TODO + } }; struct Crocodile : Enemy { - Crocodile(Room* room) : Enemy(room, 20) {} + Crocodile(Room* room) : Enemy(room, 20, 341, 600, AGGRESSION_LVL_2) {} }; struct Lion : Enemy { - Lion(Room* room) : Enemy(room, 1) + Lion(Room* room) : Enemy(room, 1, 341, 400, AGGRESSION_LVL_2) { switch (type) { - case ITEM_LION_MALE : health = 30; break; + case ITEM_LION_MALE : health = 30; aggression = AGGRESSION_LVL_MAX; break; case ITEM_LION_FEMALE : health = 25; break; case ITEM_PUMA : health = 40; break; } @@ -231,13 +396,13 @@ struct Lion : Enemy struct Gorilla : Enemy { - Gorilla(Room* room) : Enemy(room, 22) {} + Gorilla(Room* room) : Enemy(room, 22, 341, 250, AGGRESSION_LVL_MAX) {} }; struct Rat : Enemy { - Rat(Room* room) : Enemy(room, 5) {} + Rat(Room* room) : Enemy(room, 5, 204, 200, AGGRESSION_LVL_2) {} virtual void hit(int32 damage, const vec3i &point, int32 soundId) { @@ -248,49 +413,49 @@ struct Rat : Enemy struct Rex : Enemy { - Rex(Room* room) : Enemy(room, 100) {} + Rex(Room* room) : Enemy(room, 100, 341, 2000, AGGRESSION_LVL_MAX) {} }; struct Raptor : Enemy { - Raptor(Room* room) : Enemy(room, 20) {} + Raptor(Room* room) : Enemy(room, 20, 341, 400, AGGRESSION_LVL_3) {} }; struct Mutant : Enemy { - Mutant(Room* room) : Enemy(room, 50) {} + Mutant(Room* room) : Enemy(room, 50, 341, 150, AGGRESSION_LVL_MAX) {} }; struct Centaur : Enemy { - Centaur(Room* room) : Enemy(room, 120) {} + Centaur(Room* room) : Enemy(room, 120, 341, 400, AGGRESSION_LVL_MAX) {} }; struct Mummy : Enemy { - Mummy(Room* room) : Enemy(room, 18) {} + Mummy(Room* room) : Enemy(room, 18, 10, 0, AGGRESSION_LVL_MAX) {} }; struct Larson : Enemy { - Larson(Room* room) : Enemy(room, 50) {} + Larson(Room* room) : Enemy(room, 50, 102, 0, AGGRESSION_LVL_MAX) {} }; struct Pierre : Enemy { - Pierre(Room* room) : Enemy(room, 70) {} + Pierre(Room* room) : Enemy(room, 70, 102, 0, AGGRESSION_LVL_MAX) {} }; struct Skater : Enemy { - Skater(Room* room) : Enemy(room, 125) {} + Skater(Room* room) : Enemy(room, 125, 204, 0, AGGRESSION_LVL_MAX) {} virtual void hit(int32 damage, const vec3i &point, int32 soundId) { @@ -301,25 +466,25 @@ struct Skater : Enemy struct Cowboy : Enemy { - Cowboy(Room* room) : Enemy(room, 150) {} + Cowboy(Room* room) : Enemy(room, 150, 102, 0, AGGRESSION_LVL_MAX) {} }; struct MrT : Enemy { - MrT(Room* room) : Enemy(room, 200) {} + MrT(Room* room) : Enemy(room, 200, 102, 0, AGGRESSION_LVL_MAX) {} }; struct Natla : Enemy { - Natla(Room* room) : Enemy(room, 400) {} + Natla(Room* room) : Enemy(room, 400, 204, 0, AGGRESSION_LVL_MAX) {} }; struct Adam : Enemy { - Adam(Room* room) : Enemy(room, 500) {} + Adam(Room* room) : Enemy(room, 500, 341, 0, AGGRESSION_LVL_MAX) {} virtual void hit(int32 damage, const vec3i &point, int32 soundId) { diff --git a/src/platform/gba/item.h b/src/platform/gba/item.h index e82ab3f..10d296f 100644 --- a/src/platform/gba/item.h +++ b/src/platform/gba/item.h @@ -967,6 +967,8 @@ Item::Item(Room* room) goalState = state; extra = NULL; health = NOT_ENEMY; + hitMask = 0; + visibleMask = 0xFFFFFFFF; flags.save = true; flags.gravity = false; diff --git a/src/platform/gba/lara.h b/src/platform/gba/lara.h index e81da20..f2566e5 100644 --- a/src/platform/gba/lara.h +++ b/src/platform/gba/lara.h @@ -3073,7 +3073,7 @@ struct Lara : Item int32 minDist = INT_MAX; - if (arm->target) + if (arm->target && arm->target->health > 0) { Sphere spheres[MAX_SPHERES]; int32 spheresCount = arm->target->getSpheres(spheres, false); diff --git a/src/platform/gba/packer/main.cpp b/src/platform/gba/packer/main.cpp index 9756977..ca2beb7 100644 --- a/src/platform/gba/packer/main.cpp +++ b/src/platform/gba/packer/main.cpp @@ -18,6 +18,209 @@ typedef unsigned long long uint64; #define MIN(a,b) ((a) < (b) ? (a) : (b)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) +#define ITEM_TYPES(E) \ + E( LARA ) \ + E( LARA_PISTOLS ) \ + E( LARA_SHOTGUN ) \ + E( LARA_MAGNUMS ) \ + E( LARA_UZIS ) \ + E( LARA_SPEC ) \ + E( DOPPELGANGER ) \ + E( WOLF ) \ + E( BEAR ) \ + E( BAT ) \ + E( CROCODILE_LAND ) \ + E( CROCODILE_WATER ) \ + E( LION_MALE ) \ + E( LION_FEMALE ) \ + E( PUMA ) \ + E( GORILLA ) \ + E( RAT_LAND ) \ + E( RAT_WATER ) \ + E( REX ) \ + E( RAPTOR ) \ + E( MUTANT_1 ) \ + E( MUTANT_2 ) \ + E( MUTANT_3 ) \ + E( CENTAUR ) \ + E( MUMMY ) \ + E( UNUSED_1 ) \ + E( UNUSED_2 ) \ + E( LARSON ) \ + E( PIERRE ) \ + E( SKATEBOARD ) \ + E( SKATER ) \ + E( COWBOY ) \ + E( MR_T ) \ + E( NATLA ) \ + E( ADAM ) \ + E( TRAP_FLOOR ) \ + E( TRAP_SWING_BLADE ) \ + E( TRAP_SPIKES ) \ + E( TRAP_BOULDER ) \ + E( DART ) \ + E( TRAP_DART_EMITTER ) \ + E( DRAWBRIDGE ) \ + E( TRAP_SLAM ) \ + E( TRAP_SWORD ) \ + E( HAMMER_HANDLE ) \ + E( HAMMER_BLOCK ) \ + E( LIGHTNING ) \ + E( MOVING_OBJECT ) \ + E( BLOCK_1 ) \ + E( BLOCK_2 ) \ + E( BLOCK_3 ) \ + E( BLOCK_4 ) \ + E( MOVING_BLOCK ) \ + E( TRAP_CEILING ) \ + E( UNUSED_3 ) \ + E( SWITCH ) \ + E( SWITCH_WATER ) \ + E( DOOR_1 ) \ + E( DOOR_2 ) \ + E( DOOR_3 ) \ + E( DOOR_4 ) \ + E( DOOR_5 ) \ + E( DOOR_6 ) \ + E( DOOR_7 ) \ + E( DOOR_8 ) \ + E( TRAP_DOOR_1 ) \ + E( TRAP_DOOR_2 ) \ + E( UNUSED_4 ) \ + E( BRIDGE_FLAT ) \ + E( BRIDGE_TILT_1 ) \ + E( BRIDGE_TILT_2 ) \ + E( INV_PASSPORT ) \ + E( INV_COMPASS ) \ + E( INV_HOME ) \ + E( GEARS_1 ) \ + E( GEARS_2 ) \ + E( GEARS_3 ) \ + E( CUT_1 ) \ + E( CUT_2 ) \ + E( CUT_3 ) \ + E( CUT_4 ) \ + E( INV_PASSPORT_CLOSED ) \ + E( INV_MAP ) \ + E( CRYSTAL ) \ + E( PISTOLS ) \ + E( SHOTGUN ) \ + E( MAGNUMS ) \ + E( UZIS ) \ + E( AMMO_PISTOLS ) \ + E( AMMO_SHOTGUN ) \ + E( AMMO_MAGNUMS ) \ + E( AMMO_UZIS ) \ + E( EXPLOSIVE ) \ + E( MEDIKIT_SMALL ) \ + E( MEDIKIT_BIG ) \ + E( INV_DETAIL ) \ + E( INV_SOUND ) \ + E( INV_CONTROLS ) \ + E( INV_GAMMA ) \ + E( INV_PISTOLS ) \ + E( INV_SHOTGUN ) \ + E( INV_MAGNUMS ) \ + E( INV_UZIS ) \ + E( INV_AMMO_PISTOLS ) \ + E( INV_AMMO_SHOTGUN ) \ + E( INV_AMMO_MAGNUMS ) \ + E( INV_AMMO_UZIS ) \ + E( INV_EXPLOSIVE ) \ + E( INV_MEDIKIT_SMALL ) \ + E( INV_MEDIKIT_BIG ) \ + E( PUZZLE_1 ) \ + E( PUZZLE_2 ) \ + E( PUZZLE_3 ) \ + E( PUZZLE_4 ) \ + E( INV_PUZZLE_1 ) \ + E( INV_PUZZLE_2 ) \ + E( INV_PUZZLE_3 ) \ + E( INV_PUZZLE_4 ) \ + E( PUZZLEHOLE_1 ) \ + E( PUZZLEHOLE_2 ) \ + E( PUZZLEHOLE_3 ) \ + E( PUZZLEHOLE_4 ) \ + E( PUZZLEHOLE_DONE_1 ) \ + E( PUZZLEHOLE_DONE_2 ) \ + E( PUZZLEHOLE_DONE_3 ) \ + E( PUZZLEHOLE_DONE_4 ) \ + E( LEADBAR ) \ + E( INV_LEADBAR ) \ + E( MIDAS_HAND ) \ + E( KEY_ITEM_1 ) \ + E( KEY_ITEM_2 ) \ + E( KEY_ITEM_3 ) \ + E( KEY_ITEM_4 ) \ + E( INV_KEY_ITEM_1 ) \ + E( INV_KEY_ITEM_2 ) \ + E( INV_KEY_ITEM_3 ) \ + E( INV_KEY_ITEM_4 ) \ + E( KEYHOLE_1 ) \ + E( KEYHOLE_2 ) \ + E( KEYHOLE_3 ) \ + E( KEYHOLE_4 ) \ + E( UNUSED_5 ) \ + E( UNUSED_6 ) \ + E( SCION_PICKUP_QUALOPEC ) \ + E( SCION_PICKUP_DROP ) \ + E( SCION_TARGET ) \ + E( SCION_PICKUP_HOLDER ) \ + E( SCION_HOLDER ) \ + E( UNUSED_7 ) \ + E( UNUSED_8 ) \ + E( INV_SCION ) \ + E( EXPLOSION ) \ + E( UNUSED_9 ) \ + E( SPLASH ) \ + E( UNUSED_10 ) \ + E( BUBBLE ) \ + E( UNUSED_11 ) \ + E( UNUSED_12 ) \ + E( BLOOD ) \ + E( UNUSED_13 ) \ + E( SMOKE ) \ + E( CENTAUR_STATUE ) \ + E( CABIN ) \ + E( MUTANT_EGG_SMALL ) \ + E( RICOCHET ) \ + E( SPARKLES ) \ + E( MUZZLE_FLASH ) \ + E( UNUSED_14 ) \ + E( UNUSED_15 ) \ + E( VIEW_TARGET ) \ + E( WATERFALL ) \ + E( NATLA_BULLET ) \ + E( MUTANT_BULLET ) \ + E( CENTAUR_BULLET ) \ + E( UNUSED_16 ) \ + E( UNUSED_17 ) \ + E( LAVA_PARTICLE ) \ + E( LAVA_EMITTER ) \ + E( FLAME ) \ + E( FLAME_EMITTER ) \ + E( TRAP_LAVA ) \ + E( MUTANT_EGG_BIG ) \ + E( BOAT ) \ + E( EARTHQUAKE ) \ + E( UNUSED_18 ) \ + E( UNUSED_19 ) \ + E( UNUSED_20 ) \ + E( UNUSED_21 ) \ + E( UNUSED_22 ) \ + E( LARA_BRAID ) \ + E( GLYPHS ) + +#define DECL_ENUM(v) ITEM_##v, + +enum ItemType { + ITEM_TYPES(DECL_ENUM) + TR1_ITEM_MAX, + ITEM_MAX = TR1_ITEM_MAX +}; + +#undef DECL_ENUM + struct vec3s { int16 x, y, z; @@ -722,6 +925,15 @@ struct LevelPC uint16 flags; }; + enum NodeFlag + { + NODE_FLAG_POP = (1 << 0), + NODE_FLAG_PUSH = (1 << 1), + NODE_FLAG_ROTX = (1 << 2), + NODE_FLAG_ROTY = (1 << 3), + NODE_FLAG_ROTZ = (1 << 4), + }; + struct Node { uint32 flags; @@ -1108,6 +1320,46 @@ struct LevelPC */ } + void fixHeadMask() + { + #define SET_ROT(joint, mask) (((Node*)nodesData)[models[i].nodeIndex / 4 + joint]).flags |= mask; + + for (int32 i = 0; i < modelsCount; i++) + { + switch (models[i].type) + { + case ITEM_WOLF : SET_ROT(2, NODE_FLAG_ROTY); break; + case ITEM_BEAR : SET_ROT(13, NODE_FLAG_ROTY); break; + //case ITEM_BAT : break; + case ITEM_CROCODILE_LAND : SET_ROT(7, NODE_FLAG_ROTY); break; + case ITEM_CROCODILE_WATER : SET_ROT(7, NODE_FLAG_ROTY); break; + case ITEM_LION_MALE : SET_ROT(19, NODE_FLAG_ROTY); break; + case ITEM_LION_FEMALE : SET_ROT(19, NODE_FLAG_ROTY); break; + case ITEM_PUMA : SET_ROT(19, NODE_FLAG_ROTY); break; + case ITEM_GORILLA : SET_ROT(13, NODE_FLAG_ROTY); break; + case ITEM_RAT_LAND : SET_ROT(1, NODE_FLAG_ROTY); break; + case ITEM_RAT_WATER : SET_ROT(1, NODE_FLAG_ROTY); break; + case ITEM_REX : SET_ROT(10, NODE_FLAG_ROTY); SET_ROT(11, NODE_FLAG_ROTY); break; + case ITEM_RAPTOR : SET_ROT(21, NODE_FLAG_ROTY); break; + case ITEM_MUTANT_1 : SET_ROT(0, NODE_FLAG_ROTY); SET_ROT(2, NODE_FLAG_ROTY); break; + case ITEM_MUTANT_2 : SET_ROT(0, NODE_FLAG_ROTY); SET_ROT(2, NODE_FLAG_ROTY); break; + case ITEM_MUTANT_3 : SET_ROT(0, NODE_FLAG_ROTY); SET_ROT(2, NODE_FLAG_ROTY); break; + case ITEM_CENTAUR : SET_ROT(10, NODE_FLAG_ROTX | NODE_FLAG_ROTY); break; + case ITEM_MUMMY : SET_ROT(2, NODE_FLAG_ROTY); break; + case ITEM_LARSON : SET_ROT(6, NODE_FLAG_ROTY); break; + case ITEM_PIERRE : SET_ROT(6, NODE_FLAG_ROTY); break; + case ITEM_SKATER : SET_ROT(0, NODE_FLAG_ROTY); break; + case ITEM_COWBOY : SET_ROT(0, NODE_FLAG_ROTY); break; + case ITEM_MR_T : SET_ROT(0, NODE_FLAG_ROTY); break; + case ITEM_NATLA : SET_ROT(2, NODE_FLAG_ROTX | NODE_FLAG_ROTZ); break; + case ITEM_ADAM : SET_ROT(1, NODE_FLAG_ROTY); break; + default : break; + } + } + + #undef SET_ROT + } + void convertGBA(const char* fileName) { FileStream f(fileName, true); @@ -1156,6 +1408,8 @@ struct LevelPC lightmap[i * 256] = 0; } + fixHeadMask(); + header.lightmap = f.align4(); f.write(lightmap); @@ -2396,8 +2650,7 @@ void pack_tracks(const char* dir) int main() { - pack_tracks("tracks/conv_demo/*.ima"); - return 0; + //pack_tracks("tracks/conv_demo/*.ima"); return 0; for (int32 i = 0; i < MAX_LEVELS; i++) {