diff --git a/TR2_progress.txt b/TR2_progress.txt index 7b8410a..e2fd802 100644 --- a/TR2_progress.txt +++ b/TR2_progress.txt @@ -125,7 +125,7 @@ x function is unused / included in another function 0x0040CB50: BoatCheckGeton 0x0040CCC0: BoatCollision 0x0040CE20: TestWaterHeight -0x0040CF20: DoBoatShift +0x0040CF20: + DoBoatShift 0x0040D0F0: + DoWakeEffect 0x0040D270: DoBoatDynamics 0x0040D2C0: BoatDynamics @@ -136,7 +136,7 @@ x function is unused / included in another function game/box.cpp 0x0040E190: * InitialiseCreature -0x0040E1C0: CreatureActive +0x0040E1C0: * CreatureActive 0x0040E210: * CreatureAIInfo 0x0040E470: SearchLOT 0x0040E670: UpdateLOT @@ -164,13 +164,13 @@ x function is unused / included in another function game/camera.cpp 0x00410580: + InitialiseCamera 0x00410630: + MoveCamera -0x004109B0: * ClipCamera -0x00410A90: * ShiftCamera -0x00410BF0: * GoodPosition -0x00410C40: * SmartShift -0x004113D0: * ChaseCamera -0x004114C0: * ShiftClamp -0x00411660: * CombatCamera +0x004109B0: + ClipCamera +0x00410A90: + ShiftCamera +0x00410BF0: + GoodPosition +0x00410C40: + SmartShift +0x004113D0: + ChaseCamera +0x004114C0: + ShiftClamp +0x00411660: + CombatCamera 0x004117F0: + LookCamera 0x004119E0: + FixedCamera 0x00411A80: + CalculateCamera @@ -180,31 +180,31 @@ x function is unused / included in another function 0x00411F40: + StartCinematic 0x00412060: + InitCinematicRooms 0x00412100: + DoCinematic -0x00412270: * CalculateCinematicCamera -0x004123B0: * GetCinematicRoom -0x00412430: * ControlCinematicPlayer -0x00412510: * LaraControlCinematic -0x004125B0: * InitialisePlayer1 -0x00412640: * InitialiseGenPlayer -0x00412680: * InGameCinematicCamera +0x00412270: + CalculateCinematicCamera +0x004123B0: + GetCinematicRoom +0x00412430: + ControlCinematicPlayer +0x00412510: + LaraControlCinematic +0x004125B0: + InitialisePlayer1 +0x00412640: + InitialiseGenPlayer +0x00412680: + InGameCinematicCamera game/collide.cpp -0x004128D0: GetCollisionInfo -0x00412F90: FindGridShift +0x004128D0: + GetCollisionInfo +0x00412F90: * FindGridShift 0x00412FC0: + CollideStaticObjects 0x004133B0: + GetNearByRooms 0x00413480: + GetNewRoom 0x004134E0: ShiftItem 0x00413520: * UpdateLaraRoom -0x00413580: GetTiltType +0x00413580: * GetTiltType 0x00413620: LaraBaddieCollision 0x004137C0: EffectSpaz 0x00413840: * CreatureCollision 0x004138C0: * ObjectCollision 0x00413920: DoorCollision 0x004139A0: TrapCollision -0x00413A10: ItemPushLara -0x00413D20: TestBoundsCollide +0x00413A10: * ItemPushLara +0x00413D20: * TestBoundsCollide 0x00413DF0: TestLaraPosition 0x00413F30: AlignLaraPosition 0x00414070: MoveLaraPosition @@ -223,11 +223,11 @@ x function is unused / included in another function 0x004158A0: * TriggerActive 0x00415900: * GetCeiling 0x00415B60: GetDoor -0x00415BB0: * LOS -0x00415C50: zLOS -0x00415F40: xLOS -0x00416230: ClipTarget -0x00416310: ObjectOnLOS +0x00415BB0: + LOS +0x00415C50: + zLOS +0x00415F40: + xLOS +0x00416230: + ClipTarget +0x00416310: * ObjectOnLOS 0x00416610: * FlipMap 0x004166D0: RemoveRoomFlipItems 0x00416770: AddRoomFlipItems @@ -235,10 +235,10 @@ x function is unused / included in another function 0x00416800: + TriggerNormalCDTrack game/demo.cpp -0x004168E0: * DoDemoSequence +0x004168E0: + DoDemoSequence 0x00416940: + StartDemo -0x00416AF0: * LoadLaraDemoPos -0x00416BC0: * GetDemoInput +0x00416AF0: + LoadLaraDemoPos +0x00416BC0: + GetDemoInput game/diver.cpp 0x00416BF0: Harpoon @@ -290,7 +290,7 @@ x function is unused / included in another function 0x0041BA60: * InterpolateMatrix 0x0041BC10: * InterpolateArmMatrix 0x0041BD10: + DrawGunFlash -0x0041BE80: * CalculateObjectLighting +0x0041BE80: + CalculateObjectLighting 0x0041BF70: * GetFrames 0x0041C010: * GetBoundsAccurate 0x0041C090: * GetBestFrame @@ -380,9 +380,9 @@ x function is unused / included in another function 0x004201A0: + GF_ModifyInventory game/hair.cpp -0x00420E80: * InitialiseHair -0x00420F00: * HairControl -0x00421900: * DrawHair +0x00420E80: + InitialiseHair +0x00420F00: + HairControl +0x00421900: + DrawHair game/health.cpp 0x00421980: + FlashIt @@ -629,20 +629,20 @@ x function is unused / included in another function 0x0042C180: ControlHarpoonBolt 0x0042C4D0: + FireRocket 0x0042C5C0: + ControlRocket -0x0042C9D0: draw_shotgun -0x0042CB40: undraw_shotgun -0x0042CC50: * AnimateShotgun +0x0042C9D0: * draw_shotgun +0x0042CB40: * undraw_shotgun +0x0042CC50: + AnimateShotgun game/lara2gun.cpp -0x0042D000: set_pistol_arm -0x0042D050: draw_pistols -0x0042D0D0: undraw_pistols +0x0042D000: + set_pistol_arm +0x0042D050: * draw_pistols +0x0042D0D0: * undraw_pistols 0x0042D300: ready_pistols 0x0042D360: draw_pistol_meshes 0x0042D3B0: undraw_pistol_mesh_left 0x0042D3F0: undraw_pistol_mesh_right 0x0042D430: + PistolHandler -0x0042D5C0: * AnimatePistols +0x0042D5C0: + AnimatePistols game/laraclimb.cpp 0x0042D8F0: lara_as_climbleft @@ -664,30 +664,30 @@ x function is unused / included in another function 0x0042E4F0: LaraTestClimbUpPos game/larafire.cpp -0x0042E740: * LaraGun +0x0042E740: + LaraGun 0x0042ECB0: * CheckForHoldingState 0x0042ECF0: * InitialiseNewWeapon 0x0042EE30: * LaraTargetInfo 0x0042EFD0: * LaraGetNewTarget 0x0042F1F0: * find_target_point 0x0042F2A0: * AimWeapon -0x0042F370: * FireWeapon +0x0042F370: + FireWeapon 0x0042F6E0: * HitTarget -0x0042F780: * SmashItem +0x0042F780: + SmashItem 0x0042F7E0: * WeaponObject game/laraflare.cpp -0x0042F840: DoFlareLight -0x0042F8E0: DoFlareInHand +0x0042F840: + DoFlareLight +0x0042F8E0: + DoFlareInHand 0x0042F9C0: + DrawFlareInAir -0x0042FAC0: CreateFlare -0x0042FCA0: set_flare_arm -0x0042FCF0: draw_flare -0x0042FE60: undraw_flare -0x00430090: draw_flare_meshes -0x004300B0: undraw_flare_meshes -0x004300D0: ready_flare -0x00430110: FlareControl +0x0042FAC0: + CreateFlare +0x0042FCA0: + set_flare_arm +0x0042FCF0: + draw_flare +0x0042FE60: + undraw_flare +0x00430090: + draw_flare_meshes +0x004300B0: + undraw_flare_meshes +0x004300D0: + ready_flare +0x00430110: + FlareControl game/laramisc.cpp 0x00430380: + LaraControl @@ -773,10 +773,10 @@ x function is unused / included in another function 0x00434970: DeathSlideCollision 0x00434A30: ControlDeathSlide 0x00434CC0: BigBowlControl -0x00434DB0: BellControl -0x00434E30: InitialiseWindow -0x00434EB0: * SmashWindow -0x00434F80: WindowControl +0x00434DB0: + BellControl +0x00434E30: + InitialiseWindow +0x00434EB0: + SmashWindow +0x00434F80: + WindowControl 0x00435020: SmashIceControl 0x00435100: ShutThatDoor 0x00435150: OpenThatDoor @@ -786,11 +786,11 @@ x function is unused / included in another function 0x00435700: DrawBridgeFloor 0x00435740: DrawBridgeCeiling 0x00435780: DrawBridgeCollision -0x004357B0: InitialiseLift -0x004357F0: LiftControl -0x004358D0: LiftFloorCeiling -0x00435A50: LiftFloor -0x00435A90: LiftCeiling +0x004357B0: + InitialiseLift +0x004357F0: + LiftControl +0x004358D0: + LiftFloorCeiling +0x00435A50: + LiftFloor +0x00435A90: + LiftCeiling 0x00435AD0: BridgeFlatFloor 0x00435AF0: BridgeFlatCeiling 0x00435B10: GetOffset @@ -803,13 +803,13 @@ x function is unused / included in another function 0x00435E20: DetonatorControl game/people.cpp -0x00435EB0: Targetable +0x00435EB0: + Targetable 0x00435F40: ControlGlow 0x00435F80: ControlGunShot 0x00435FD0: + GunShot 0x00436040: + GunHit -0x00436100: GunMiss -0x004361B0: ShotLara +0x00436100: + GunMiss +0x004361B0: + ShotLara 0x00436380: * InitialiseCult1 0x004363D0: * Cult1Control 0x00436800: * InitialiseCult3 @@ -818,7 +818,7 @@ x function is unused / included in another function 0x004371C0: * Worker2Control 0x00437620: * BanditControl 0x00437960: * Bandit2Control -0x00437DA0: * WinstonControl +0x00437DA0: + WinstonControl game/pickup.cpp 0x00437F20: * PickUpCollision @@ -894,8 +894,8 @@ x function is unused / included in another function 0x0043FA30: + SOUND_Init game/sphere.cpp -0x0043FA60: TestCollision -0x0043FB90: GetSpheres +0x0043FA60: * TestCollision +0x0043FB90: * GetSpheres 0x0043FE70: * GetJointAbsPosition 0x00440010: * BaddieBiteEffect @@ -939,10 +939,10 @@ x function is unused / included in another function 0x00441900: + BladeControl 0x004419A0: + InitialiseKillerStatue 0x004419F0: + KillerStatueControl -0x00441B00: SpringBoardControl -0x00441BE0: InitialiseRollingBall -0x00441C20: RollingBallControl -0x00441F70: RollingBallCollision +0x00441B00: + SpringBoardControl +0x00441BE0: + InitialiseRollingBall +0x00441C20: + RollingBallControl +0x00441F70: + RollingBallCollision 0x004421C0: SpikeCollision 0x00442320: TrapDoorControl 0x00442370: TrapDoorFloor @@ -1168,7 +1168,7 @@ x function is unused / included in another function 0x0044ADA0: + LoadCinematic 0x0044AE20: + LoadDemo 0x0044AEB0: + LoadDemoExternal -0x0044AF50: LoadSamples +0x0044AF50: + LoadSamples 0x0044B1C0: + ChangeFileNameExtension 0x0044B200: + GetFullPath 0x0044B230: + SelectDrive diff --git a/game/boat.cpp b/game/boat.cpp index 8bad13e..d7e9053 100644 --- a/game/boat.cpp +++ b/game/boat.cpp @@ -25,10 +25,48 @@ #include "game/control.h" #include "game/items.h" #include "game/missile.h" +#include "game/sound.h" #include "specific/game.h" #include "specific/output.h" #include "global/vars.h" +void __cdecl DoBoatShift(int itemID) { + ITEM_INFO *item, *link; + __int16 linkID; + int x, z, dx, dz; + + item = &Items[itemID]; + for (linkID = RoomInfo[item->roomNumber].itemNumber; linkID != -1; linkID = link->nextItem) { + link = &Items[linkID]; + if (link->objectID == ID_BOAT && linkID != itemID && Lara.skidoo != linkID) { + dz = link->pos.z - item->pos.z; + dx = link->pos.x - item->pos.x; + if (SQR(dx) + SQR(dz) < SQR(1000)) { + item->pos.x = link->pos.x - SQR(1000) * dx / (SQR(dx) + SQR(dz)); + item->pos.z = link->pos.z - SQR(1000) * dz / (SQR(dx) + SQR(dz)); + } + } else { + if (link->objectID == ID_GONDOLA && link->currentAnimState == 1) { + x = link->pos.x - (512 * phd_sin(link->pos.rotY) >> W2V_SHIFT); + z = link->pos.z - (512 * phd_cos(link->pos.rotY) >> W2V_SHIFT); + dx = x - item->pos.x; + dz = z - item->pos.z; + if (SQR(dx) + SQR(dz) < SQR(1000)) { + if (item->speed < 80) { + item->pos.x = x - SQR(1000) * dx / (SQR(dx) + SQR(dz)); + item->pos.z = z - SQR(1000) * dz / (SQR(dx) + SQR(dz)); + } else { + if (link->pos.y - item->pos.y < 2048) { + PlaySoundEffect(337, &link->pos, 0); + link->goalAnimState = 2; + } + } + } + } + } + } +} + void __cdecl DoWakeEffect(ITEM_INFO *item) { __int16 frame_number, fxID; int i; @@ -96,8 +134,8 @@ void Inject_Boat() { // INJECT(0x0040CB50, BoatCheckGeton); // INJECT(0x0040CCC0, BoatCollision); // INJECT(0x0040CE20, TestWaterHeight); -// INJECT(0x0040CF20, DoBoatShift); + INJECT(0x0040CF20, DoBoatShift); INJECT(0x0040D0F0, DoWakeEffect); // INJECT(0x0040D270, DoBoatDynamics); diff --git a/game/boat.h b/game/boat.h index 34396d6..00ac83f 100644 --- a/game/boat.h +++ b/game/boat.h @@ -31,8 +31,8 @@ // 0x0040CB50: BoatCheckGeton // 0x0040CCC0: BoatCollision // 0x0040CE20: TestWaterHeight -// 0x0040CF20: DoBoatShift +void __cdecl DoBoatShift(int itemID); // 0x0040CF20 void __cdecl DoWakeEffect(ITEM_INFO *item); // 0x0040D0F0 // 0x0040D270: DoBoatDynamics diff --git a/game/box.h b/game/box.h index c708827..c4f62ba 100644 --- a/game/box.h +++ b/game/box.h @@ -28,9 +28,7 @@ * Function list */ #define InitialiseCreature ((void(__cdecl*)(__int16)) 0x0040E190) - -// 0x0040E1C0: CreatureActive - +#define CreatureActive ((int(__cdecl*)(__int16)) 0x0040E1C0) #define CreatureAIInfo ((void(__cdecl*)(ITEM_INFO *, AI_INFO *)) 0x0040E210) // 0x0040E470: SearchLOT diff --git a/game/camera.cpp b/game/camera.cpp index dc2c99d..6496ffd 100644 --- a/game/camera.cpp +++ b/game/camera.cpp @@ -136,6 +136,310 @@ void __cdecl MoveCamera(GAME_VECTOR *destination, int speed) { } } +void __cdecl ClipCamera(int *x, int *y, int *z, int tx, int ty, int tz, int left, int top, int right, int bottom) { + if ((right > left) != (tx < left)) { + *y = ty + (*y - ty) * (left - tx) / (*x - tx); + *z = tz + (*z - tz) * (left - tx) / (*x - tx); + *x = left; + } + if ((bottom > top && ty > top && *y < top) || (bottom < top && ty < top && *y > top)) { + *x = tx + (*x - tx) * (top - ty) / (*y - ty); + *z = tz + (*z - tz) * (top - ty) / (*y - ty); + *y = top; + } +} + +void __cdecl ShiftCamera(int *x, int *y, int *z, int tx, int ty, int tz, int left, int top, int right, int bottom) { + int squareL, squareT, squareB, squareR; + + squareL = SQR(tx - left); + squareT = SQR(ty - top); + if (Camera.targetSquare < squareL + squareT) { + *x = left; + if (Camera.targetSquare >= squareL) + *y = ty + (top >= bottom ? phd_sqrt(Camera.targetSquare - squareL) : -phd_sqrt(Camera.targetSquare - squareL)); + } else { + if (squareL + squareT > SQR(341)) { + *x = left; + *y = top; + } else { + squareB = SQR(ty - bottom) + squareL; + if (Camera.targetSquare < squareB) { + *x = left; + if (Camera.targetSquare >= squareL) + *y = ty + (top < bottom ? phd_sqrt(Camera.targetSquare - squareL) : -phd_sqrt(Camera.targetSquare - squareL)); + } else { + squareR = SQR(tx - right) + squareT; + if (2 * Camera.targetSquare < squareR) { + if (2 * Camera.targetSquare >= squareT) { + *x = tx + (left < right ? phd_sqrt(2 * Camera.targetSquare - squareT) : -phd_sqrt(2 * Camera.targetSquare - squareT)); + *y = top; + } + } else { + if (squareB > squareR) { + *x = left; + *y = bottom; + } else { + *x = right; + *y = top; + } + } + } + } + } +} + +FLOOR_INFO* __cdecl GoodPosition(int x, int y, int z, __int16 roomID) { + FLOOR_INFO *floor; + + floor = GetFloor(x, y, z, &roomID); + if (y <= GetHeight(floor, x, y, z) && y >= GetCeiling(floor, x, y, z)) + return floor; + return NULL; +} + +void __cdecl SmartShift(GAME_VECTOR *goal, CB_SMARTCAM shift) { + ROOM_INFO *room; + BOX_INFO *box; + int left, right, top, bottom, side, x, z; + __int16 boxID; + FLOOR_INFO *floorL, *floorR, *floorT, *floorB; + GAME_VECTOR secondary, primary; + BOOL clear, first; + + LOS(&Camera.target, goal); + room = &RoomInfo[Camera.target.roomNumber]; + box = &Boxes[room->floor[((Camera.target.x - room->x) >> WALL_SHIFT) * room->xSize + ((Camera.target.z - room->z) >> WALL_SHIFT)].box]; + left = box->left << WALL_SHIFT; + right = (box->right << WALL_SHIFT) - 1; + top = box->top << WALL_SHIFT; + bottom = (box->bottom << WALL_SHIFT) - 1; + room = &RoomInfo[goal->roomNumber]; + boxID = room->floor[((goal->x - room->x) >> WALL_SHIFT) * room->xSize + ((goal->z - room->z) >> WALL_SHIFT)].box; + if (boxID != -1 && (goal->z < left || goal->z > right || goal->x < top || goal->x > bottom)) { + box = &Boxes[boxID]; + left = box->left << WALL_SHIFT; + right = (box->right << WALL_SHIFT) - 1; + top = box->top << WALL_SHIFT; + bottom = (box->bottom << WALL_SHIFT) - 1; + } + z = (goal->z - 1024) | 0x3FF; + floorL = GoodPosition(goal->x, goal->y, z, goal->roomNumber); + if (floorL) { + side = Boxes[floorL->box].left << WALL_SHIFT; + if (floorL->box != -1 && side < left) + left = side; + } else { + left = z; + } + z = (goal->z + 1024) & -0x400; + floorR = GoodPosition(goal->x, goal->y, z, goal->roomNumber); + if (floorR) { + side = (Boxes[floorR->box].right << WALL_SHIFT) - 1; + if (floorR->box != -1 && side > right) + right = side; + } else { + right = z; + } + x = (goal->x - 1024) | 0x3FF; + floorT = GoodPosition(x, goal->y, goal->z, goal->roomNumber); + if (floorT) { + side = Boxes[floorT->box].top << WALL_SHIFT; + if (floorT->box != -1 && side < top) + top = side; + } else { + top = x; + } + x = (goal->x + 1024) & -0x400; + floorB = GoodPosition(x, goal->y, goal->z, goal->roomNumber); + if (floorB) { + side = (Boxes[floorB->box].bottom << WALL_SHIFT) - 1; + if (floorB->box != -1 && side > bottom) + bottom = side; + } else { + bottom = x; + } + left += 256; + right -= 256; + top += 256; + bottom -= 256; + secondary.x = goal->x; + primary.x = goal->x; + secondary.y = goal->y; + primary.y = goal->y; + secondary.z = goal->z; + secondary.roomNumber = goal->roomNumber; + primary.roomNumber = goal->roomNumber; + primary.z = goal->z; + clear = TRUE; + if (ABS(goal->z - Camera.target.z) > ABS(goal->x - Camera.target.x)) { + if (goal->z < left && !floorL) { + first = Camera.pos.x < Camera.target.x; + clear = FALSE; + shift(&primary.z, &primary.x, &primary.y, Camera.target.z, Camera.target.x, Camera.target.y, left, top, right, bottom); + shift(&secondary.z, &secondary.x, &secondary.y, Camera.target.z, Camera.target.x, Camera.target.y, left, bottom, right, top); + } else { + if (goal->z > right && !floorR) { + first = Camera.pos.x < Camera.target.x; + clear = FALSE; + shift(&primary.z, &primary.x, &primary.y, Camera.target.z, Camera.target.x, Camera.target.y, right, top, left, bottom); + shift(&secondary.z, &secondary.x, &secondary.y, Camera.target.z, Camera.target.x, Camera.target.y, right, bottom, left, top); + } + } + if (clear) { + if (goal->x < top && !floorT) { + first = goal->z < Camera.target.z; + clear = FALSE; + shift(&primary.x, &primary.z, &primary.y, Camera.target.x, Camera.target.z, Camera.target.y, top, left, bottom, right); + shift(&secondary.x, &secondary.z, &secondary.y, Camera.target.x, Camera.target.z, Camera.target.y, top, right, bottom, left); + } else { + if (goal->x > bottom && !floorB) { + first = goal->z < Camera.target.z; + clear = FALSE; + shift(&primary.x, &primary.z, &primary.y, Camera.target.x, Camera.target.z, Camera.target.y, bottom, left, top, right); + shift(&secondary.x, &secondary.z, &secondary.y, Camera.target.x, Camera.target.z, Camera.target.y, bottom, right, top, left); + } + } + } + } else { + if (goal->x < top && !floorT) { + first = Camera.pos.z < Camera.target.z; + clear = FALSE; + shift(&primary.x, &primary.z, &primary.y, Camera.target.x, Camera.target.z, Camera.target.y, top, left, bottom, right); + shift(&secondary.x, &secondary.z, &secondary.y, Camera.target.x, Camera.target.z, Camera.target.y, top, right, bottom, left); + } else { + if (goal->x > bottom && !floorB) { + first = Camera.pos.z < Camera.target.z; + clear = FALSE; + shift(&primary.x, &primary.z, &primary.y, Camera.target.x, Camera.target.z, Camera.target.y, bottom, left, top, right); + shift(&secondary.x, &secondary.z, &secondary.y, Camera.target.x, Camera.target.z, Camera.target.y, bottom, right, top, left); + } + } + if (clear) { + if (goal->z < left && !floorL) { + first = goal->x < Camera.target.x; + clear = FALSE; + shift(&primary.z, &primary.x, &primary.y, Camera.target.z, Camera.target.x, Camera.target.y, left, top, right, bottom); + shift(&secondary.z, &secondary.x, &secondary.y, Camera.target.z, Camera.target.x, Camera.target.y, left, bottom, right, top); + } else { + if (goal->z > right && !floorR) { + first = goal->x < Camera.target.x; + clear = FALSE; + shift(&primary.z, &primary.x, &primary.y, Camera.target.z, Camera.target.x, Camera.target.y, right, top, left, bottom); + shift(&secondary.z, &secondary.x, &secondary.y, Camera.target.z, Camera.target.x, Camera.target.y, right, bottom, left, top); + } + } + } + } + if (!clear) { + if (first && !LOS(&Camera.target, &primary)) { + first = FALSE; + } else { + if (!first && !LOS(&Camera.target, &secondary)) + first = TRUE; + } + if (first) { + goal->x = primary.x; + goal->y = primary.y; + goal->z = primary.z; + } else { + goal->x = secondary.x; + goal->y = secondary.y; + goal->z = secondary.z; + } + GetFloor(goal->x, goal->y, goal->z, &goal->roomNumber); + } +} + +void __cdecl ChaseCamera(ITEM_INFO *item) { + int distance; + GAME_VECTOR goal; + + Camera.targetElevation += item->pos.rotX; + CLAMP(Camera.targetElevation, -85 * PHD_DEGREE, 85 * PHD_DEGREE); + distance = Camera.targetDistance * phd_cos(Camera.targetElevation) >> W2V_SHIFT; + goal.y = Camera.target.y + (Camera.targetDistance * phd_sin(Camera.targetElevation) >> W2V_SHIFT); + Camera.targetSquare = SQR(distance); + goal.x = Camera.target.x - (distance * phd_sin(Camera.targetAngle + item->pos.rotY) >> W2V_SHIFT); + goal.z = Camera.target.z - (distance * phd_cos(Camera.targetAngle + item->pos.rotY) >> W2V_SHIFT); + goal.roomNumber = Camera.pos.roomNumber; + SmartShift(&goal, ShiftCamera); + MoveCamera(&goal, Camera.speed); +} + +int __cdecl ShiftClamp(GAME_VECTOR *pos, int clamp) { + FLOOR_INFO *floor; + BOX_INFO *box; + int x, z, left, right, top, bottom, height, ceiling, shift; + + x = pos->x; + z = pos->z; + floor = GetFloor(x, pos->y, z, &pos->roomNumber); + box = &Boxes[floor->box]; + left = (box->left << WALL_SHIFT) + clamp; + right = (box->right << WALL_SHIFT) - clamp - 1; + if (z < left && !GoodPosition(x, pos->y, z - clamp, pos->roomNumber)) { + pos->z = left; + } else { + if (z > right && !GoodPosition(x, pos->y, z + clamp, pos->roomNumber)) + pos->z = right; + } + top = (box->top << WALL_SHIFT) + clamp; + bottom = (box->bottom << WALL_SHIFT) - clamp - 1; + if (x < top && !GoodPosition(x - clamp, pos->y, z, pos->roomNumber)) { + pos->x = top; + } else { + if (x > bottom && !GoodPosition(x + clamp, pos->y, z, pos->roomNumber)) + pos->x = bottom; + } + height = GetHeight(floor, x, pos->y, z) - clamp; + ceiling = GetCeiling(floor, x, pos->y, z) + clamp; + if (height < ceiling) { + height = (height + ceiling) >> 1; + ceiling = height; + } + if (pos->y > height) { + shift = height - pos->y; + } else { + if (pos->y < ceiling) { + shift = ceiling - pos->y; + } else { + shift = 0; + } + } + return shift; +} + +void __cdecl CombatCamera(ITEM_INFO *item) { + int distance, y, dy; + GAME_VECTOR goal; + + Camera.target.z = item->pos.z; + Camera.target.x = item->pos.x; + if (Lara.target) { + Camera.targetAngle = item->pos.rotY + Lara.target_angles[0]; + Camera.targetElevation = item->pos.rotX + Lara.target_angles[1]; + } else { + Camera.targetAngle = item->pos.rotY + Lara.head_y_rot + Lara.torso_y_rot; + Camera.targetElevation = item->pos.rotX + Lara.head_x_rot + Lara.torso_x_rot; + } + Camera.targetDistance = 2560; + distance = Camera.targetDistance * phd_cos(Camera.targetElevation) >> W2V_SHIFT; + goal.x = Camera.target.x - (distance * phd_sin(Camera.targetAngle) >> W2V_SHIFT); + goal.y = Camera.target.y + (Camera.targetDistance * phd_sin(Camera.targetElevation) >> W2V_SHIFT); + goal.z = Camera.target.z - (distance * phd_cos(Camera.targetAngle) >> W2V_SHIFT); + goal.roomNumber = Camera.pos.roomNumber; + y = LaraItem->pos.y + Lara.water_surface_dist; + if (Lara.water_status == LWS_Underwater && Camera.target.y > y && y > goal.y) { + dy = goal.y - Camera.target.y; + goal.y = y; + goal.z = Camera.target.z + (goal.z - Camera.target.z) * (y - Camera.target.y) / dy; + goal.x = Camera.target.x + (goal.x - Camera.target.x) * (y - Camera.target.y) / dy; + } + SmartShift(&goal, ShiftCamera); + MoveCamera(&goal, Camera.speed); +} + void __cdecl LookCamera(ITEM_INFO *item) { int zOld = Camera.target.z; int xOld = Camera.target.x; @@ -319,15 +623,13 @@ void __cdecl CalculateCamera() { void Inject_Camera() { INJECT(0x00410580, InitialiseCamera); INJECT(0x00410630, MoveCamera); - -// INJECT(0x004109B0, ClipCamera); -// INJECT(0x00410A90, ShiftCamera); -// INJECT(0x00410BF0, BadPosition); -// INJECT(0x00410C40, SmartShift); -// INJECT(0x004113D0, ChaseCamera); -// INJECT(0x004114C0, ShiftClamp); -// INJECT(0x00411660, CombatCamera); - + INJECT(0x004109B0, ClipCamera); + INJECT(0x00410A90, ShiftCamera); + INJECT(0x00410BF0, GoodPosition); + INJECT(0x00410C40, SmartShift); + INJECT(0x004113D0, ChaseCamera); + INJECT(0x004114C0, ShiftClamp); + INJECT(0x00411660, CombatCamera); INJECT(0x004117F0, LookCamera); INJECT(0x004119E0, FixedCamera); INJECT(0x00411A80, CalculateCamera); diff --git a/game/camera.h b/game/camera.h index 09e0e57..7a2ce4e 100644 --- a/game/camera.h +++ b/game/camera.h @@ -31,15 +31,13 @@ typedef void(__cdecl *CB_SMARTCAM)(int*, int*, int*, int, int, int, int, int, in */ void __cdecl InitialiseCamera(); // 0x00410580 void __cdecl MoveCamera(GAME_VECTOR *destination, int speed); // 0x00410630 - -#define ClipCamera ((void(__cdecl*)(int*, int*, int*, int, int, int, int, int, int, int)) 0x004109B0) -#define ShiftCamera ((void(__cdecl*)(int*, int*, int*, int, int, int, int, int, int, int)) 0x00410A90) -#define GoodPosition ((FLOOR_INFO*(__cdecl*)(int, int, int, __int16)) 0x00410BF0) -#define SmartShift ((void(__cdecl*)(GAME_VECTOR*, CB_SMARTCAM)) 0x00410C40) -#define ChaseCamera ((void(__cdecl*)(ITEM_INFO*)) 0x004113D0) -#define ShiftClamp ((int(__cdecl*)(GAME_VECTOR*, int)) 0x004114C0) -#define CombatCamera ((void(__cdecl*)(ITEM_INFO*)) 0x00411660) - +void __cdecl ClipCamera(int *x, int *y, int *z, int tx, int ty, int tz, int left, int top, int right, int bottom); // 0x004109B0 +void __cdecl ShiftCamera(int *x, int *y, int *z, int tx, int ty, int tz, int left, int top, int right, int bottom); // 0x00410A90 +FLOOR_INFO* __cdecl GoodPosition(int x, int y, int z, __int16 roomID); // 0x00410BF0 +void __cdecl SmartShift(GAME_VECTOR *goal, CB_SMARTCAM shift); // 0x00410C40 +void __cdecl ChaseCamera(ITEM_INFO *item); // 0x004113D0 +int __cdecl ShiftClamp(GAME_VECTOR *pos, int clamp); // 0x004114C0 +void __cdecl CombatCamera(ITEM_INFO *item); // 0x00411660 void __cdecl LookCamera(ITEM_INFO *item); // 0x004117F0 void __cdecl FixedCamera(); // 0x004119E0 void __cdecl CalculateCamera(); // 0x00411A80 diff --git a/game/cinema.cpp b/game/cinema.cpp index e3f8107..66cb016 100644 --- a/game/cinema.cpp +++ b/game/cinema.cpp @@ -21,9 +21,15 @@ #include "global/precompiled.h" #include "game/cinema.h" +#include "3dsystem/3d_gen.h" +#include "3dsystem/phd_math.h" +#include "game/control.h" #include "game/draw.h" #include "game/hair.h" +#include "game/items.h" +#include "game/laramisc.h" #include "game/setup.h" +#include "game/sphere.h" #include "specific/frontend.h" #include "specific/input.h" #include "specific/output.h" @@ -148,6 +154,158 @@ int __cdecl DoCinematic(int nTicks) { return 0; } +void __cdecl CalculateCinematicCamera() { + CINE_FRAME_INFO *frame; + int c, s, sourceX, sourceY, sourceZ, targetX, targetY, targetZ; + __int16 roomID; + + frame = &CineFrames[CineFrameIdx]; + c = phd_cos(Camera.targetAngle); + s = phd_sin(Camera.targetAngle); + targetX = LaraItem->pos.x + ((s * frame->zTarget + c * frame->xTarget) >> W2V_SHIFT); + targetY = LaraItem->pos.y + frame->yTarget; + targetZ = LaraItem->pos.z + ((c * frame->zTarget - s * frame->xTarget) >> W2V_SHIFT); + sourceX = LaraItem->pos.x + ((s * frame->xPos + c * frame->zPos) >> W2V_SHIFT); + sourceZ = LaraItem->pos.z + ((c * frame->xPos - s * frame->zPos) >> W2V_SHIFT); + sourceY = LaraItem->pos.y + frame->yPos; + roomID = GetCinematicRoom(sourceX, sourceY, sourceZ); + if (roomID >= 0) + Camera.pos.roomNumber = roomID; + AlterFOV(frame->fov); + phd_LookAt(sourceX, sourceY, sourceZ, targetX, targetY, targetZ, frame->roll); +} + +int __cdecl GetCinematicRoom(int x, int y, int z) { + __int16 roomID; + int i; + ROOM_INFO *room; + + roomID = -1; + for (i = 0; i < RoomCount; ++i) { + room = &RoomInfo[i]; + if (x >= room->x + 1024 && + x < room->x + (room->ySize << WALL_SHIFT) - 1024 && + y >= room->maxCeiling && + y <= room->minFloor && + z >= room->z + 1024 && + z < room->z + (room->xSize << WALL_SHIFT) - 1024) + { + roomID = i; + break; + } + } + return roomID; +} + +void __cdecl ControlCinematicPlayer(__int16 itemID) { + ITEM_INFO *item; + PHD_VECTOR pos; + __int16 roomID; + + item = &Items[itemID]; + item->pos.rotY = Camera.targetAngle; + item->pos.x = Camera.pos.x; + item->pos.y = Camera.pos.y; + item->pos.z = Camera.pos.z; + pos.x = 0; + pos.y = 0; + pos.z = 0; + GetJointAbsPosition(item, &pos, 0); + roomID = GetCinematicRoom(pos.x, pos.y, pos.z); + if (roomID != -1 && item->roomNumber != roomID) + ItemNewRoom(itemID, roomID); + if (item->dynamic_light && item->status != ITEM_INVISIBLE) { + pos.x = 0; + pos.y = 0; + pos.z = 0; + GetJointAbsPosition(item, &pos, 0); + AddDynamicLight(pos.x, pos.y, pos.z, 12, 11); + } + AnimateItem(item); +} + +void __cdecl LaraControlCinematic(__int16 itemID) { + ITEM_INFO *item; + PHD_VECTOR pos; + __int16 roomID; + + item = &Items[itemID]; + item->pos.rotY = Camera.targetAngle; + item->pos.x = Camera.pos.x; + item->pos.y = Camera.pos.y; + item->pos.z = Camera.pos.z; + pos.x = 0; + pos.y = 0; + pos.z = 0; + GetJointAbsPosition(item, &pos, 0); + roomID = GetCinematicRoom(pos.x, pos.y, pos.z); + if (roomID != -1 && item->roomNumber != roomID) + ItemNewRoom(itemID, roomID); + AnimateLara(item); +} + +void __cdecl InitialisePlayer1(__int16 itemID) { + ITEM_INFO *item; + + Objects[ID_LARA].drawRoutine = DrawLara; + Objects[ID_LARA].control = LaraControlCinematic; + AddActiveItem(itemID); + item = &Items[itemID]; + Camera.pos.x = item->pos.x; + Camera.pos.y = item->pos.y; + Camera.pos.z = item->pos.z; + item->pos.rotY = 0; + Camera.targetAngle = 0; + Camera.pos.roomNumber = item->roomNumber; + item->dynamic_light = 0; + item->goalAnimState = AS_WALK; + item->currentAnimState = AS_WALK; + item->frameNumber = 0; + item->animNumber = 0; + Lara.hit_direction = -1; +} + +void __cdecl InitialiseGenPlayer(__int16 itemID) { + ITEM_INFO *item; + + AddActiveItem(itemID); + item = &Items[itemID]; + item->pos.rotY = 0; + item->dynamic_light = 0; +} + +void __cdecl InGameCinematicCamera() { + CINE_FRAME_INFO *frame; + int c, s; + + ++CineFrameIdx; + if (CineFrameIdx >= CineFramesCount) + CineFrameIdx = CineFramesCount - 1; + frame = &CineFrames[CineFrameIdx]; + c = phd_cos(CinematicPos.rotY); + s = phd_sin(CinematicPos.rotY); + Camera.target.x = CinematicPos.x + ((s * frame->zTarget + c * frame->xTarget) >> W2V_SHIFT); + Camera.target.y = CinematicPos.y + frame->yTarget; + Camera.target.z = CinematicPos.z + ((c * frame->zTarget - s * frame->xTarget) >> W2V_SHIFT); + Camera.pos.x = CinematicPos.x + ((s * frame->xPos + c * frame->zPos) >> W2V_SHIFT); + Camera.pos.y = CinematicPos.y + frame->yPos; + Camera.pos.z = CinematicPos.z + ((c * frame->xPos - s * frame->zPos) >> W2V_SHIFT); + AlterFOV(frame->fov); + phd_LookAt(Camera.pos.x, Camera.pos.y, Camera.pos.z, Camera.target.x, Camera.target.y, Camera.target.z, frame->roll); + GetFloor(Camera.pos.x, Camera.pos.y, Camera.pos.z, &Camera.pos.roomNumber); + if (Camera.isLaraMic) { + Camera.actualAngle = LaraItem->pos.rotY + Lara.head_y_rot + Lara.torso_y_rot; + Camera.micPos.x = LaraItem->pos.x; + Camera.micPos.y = LaraItem->pos.y; + Camera.micPos.z = LaraItem->pos.z; + } else { + Camera.actualAngle = phd_atan(Camera.target.z - Camera.pos.z, Camera.target.x - Camera.pos.x); + Camera.micPos.x = Camera.pos.x + (phd_sin(Camera.actualAngle) * PhdPersp >> W2V_SHIFT); + Camera.micPos.z = Camera.pos.z + (phd_cos(Camera.actualAngle) * PhdPersp >> W2V_SHIFT); + Camera.micPos.y = Camera.pos.y; + } +} + /* * Inject function */ @@ -156,12 +314,11 @@ void Inject_Cinema() { INJECT(0x00411F40, StartCinematic); INJECT(0x00412060, InitCinematicRooms); INJECT(0x00412100, DoCinematic); - -// INJECT(0x00412270, CalculateCinematicCamera); -// INJECT(0x004123B0, GetCinematicRoom); -// INJECT(0x00412430, ControlCinematicPlayer); -// INJECT(0x00412510, LaraControlCinematic); -// INJECT(0x004125B0, InitialisePlayer1); -// INJECT(0x00412640, InitialiseGenPlayer); -// INJECT(0x00412680, InGameCinematicCamera); + INJECT(0x00412270, CalculateCinematicCamera); + INJECT(0x004123B0, GetCinematicRoom); + INJECT(0x00412430, ControlCinematicPlayer); + INJECT(0x00412510, LaraControlCinematic); + INJECT(0x004125B0, InitialisePlayer1); + INJECT(0x00412640, InitialiseGenPlayer); + INJECT(0x00412680, InGameCinematicCamera); } diff --git a/game/cinema.h b/game/cinema.h index b818311..05f24d4 100644 --- a/game/cinema.h +++ b/game/cinema.h @@ -31,13 +31,12 @@ void __cdecl SetCutsceneTrack(int track); // 0x00411F30 int __cdecl StartCinematic(int levelID); // 0x00411F40 void __cdecl InitCinematicRooms(); // 0x00412060 int __cdecl DoCinematic(int nTicks); // 0x00412100 - -#define CalculateCinematicCamera ((void(__cdecl*)(void)) 0x00412270) -#define GetCinematicRoom ((int(__cdecl*)(int, int, int)) 0x004123B0) -#define ControlCinematicPlayer ((void(__cdecl*)(__int16)) 0x00412430) -#define LaraControlCinematic ((void(__cdecl*)(__int16)) 0x00412510) -#define InitialisePlayer1 ((void(__cdecl*)(__int16)) 0x004125B0) -#define InitialiseGenPlayer ((void(__cdecl*)(__int16)) 0x00412640) -#define InGameCinematicCamera ((void(__cdecl*)(void)) 0x00412680) +void __cdecl CalculateCinematicCamera(); // 0x00412270 +int __cdecl GetCinematicRoom(int x, int y, int z); // 0x004123B0 +void __cdecl ControlCinematicPlayer(__int16 itemID); // 0x00412430 +void __cdecl LaraControlCinematic(__int16 itemID); // 0x00412510 +void __cdecl InitialisePlayer1(__int16 itemID); // 0x004125B0 +void __cdecl InitialiseGenPlayer(__int16 itemID); // 0x00412640 +void __cdecl InGameCinematicCamera(); // 0x00412680 #endif // CINEMA_H_INCLUDED diff --git a/game/collide.cpp b/game/collide.cpp index 2562da0..47d4d53 100644 --- a/game/collide.cpp +++ b/game/collide.cpp @@ -21,9 +21,227 @@ #include "global/precompiled.h" #include "game/collide.h" +#include "3dsystem/phd_math.h" #include "game/control.h" #include "global/vars.h" +void __cdecl GetCollisionInfo(COLL_INFO *coll, int x, int y, int z, __int16 roomID, int height) { + int head, top, h, c, frontX, frontZ, leftX, leftZ, rightX, rightZ; + FLOOR_INFO *floor; + __int16 tilt; + + coll->collType = 0; + coll->shift.z = 0; + coll->shift.y = 0; + coll->shift.x = 0; + head = y - height; + top = head - 160; + coll->quadrant = (UINT16) (coll->facing + PHD_45) >> W2V_SHIFT; + floor = GetFloor(x, top, z, &roomID); + h = GetHeight(floor, x, top, z); + if (h != NO_HEIGHT) + h -= y; + c = GetCeiling(floor, x, top, z); + if (c != NO_HEIGHT) + c -= head; + coll->sideMid.floor = h; + coll->sideMid.ceiling = c; + coll->sideMid.type = HeightType; + coll->trigger = TriggerPtr; + tilt = GetTiltType(floor, x, LaraItem->pos.y, z); + coll->xTilt = tilt; + coll->zTilt = tilt >> 8; + switch (coll->quadrant) { + case 0: + frontX = coll->radius * phd_sin(coll->facing) >> W2V_SHIFT; + frontZ = coll->radius; + leftX = -coll->radius; + leftZ = coll->radius; + rightX = coll->radius; + rightZ = coll->radius; + break; + case 1: + frontX = coll->radius; + frontZ = coll->radius * phd_cos(coll->facing) >> W2V_SHIFT; + leftX = coll->radius; + leftZ = coll->radius; + rightX = coll->radius; + rightZ = -coll->radius; + break; + case 2: + frontX = coll->radius * phd_sin(coll->facing) >> W2V_SHIFT; + frontZ = -coll->radius; + leftX = coll->radius; + leftZ = -coll->radius; + rightX = -coll->radius; + rightZ = -coll->radius; + break; + case 3: + frontX = -coll->radius; + frontZ = coll->radius * phd_cos(coll->facing) >> W2V_SHIFT; + rightZ = coll->radius; + leftX = -coll->radius; + leftZ = -coll->radius; + rightX = -coll->radius; + break; + default: + frontZ = 0; + frontX = 0; + leftZ = 0; + leftX = 0; + rightZ = 0; + rightX = 0; + break; + } + floor = GetFloor(x + frontX, top, z + frontZ, &roomID); + h = GetHeight(floor, x + frontX, top, z + frontZ); + if (h != NO_HEIGHT) + h -= y; + c = GetCeiling(floor, x + frontX, top, z + frontZ); + if (c != NO_HEIGHT) + c -= head; + coll->sideFront.floor = h; + coll->sideFront.ceiling = c; + coll->sideFront.type = HeightType; + if (CHK_ANY(coll->flags, 1) && coll->sideFront.type == HT_BIG_SLOPE && coll->sideFront.floor < 0) { + coll->sideFront.floor = -32767; + } else { + if ((CHK_ANY(coll->flags, 2) && + coll->sideFront.type == HT_BIG_SLOPE && + coll->sideFront.floor > 0) || + (CHK_ANY(coll->flags, 4) && + coll->sideFront.floor > 0 && + TriggerPtr && + (*TriggerPtr & DATA_TYPE) == FT_LAVA)) + coll->sideFront.floor = 512; + } + floor = GetFloor(x + leftX, top, z + leftZ, &roomID); + h = GetHeight(floor, x + leftX, top, z + leftZ); + if (h != NO_HEIGHT) + h -= y; + c = GetCeiling(floor, x + leftX, top, z + leftZ); + if (c != NO_HEIGHT) + c -= head; + coll->sideLeft.ceiling = c; + coll->sideLeft.floor = h; + coll->sideLeft.type = HeightType; + if (CHK_ANY(coll->flags, 1) && coll->sideLeft.type == HT_BIG_SLOPE && coll->sideLeft.floor < 0) { + coll->sideLeft.floor = -32767; + } else { + if ((CHK_ANY(coll->flags, 2) && + coll->sideLeft.type == HT_BIG_SLOPE && + coll->sideLeft.floor > 0) || + (CHK_ANY(coll->flags, 4) && + coll->sideLeft.floor > 0 && + TriggerPtr && + (*TriggerPtr & DATA_TYPE) == FT_LAVA)) + coll->sideLeft.floor = 512; + } + floor = GetFloor(x + rightX, top, z + rightZ, &roomID); + h = GetHeight(floor, x + rightX, top, z + rightZ); + if (h != NO_HEIGHT) + h -= y; + c = GetCeiling(floor, x + rightX, top, z + rightZ); + if (c != NO_HEIGHT) + c -= head; + coll->sideRight.ceiling = c; + coll->sideRight.floor = h; + coll->sideRight.type = HeightType; + if (CHK_ANY(coll->flags, 1) && coll->sideRight.type == HT_BIG_SLOPE && coll->sideRight.floor < 0) { + coll->sideRight.floor = -32767; + } else { + if ((CHK_ANY(coll->flags, 2) && + coll->sideRight.type == HT_BIG_SLOPE && + coll->sideRight.floor > 0) || + (CHK_ANY(coll->flags, 4) && + coll->sideRight.floor > 0 && + TriggerPtr && + (*TriggerPtr & DATA_TYPE) == FT_LAVA)) + coll->sideRight.floor = 512; + } + if (CollideStaticObjects(coll, x, y, z, roomID, height)) { + floor = GetFloor(x + coll->shift.x, y, z + coll->shift.z, &roomID); + if (GetHeight(floor, x + coll->shift.x, y, z + coll->shift.z) < y - 512 || + GetCeiling(floor, x + coll->shift.x, y, z + coll->shift.z) > head) + { + coll->shift.x = -coll->shift.x; + coll->shift.z = -coll->shift.z; + } + } + if (coll->sideMid.floor == NO_HEIGHT) { + coll->shift.y = coll->old.y - y; + coll->shift.x = coll->old.x - x; + coll->shift.z = coll->old.z - z; + coll->collType = COLL_FRONT; + } else { + if (coll->sideMid.floor - coll->sideMid.ceiling <= 0) { + coll->shift.y = coll->old.y - y; + coll->shift.x = coll->old.x - x; + coll->shift.z = coll->old.z - z; + coll->collType = COLL_CLAMP; + } else { + if (coll->sideMid.ceiling >= 0) { + coll->shift.y = coll->sideMid.ceiling; + coll->collType = COLL_TOP; + } + if (coll->sideFront.floor <= coll->badPos && + coll->sideFront.floor >= coll->badNeg && + coll->sideFront.ceiling <= coll->badCeiling) + { + if (coll->sideFront.ceiling >= coll->badCeiling) + { + coll->shift.y = coll->old.y - y; + coll->shift.x = coll->old.x - x; + coll->shift.z = coll->old.z - z; + coll->collType = COLL_TOPFRONT; + } else { + if (coll->sideLeft.floor <= coll->badPos && coll->sideLeft.floor >= coll->badNeg) { + if (coll->sideRight.floor > coll->badPos || coll->sideRight.floor < coll->badNeg) { + switch (coll->quadrant) { + case 0: + case 2: + coll->shift.x = FindGridShift(x + rightX, x + frontX); + break; + case 1: + case 3: + coll->shift.z = FindGridShift(z + rightZ, z + frontZ); + break; + } + coll->collType = COLL_RIGHT; + } + } else { + switch (coll->quadrant) { + case 0: + case 2: + coll->shift.x = FindGridShift(x + leftX, x + frontX); + break; + case 1: + case 3: + coll->shift.z = FindGridShift(z + leftZ, z + frontZ); + break; + } + coll->collType = COLL_LEFT; + } + } + } else { + switch (coll->quadrant) { + case 0: + case 2: + coll->shift.x = coll->old.x - x; + coll->shift.z = FindGridShift(z + frontZ, z); + break; + case 1: + case 3: + coll->shift.x = FindGridShift(x + frontX, x); + coll->shift.z = coll->old.z - z; + break; + } + coll->collType = COLL_FRONT; + } + } + } +} + int __cdecl CollideStaticObjects(COLL_INFO *coll, int x, int y, int z, __int16 roomID, int hite) { int rxMin = x - coll->radius; int rxMax = x + coll->radius; @@ -195,7 +413,8 @@ void __cdecl GetNewRoom(int x, int y, int z, __int16 roomID) { * Inject function */ void Inject_Collide() { -// INJECT(0x004128D0, GetCollisionInfo); + INJECT(0x004128D0, GetCollisionInfo); + // INJECT(0x00412F90, FindGridShift); INJECT(0x00412FC0, CollideStaticObjects); diff --git a/game/collide.h b/game/collide.h index e7bccfb..3f0ccc2 100644 --- a/game/collide.h +++ b/game/collide.h @@ -27,8 +27,9 @@ /* * Function list */ -// 0x004128D0: GetCollisionInfo -// 0x00412F90: FindGridShift +void __cdecl GetCollisionInfo(COLL_INFO *coll, int x, int y, int z, __int16 roomID, int height); // 0x004128D0 + +#define FindGridShift ((int(__cdecl*)(int, int)) 0x00412F90) int __cdecl CollideStaticObjects(COLL_INFO *coll, int x, int y, int z, __int16 roomID, int hite); // 0x00412FC0 void __cdecl GetNearByRooms(int x, int y, int z, int r, int h, __int16 roomID); // 0x004133B0 @@ -37,8 +38,8 @@ void __cdecl GetNewRoom(int x, int y, int z, __int16 roomID); // 0x00413480 // 0x004134E0: ShiftItem #define UpdateLaraRoom ((void(__cdecl*)(ITEM_INFO*, int)) 0x00413520) +#define GetTiltType ((__int16(__cdecl*)(FLOOR_INFO*, int, int, int)) 0x00413580) -// 0x00413580: GetTiltType // 0x00413620: LaraBaddieCollision // 0x004137C0: EffectSpaz @@ -47,8 +48,10 @@ void __cdecl GetNewRoom(int x, int y, int z, __int16 roomID); // 0x00413480 // 0x00413920: DoorCollision // 0x004139A0: TrapCollision -// 0x00413A10: ItemPushLara -// 0x00413D20: TestBoundsCollide + +#define ItemPushLara ((void(__cdecl*)(ITEM_INFO*, ITEM_INFO*, COLL_INFO*, BOOL, BOOL)) 0x00413A10) +#define TestBoundsCollide ((int(__cdecl*)(ITEM_INFO*, ITEM_INFO*, int)) 0x00413D20) + // 0x00413DF0: TestLaraPosition // 0x00413F30: AlignLaraPosition // 0x00414070: MoveLaraPosition diff --git a/game/control.cpp b/game/control.cpp index d60148d..d38481b 100644 --- a/game/control.cpp +++ b/game/control.cpp @@ -173,6 +173,200 @@ int __cdecl ControlPhase(int nTicks, BOOL demoMode) { return 0; } +int __cdecl LOS(GAME_VECTOR *start, GAME_VECTOR *target) { + int beginning, ending; + + if (ABS(target->z - start->z) > ABS(target->x - start->x)) { + beginning = xLOS(start, target); + ending = zLOS(start, target); + } else { + beginning = zLOS(start, target); + ending = xLOS(start, target); + } + return ending && ClipTarget(start, target, GetFloor(target->x, target->y, target->z, &target->roomNumber)) && beginning == 1 && ending == 1; +} + +int __cdecl zLOS(GAME_VECTOR *start, GAME_VECTOR *target) { + int dx, dy, dz, x, y, z; + __int16 previousID, roomID; + FLOOR_INFO *floor; + + dz = target->z - start->z; + if (!dz) + return 1; + dx = ((target->x - start->x) << WALL_SHIFT) / dz; + previousID = start->roomNumber; + roomID = start->roomNumber; + LosRooms[0] = start->roomNumber; + LosRoomsCount = 1; + dy = ((target->y - start->y) << WALL_SHIFT) / dz; + if (dz < 0) { + z = start->z & -0x400; + x = start->x + ((z - start->z) * dx >> WALL_SHIFT); + y = start->y + ((z - start->z) * dy >> WALL_SHIFT); + while (z > target->z) { + floor = GetFloor(x, y, z, &roomID); + if (y > GetHeight(floor, x, y, z) || y < GetCeiling(floor, x, y, z)) { + target->x = x; + target->y = y; + target->z = z; + target->roomNumber = roomID; + return -1; + } + if (roomID != previousID) { + previousID = roomID; + LosRooms[LosRoomsCount] = roomID; + ++LosRoomsCount; + } + floor = GetFloor(x, y, z - 1, &roomID); + if (y > GetHeight(floor, x, y, z - 1) || y < GetCeiling(floor, x, y, z - 1)) { + target->x = x; + target->roomNumber = previousID; + target->y = y; + target->z = z; + return 0; + } + z -= 1024; + x -= dx; + y -= dy; + } + } else { + z = start->z | 0x3FF; + x = start->x + ((z - start->z) * dx >> WALL_SHIFT); + y = start->y + ((z - start->z) * dy >> WALL_SHIFT); + while (z < target->z) { + floor = GetFloor(x, y, z, &roomID); + if (y > GetHeight(floor, x, y, z) || y < GetCeiling(floor, x, y, z)) { + target->x = x; + target->y = y; + target->z = z; + target->roomNumber = roomID; + return -1; + } + if (roomID != previousID) { + previousID = roomID; + LosRooms[LosRoomsCount] = roomID; + ++LosRoomsCount; + } + floor = GetFloor(x, y, z + 1, &roomID); + if (y > GetHeight(floor, x, y, z + 1) || y < GetCeiling(floor, x, y, z + 1)) { + target->x = x; + target->y = y; + target->z = z; + target->roomNumber = previousID; + return 0; + } + z += 1024; + x += dx; + y += dy; + } + } + target->roomNumber = roomID; + return 1; +} + +int __cdecl xLOS(GAME_VECTOR *start, GAME_VECTOR *target) { + int dx, dy, dz, x, y, z; + __int16 previousID, roomID; + FLOOR_INFO *floor; + + dx = target->x - start->x; + if (!dx) + return 1; + dy = ((target->y - start->y) << WALL_SHIFT) / dx; + previousID = start->roomNumber; + roomID = start->roomNumber; + LosRooms[0] = start->roomNumber; + LosRoomsCount = 1; + dz = ((target->z - start->z) << WALL_SHIFT) / dx; + if (dx < 0) { + x = start->x & -0x400; + y = start->y + ((x - start->x) * dy >> WALL_SHIFT); + z = start->z + ((x - start->x) * dz >> WALL_SHIFT); + while (x > target->x) { + floor = GetFloor(x, y, z, &roomID); + if (y > GetHeight(floor, x, y, z) || y < GetCeiling(floor, x, y, z)) { + target->x = x; + target->y = y; + target->z = z; + target->roomNumber = roomID; + return -1; + } + if (roomID != previousID) { + previousID = roomID; + LosRooms[LosRoomsCount] = roomID; + ++LosRoomsCount; + } + floor = GetFloor(x - 1, y, z, &roomID); + if (y > GetHeight(floor, x - 1, y, z) || y < GetCeiling(floor, x - 1, y, z)) { + target->x = x; + target->roomNumber = previousID; + target->y = y; + target->z = z; + return 0; + } + x -= 1024; + y -= dy; + z -= dz; + } + } else { + x = start->x | 0x3FF; + y = start->y + ((x - start->x) * dy >> WALL_SHIFT); + z = start->z + ((x - start->x) * dz >> WALL_SHIFT); + while (x < target->x) { + floor = GetFloor(x, y, z, &roomID); + if (y > GetHeight(floor, x, y, z) || y < GetCeiling(floor, x, y, z)) { + target->z = z; + target->y = y; + target->x = x; + target->roomNumber = roomID; + return -1; + } + if (roomID != previousID) { + previousID = roomID; + LosRooms[LosRoomsCount] = roomID; + ++LosRoomsCount; + } + floor = GetFloor(x + 1, y, z, &roomID); + if (y > GetHeight(floor, x + 1, y, z) || y < GetCeiling(floor, x + 1, y, z)) { + target->x = x; + target->y = y; + target->z = z; + target->roomNumber = previousID; + return 0; + } + x += 1024; + y += dy; + z += dz; + } + } + target->roomNumber = roomID; + return 1; +} + +int __cdecl ClipTarget(GAME_VECTOR *start, GAME_VECTOR *target, FLOOR_INFO *floor) { + int dx, dy, dz, height, ceiling; + + dx = target->x - start->x; + dy = target->y - start->y; + dz = target->z - start->z; + height = GetHeight(floor, target->x, target->y, target->z); + if (target->y > height && start->y < height) { + target->y = height; + target->x = start->x + (target->y - start->y) * dx / dy; + target->z = start->z + (target->y - start->y) * dz / dy; + return 0; + } + ceiling = GetCeiling(floor, target->x, target->y, target->z); + if (target->y < ceiling && start->y > ceiling) { + target->y = ceiling; + target->x = start->x + (target->y - start->y) * dx / dy; + target->z = start->z + (target->y - start->y) * dz / dy; + return 0; + } + return 1; +} + void __cdecl TriggerCDTrack(__int16 value, UINT16 flags, __int16 type) { if( value > 1 && value < 64 ) { TriggerNormalCDTrack(value, flags, type); @@ -226,10 +420,12 @@ void Inject_Control() { // INJECT(0x004158A0, TriggerActive); // INJECT(0x00415900, GetCeiling); // INJECT(0x00415B60, GetDoor); -// INJECT(0x00415BB0, LOS); -// INJECT(0x00415C50, zLOS); -// INJECT(0x00415F40, xLOS); -// INJECT(0x00416230, ClipTarget); + + INJECT(0x00415BB0, LOS); + INJECT(0x00415C50, zLOS); + INJECT(0x00415F40, xLOS); + INJECT(0x00416230, ClipTarget); + // INJECT(0x00416310, ObjectOnLOS); // INJECT(0x00416610, FlipMap); // INJECT(0x004166D0, RemoveRoomFlipItems); diff --git a/game/control.h b/game/control.h index b2cc6cc..0392488 100644 --- a/game/control.h +++ b/game/control.h @@ -46,13 +46,12 @@ int __cdecl ControlPhase(int nTicks, BOOL demoMode); // 0x00415B60: GetDoor -#define LOS ((int(__cdecl*)(GAME_VECTOR*, GAME_VECTOR*)) 0x00415BB0) - -// 0x00415C50: zLOS -// 0x00415F40: xLOS -// 0x00416230: ClipTarget -// 0x00416310: ObjectOnLOS +int __cdecl LOS(GAME_VECTOR *start, GAME_VECTOR *target); // 0x00415BB0 +int __cdecl zLOS(GAME_VECTOR *start, GAME_VECTOR *target); // 0x00415C50 +int __cdecl xLOS(GAME_VECTOR *start, GAME_VECTOR *target); // 0x00415F40 +int __cdecl ClipTarget(GAME_VECTOR *start, GAME_VECTOR *target, FLOOR_INFO *floor); // 0x00416230 +#define ObjectOnLOS ((int(__cdecl*)(GAME_VECTOR*, GAME_VECTOR*)) 0x00416310) #define FlipMap ((void(__cdecl*)(void)) 0x00416610) // 0x004166D0: RemoveRoomFlipItems diff --git a/game/demo.cpp b/game/demo.cpp index 6b183db..cf250ee 100644 --- a/game/demo.cpp +++ b/game/demo.cpp @@ -21,6 +21,9 @@ #include "global/precompiled.h" #include "game/demo.h" +#include "game/control.h" +#include "game/gameflow.h" +#include "game/items.h" #include "game/laramisc.h" #include "game/setup.h" #include "game/text.h" @@ -34,6 +37,21 @@ extern bool PsxBarPosEnabled; DWORD DemoTextMode = 0; #endif // FEATURE_HUD_IMPROVED +int __cdecl DoDemoSequence(int levelID) { + static int DemoLevelID = 0; + + if (levelID < 0 && !GF_GameFlow.num_Demos) + return GF_EXIT_TO_TITLE; + if (levelID < 0) { + if (DemoLevelID >= GF_GameFlow.num_Demos) + DemoLevelID = 0; + ++DemoLevelID; + return GF_DoLevelSequence(GF_DemoLevels[DemoLevelID - 1], GFL_DEMO); + } + DemoLevelID = levelID; + return GF_DoLevelSequence(levelID, GFL_DEMO); +} + int __cdecl StartDemo(int levelID) { static int DemoLevelID = 0; @@ -108,14 +126,42 @@ int __cdecl StartDemo(int levelID) { return result; } +void __cdecl LoadLaraDemoPos() { + __int16 roomID; + + LaraItem->pos.x = ((int *) DemoPtr)[0]; + LaraItem->pos.y = ((int *) DemoPtr)[1]; + LaraItem->pos.z = ((int *) DemoPtr)[2]; + LaraItem->pos.rotX = ((int *) DemoPtr)[3]; + LaraItem->pos.rotY = ((int *) DemoPtr)[4]; + LaraItem->pos.rotZ = ((int *) DemoPtr)[5]; + roomID = ((int *) DemoPtr)[6]; + if (LaraItem->roomNumber != roomID) + ItemNewRoom(Lara.item_number, roomID); + LaraItem->floor = GetHeight(GetFloor(LaraItem->pos.x, LaraItem->pos.y, LaraItem->pos.z, &roomID), LaraItem->pos.x, LaraItem->pos.y, LaraItem->pos.z); + Lara.last_gun_type = ((int *) DemoPtr)[7]; + DemoCount += 8; +} + +void __cdecl GetDemoInput() { + DWORD input; + + if (DemoCount < 9000) { + input = ((DWORD *) DemoPtr)[DemoCount]; + } else { + input = 0xFFFFFFFF; + } + InputStatus = input; + if (input != 0xFFFFFFFF) + ++DemoCount; +} + /* * Inject function */ void Inject_Demo() { -// INJECT(0x004168E0, DoDemoSequence); - + INJECT(0x004168E0, DoDemoSequence); INJECT(0x00416940, StartDemo); - -// INJECT(0x00416AF0, LoadLaraDemoPos); -// INJECT(0x00416BC0, GetDemoInput); + INJECT(0x00416AF0, LoadLaraDemoPos); + INJECT(0x00416BC0, GetDemoInput); } diff --git a/game/demo.h b/game/demo.h index 0c545c1..abaf46e 100644 --- a/game/demo.h +++ b/game/demo.h @@ -27,11 +27,9 @@ /* * Function list */ -#define DoDemoSequence ((int(__cdecl*)(int)) 0x004168E0) - +int __cdecl DoDemoSequence(int levelID); // 0x004168E0 int __cdecl StartDemo(int levelID); // 0x00416940 - -#define LoadLaraDemoPos ((void(__cdecl*)(void)) 0x00416AF0) -#define GetDemoInput ((void(__cdecl*)(void)) 0x00416BC0) +void __cdecl LoadLaraDemoPos(); // 0x00416AF0 +void __cdecl GetDemoInput(); // 0x00416BC0 #endif // DEMO_H_INCLUDED diff --git a/game/draw.cpp b/game/draw.cpp index c6c29f8..f19de20 100644 --- a/game/draw.cpp +++ b/game/draw.cpp @@ -994,6 +994,26 @@ void __cdecl DrawGunFlash(int weapon, int clip) { #endif // FEATURE_VIDEOFX_IMPROVED } +void __cdecl CalculateObjectLighting(ITEM_INFO *item, __int16 *frame) { + int x, y, z; + + if (item->shade1 < 0) { + phd_PushUnitMatrix(); + PhdMatrixPtr->_23 = 0; + PhdMatrixPtr->_13 = 0; + PhdMatrixPtr->_03 = 0; + phd_RotYXZ(item->pos.rotY, item->pos.rotX, item->pos.rotZ); + phd_TranslateRel((frame[0] + frame[1]) >> 1, (frame[2] + frame[3]) >> 1, (frame[4] + frame[5]) >> 1); + x = item->pos.x + (PhdMatrixPtr->_03 >> W2V_SHIFT); + y = item->pos.y + (PhdMatrixPtr->_13 >> W2V_SHIFT); + z = item->pos.z + (PhdMatrixPtr->_23 >> W2V_SHIFT); + phd_PopMatrix(); + S_CalculateLight(x, y, z, item->roomNumber); + } else { + S_CalculateStaticMeshLight(item->pos.x, item->pos.y, item->pos.z, item->shade1, item->shade2, &RoomInfo[item->roomNumber]); + } +} + void __cdecl AddDynamicLight(int x, int y, int z, int intensity, int falloff) { int idx = ( DynamicLightCount < ARRAY_SIZE(DynamicLights) ) ? DynamicLightCount++ : 0; DynamicLights[idx].x = x; @@ -1044,8 +1064,8 @@ void Inject_Draw() { // INJECT(0x0041BC10, InterpolateArmMatrix); INJECT(0x0041BD10, DrawGunFlash); + INJECT(0x0041BE80, CalculateObjectLighting); -// INJECT(0x0041BE80, CalculateObjectLighting); // INJECT(0x0041BF70, GetFrames); // INJECT(0x0041C010, GetBoundsAccurate); // INJECT(0x0041C090, GetBestFrame); diff --git a/game/draw.h b/game/draw.h index ef8274d..c94019d 100644 --- a/game/draw.h +++ b/game/draw.h @@ -63,8 +63,8 @@ void __cdecl phd_PutPolygons_I(__int16 *ptrObj, int clip); // 0x0041BA30 #define InterpolateArmMatrix ((void(__cdecl*)(void)) 0x0041BC10) void __cdecl DrawGunFlash(int weapon, int clip); +void __cdecl CalculateObjectLighting(ITEM_INFO *item, __int16 *frame); // 0x0041BE80 -#define CalculateObjectLighting ((void(__cdecl*)(ITEM_INFO*, __int16*)) 0x0041BE80) #define GetFrames ((int(__cdecl*)(ITEM_INFO*, __int16**, int*)) 0x0041BF70) #define GetBoundsAccurate ((__int16*(__cdecl*)(ITEM_INFO*)) 0x0041C010) #define GetBestFrame ((__int16*(__cdecl*)(ITEM_INFO*)) 0x0041C090) diff --git a/game/hair.cpp b/game/hair.cpp index 91fb200..22ccb9f 100644 --- a/game/hair.cpp +++ b/game/hair.cpp @@ -21,15 +21,268 @@ #include "global/precompiled.h" #include "game/hair.h" +#include "3dsystem/3d_gen.h" +#include "3dsystem/phd_math.h" +#include "game/control.h" +#include "game/draw.h" +#include "specific/game.h" #include "global/vars.h" +void __cdecl InitialiseHair() { + int *bone, i; + bone = &AnimBones[Objects[ID_LARA_HAIR].boneIndex]; + SkipHairPhysics = TRUE; + HairPos[0].rotY = 0; + HairPos[0].rotX = -PHD_90; + for (i = 1; i < 7; ++i) { + HairPos[i].x = bone[4 * i - 3]; + HairPos[i].y = bone[4 * i - 2]; + HairPos[i].z = bone[4 * i - 1]; + HairPos[i].rotX = -PHD_90; + HairPos[i].rotZ = 0; + HairVelocity[i].z = 0; + HairPos[i].rotY = 0; + HairVelocity[i].y = 0; + HairVelocity[i].x = 0; + } +} + +void __cdecl HairControl(BOOL isCutscene) { + __int16 *frame, *mesh, roomID; + UINT16 *rotation; + int *bone, x, y, z, i, j, water, height, random, dx, dy, dz, sum, distance; + SPHERE_INFO spheres[5]; + static int wind = 0; + + if (Lara.hit_direction >= 0) { + switch (Lara.hit_direction) { + case 1: + frame = &Anims[127].framePtr[Lara.hit_frame * (Anims[127].interpolation >> 8)]; + break; + case 2: + frame = &Anims[126].framePtr[Lara.hit_frame * (Anims[126].interpolation >> 8)]; + break; + case 3: + frame = &Anims[128].framePtr[Lara.hit_frame * (Anims[128].interpolation >> 8)]; + break; + default: + frame = &Anims[125].framePtr[Lara.hit_frame * (Anims[125].interpolation >> 8)]; + break; + } + } else { + frame = GetBestFrame(LaraItem); + } + phd_PushUnitMatrix(); + PhdMatrixPtr->_03 = LaraItem->pos.x << W2V_SHIFT; + PhdMatrixPtr->_13 = LaraItem->pos.y << W2V_SHIFT; + PhdMatrixPtr->_23 = LaraItem->pos.z << W2V_SHIFT; + phd_RotYXZ(LaraItem->pos.rotY, LaraItem->pos.rotX, LaraItem->pos.rotZ); + rotation = (UINT16 *) &frame[9]; + bone = &AnimBones[Objects[ID_LARA].boneIndex]; + phd_TranslateRel(frame[6], frame[7], frame[8]); + phd_RotYXZsuperpack(&rotation, 0); + phd_PushMatrix(); + mesh = Lara.mesh_ptrs[0]; + phd_TranslateRel(mesh[0], mesh[1], mesh[2]); + spheres[0].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + spheres[0].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + spheres[0].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + phd_PopMatrix(); + spheres[0].r = mesh[3]; + phd_TranslateRel(bone[25], bone[26], bone[27]); + if (Lara.weapon_item != -1 && + Lara.gun_type == LGT_M16 && + (!Items[Lara.weapon_item].currentAnimState || + Items[Lara.weapon_item].currentAnimState == 2 || + Items[Lara.weapon_item].currentAnimState == 4)) + { + rotation = (UINT16 *) &Lara.right_arm.frame_base[Lara.right_arm.frame_number * (Anims[Lara.right_arm.anim_number].interpolation >> 8) + 9]; + phd_RotYXZsuperpack(&rotation, 7); + } else { + phd_RotYXZsuperpack(&rotation, 6); + } + phd_RotYXZ(Lara.torso_y_rot, Lara.torso_x_rot, Lara.torso_z_rot); + phd_PushMatrix(); + mesh = Lara.mesh_ptrs[7]; + phd_TranslateRel(mesh[0], mesh[1], mesh[2]); + spheres[1].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + spheres[1].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + spheres[1].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + spheres[1].r = mesh[3]; + phd_PopMatrix(); + phd_PushMatrix(); + phd_TranslateRel(bone[29], bone[30], bone[31]); + phd_RotYXZsuperpack(&rotation, 0); + mesh = Lara.mesh_ptrs[8]; + phd_TranslateRel(mesh[0], mesh[1], mesh[2]); + spheres[3].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + spheres[3].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + spheres[3].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + phd_PopMatrix(); + spheres[3].r = 3 * mesh[3] / 2; + phd_PushMatrix(); + phd_TranslateRel(bone[41], bone[42], bone[43]); + phd_RotYXZsuperpack(&rotation, 2); + phd_TranslateRel(mesh[0], mesh[1], mesh[2]); + spheres[4].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + spheres[4].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + spheres[4].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + phd_PopMatrix(); + spheres[4].r = 3 * mesh[3] / 2; + phd_TranslateRel(bone[53], bone[54], bone[55]); + phd_RotYXZsuperpack(&rotation, 2); + phd_RotYXZ(Lara.head_y_rot, Lara.head_x_rot, Lara.head_z_rot); + phd_PushMatrix(); + mesh = Lara.mesh_ptrs[14]; + phd_TranslateRel(mesh[0], mesh[1], mesh[2]); + spheres[2].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + spheres[2].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + spheres[2].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + spheres[2].r = mesh[3]; + phd_PopMatrix(); + phd_TranslateRel(0, -23, -55); + x = PhdMatrixPtr->_03 >> W2V_SHIFT; + y = PhdMatrixPtr->_13 >> W2V_SHIFT; + z = PhdMatrixPtr->_23 >> W2V_SHIFT; + phd_PopMatrix(); + bone = &AnimBones[Objects[ID_LARA_HAIR].boneIndex]; + if (SkipHairPhysics) { + HairPos[0].z = z; + SkipHairPhysics = FALSE; + HairPos[0].x = x; + HairPos[0].y = y; + for (i = 1; i < 7; ++i) { + phd_PushUnitMatrix(); + PhdMatrixPtr->_03 = HairPos[i - 1].x << W2V_SHIFT; + PhdMatrixPtr->_13 = HairPos[i - 1].y << W2V_SHIFT; + PhdMatrixPtr->_23 = HairPos[i - 1].z << W2V_SHIFT; + phd_RotYXZ(HairPos[i - 1].rotY, HairPos[i - 1].rotX, 0); + phd_TranslateRel(bone[4 * i - 3], bone[4 * i - 2], bone[4 * i - 1]); + HairPos[i].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + HairPos[i].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + HairPos[i].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + phd_PopMatrix(); + } + wind = 0; + } else { + HairPos[0].x = x; + HairPos[0].y = y; + HairPos[0].z = z; + roomID = LaraItem->roomNumber; + if (isCutscene) { + water = NO_HEIGHT; + } else { + water = GetWaterHeight(LaraItem->pos.x + (frame[0] + frame[1]) / 2, + LaraItem->pos.y + (frame[2] + frame[3]) / 2, + LaraItem->pos.z + (frame[4] + frame[5]) / 2, + roomID); + } + height = GetHeight(GetFloor(x, y, z, &roomID), x, y, z); + if (height < y) + height = LaraItem->floor; + if (CHK_ANY(RoomInfo[roomID].flags, 0x20)) { + random = GetRandomDraw() & 7; + if (random) { + wind += random - 4; + if (wind < 0) { + wind = 0; + } else { + if (wind >= 8) + --wind; + } + } + } else { + wind = 0; + } + for (i = 1; i < 7; ++i) { + HairVelocity[0].z = HairPos[i].z; + HairVelocity[0].x = HairPos[i].x; + HairVelocity[0].y = HairPos[i].y; + HairPos[i].x += 3 * HairVelocity[i].x / 4; + HairPos[i].y += 3 * HairVelocity[i].y / 4; + HairPos[i].z += 3 * HairVelocity[i].z / 4; + switch (Lara.water_status) { + case LWS_AboveWater: + HairPos[i].y += 10; + if (water != NO_HEIGHT && HairPos[i].y > water) { + HairPos[i].y = water; + } else { + if (HairPos[i].y <= height) { + HairPos[i].z += wind; + } else { + HairPos[i].y = height; + } + } + break; + case LWS_Underwater: + case LWS_Surface: + case LWS_Wade: + if (HairPos[i].y < water) { + HairPos[i].y = water; + } else { + if (HairPos[i].y > height) + HairPos[i].y = height; + } + break; + } + for (j = 0; j < 5; ++j) { + dx = HairPos[i].x - spheres[j].x; + dy = HairPos[i].y - spheres[j].y; + dz = HairPos[i].z - spheres[j].z; + sum = SQR(dx) + SQR(dy) + SQR(dz); + if (sum < SQR(spheres[j].r)) { + distance = phd_sqrt(sum); + if (!distance) + distance = 1; + HairPos[i].x = spheres[j].x + dx * spheres[j].r / distance; + HairPos[i].y = spheres[j].y + dy * spheres[j].r / distance; + HairPos[i].z = spheres[j].z + dz * spheres[j].r / distance; + } + } + HairPos[i - 1].rotY = phd_atan(HairPos[i].z - HairPos[i - 1].z, HairPos[i].x - HairPos[i - 1].x); + HairPos[i - 1].rotX = -phd_atan(phd_sqrt(SQR(HairPos[i].z - HairPos[i - 1].z) + SQR(HairPos[i].x - HairPos[i - 1].x)), HairPos[i].y - HairPos[i - 1].y); + phd_PushUnitMatrix(); + PhdMatrixPtr->_03 = HairPos[i - 1].x << W2V_SHIFT; + PhdMatrixPtr->_13 = HairPos[i - 1].y << W2V_SHIFT; + PhdMatrixPtr->_23 = HairPos[i - 1].z << W2V_SHIFT; + phd_RotYXZ(HairPos[i - 1].rotY, HairPos[i - 1].rotX, 0); + if (i == 6) { + phd_TranslateRel(bone[17], bone[18], bone[19]); + } else { + phd_TranslateRel(bone[4 * i - 3], bone[4 * i - 2], bone[4 * i - 1]); + } + HairPos[i].x = PhdMatrixPtr->_03 >> W2V_SHIFT; + HairPos[i].y = PhdMatrixPtr->_13 >> W2V_SHIFT; + HairPos[i].z = PhdMatrixPtr->_23 >> W2V_SHIFT; + phd_PopMatrix(); + HairVelocity[i].x = HairPos[i].x - HairVelocity[0].x; + HairVelocity[i].y = HairPos[i].y - HairVelocity[0].y; + HairVelocity[i].z = HairPos[i].z - HairVelocity[0].z; + } + } +} + +void __cdecl DrawHair() { + int i; + __int16 **mesh; + + mesh = &MeshPtr[Objects[ID_LARA_HAIR].meshIndex]; + for (i = 0; i < 6; ++i) { + phd_PushMatrix(); + phd_TranslateAbs(HairPos[i].x, HairPos[i].y, HairPos[i].z); + phd_RotY(HairPos[i].rotY); + phd_RotX(HairPos[i].rotX); + phd_PutPolygons(mesh[i], 1); + phd_PopMatrix(); + } +} /* * Inject function */ void Inject_Hair() { -// INJECT(0x00420E80, InitialiseHair); -// INJECT(0x00420F00, HairControl); -// INJECT(0x00421900, DrawHair); + INJECT(0x00420E80, InitialiseHair); + INJECT(0x00420F00, HairControl); + INJECT(0x00421900, DrawHair); } diff --git a/game/hair.h b/game/hair.h index 186af52..5cc2baa 100644 --- a/game/hair.h +++ b/game/hair.h @@ -27,8 +27,9 @@ /* * Function list */ -#define InitialiseHair ((void(__cdecl*)(void)) 0x00420E80) -#define HairControl ((void(__cdecl*)(int)) 0x00420F00) -#define DrawHair ((void(__cdecl*)(void)) 0x00421900) + +void __cdecl InitialiseHair(); // 0x00420E80 +void __cdecl HairControl(BOOL isCutscene); // 0x00420F00 +void __cdecl DrawHair(); // 0x00421900 #endif // HAIR_H_INCLUDED diff --git a/game/lara1gun.cpp b/game/lara1gun.cpp index a6737a4..4ce4eb1 100644 --- a/game/lara1gun.cpp +++ b/game/lara1gun.cpp @@ -291,6 +291,130 @@ void __cdecl ControlRocket(__int16 itemID) { } } +void __cdecl AnimateShotgun(int gunType) { + ITEM_INFO *item; + BOOL change; + static BOOL IsFireM16 = FALSE; + static BOOL IsFireHarpoon = FALSE; + + item = &Items[Lara.weapon_item]; + if (gunType == LGT_M16 && LaraItem->speed) { + change = TRUE; + } else { + change = FALSE; + } + switch (item->currentAnimState) { + case 0: + IsFireM16 = FALSE; + if (IsFireHarpoon) { + item->goalAnimState = 5; + IsFireHarpoon = FALSE; + } else { + if (Lara.water_status != LWS_Underwater && !change) { + if ((CHK_ANY(InputStatus, IN_ACTION) && !Lara.target) || Lara.left_arm.lock) { + item->goalAnimState = 2; + } else { + item->goalAnimState = 4; + } + } else { + item->goalAnimState = 6; + } + } + break; + case 2: + if (item->frameNumber == Anims[item->animNumber].frameBase) { + item->goalAnimState = 4; + if (Lara.water_status != LWS_Underwater && !change && !IsFireHarpoon) { + if (CHK_ANY(InputStatus, IN_ACTION)) { + if (!Lara.target || Lara.left_arm.lock) { + if (gunType == LGT_Harpoon) { + FireHarpoon(); + if (!CHK_ANY(Lara.harpoon_ammo, 3)) + IsFireHarpoon = TRUE; + } else { + if (gunType == LGT_Grenade) { + FireRocket(); + } else { + if (gunType == LGT_M16) { + FireM16(FALSE); + PlaySoundEffect(78, &LaraItem->pos, 0); + IsFireM16 = TRUE; + } else { + FireShotgun(); + } + } + } + item->goalAnimState = 2; + } + } else { + if (Lara.left_arm.lock) + item->goalAnimState = 0; + } + } + if (item->goalAnimState != 2 && IsFireM16) { + PlaySoundEffect(104, &LaraItem->pos, 0); + IsFireM16 = FALSE; + } + } else { + if (IsFireM16) { + PlaySoundEffect(78, &LaraItem->pos, 0); + } else { + if (gunType == LGT_Shotgun && !CHK_ANY(InputStatus, IN_ACTION) && !Lara.left_arm.lock) + item->goalAnimState = 4; + } + } + break; + case 6: + IsFireM16 = FALSE; + if (IsFireHarpoon) { + item->goalAnimState = 5; + IsFireHarpoon = FALSE; + } else { + if (Lara.water_status != LWS_Underwater && !change) { + item->goalAnimState = 0; + } else { + if ((CHK_ANY(InputStatus, IN_ACTION) && !Lara.target) || Lara.left_arm.lock) { + item->goalAnimState = 8; + } else { + item->goalAnimState = 7; + } + } + } + break; + case 8: + if (item->frameNumber == Anims[item->animNumber].frameBase) { + item->goalAnimState = 7; + if ((Lara.water_status == LWS_Underwater || change) && !IsFireHarpoon) { + if (CHK_ANY(InputStatus, IN_ACTION)) { + if (!Lara.target || Lara.left_arm.lock) { + if (gunType == LGT_Harpoon) { + FireHarpoon(); + if (!CHK_ANY(Lara.harpoon_ammo, 3)) + IsFireHarpoon = TRUE; + } else { + FireM16(TRUE); + } + item->goalAnimState = 8; + } + } else { + if (Lara.left_arm.lock) + item->goalAnimState = 6; + } + } + } + if (gunType == LGT_M16 && item->goalAnimState == 8) + PlaySoundEffect(78, &LaraItem->pos, 0); + break; + } + AnimateItem(item); + Lara.right_arm.frame_base = Anims[item->animNumber].framePtr; + Lara.left_arm.frame_base = Lara.right_arm.frame_base; + Lara.right_arm.frame_number = item->frameNumber - Anims[item->animNumber].frameBase; + Lara.left_arm.frame_number = Lara.right_arm.frame_number; + Lara.right_arm.anim_number = item->animNumber; + Lara.left_arm.anim_number = Lara.right_arm.anim_number; +} + /* * Inject function */ @@ -311,5 +435,6 @@ void Inject_Lara1Gun() { // INJECT(0x0042C9D0, draw_shotgun); // INJECT(0x0042CB40, undraw_shotgun); -// INJECT(0x0042CC50, AnimateShotgun); + + INJECT(0x0042CC50, AnimateShotgun); } diff --git a/game/lara1gun.h b/game/lara1gun.h index dc6508b..9cc73aa 100644 --- a/game/lara1gun.h +++ b/game/lara1gun.h @@ -41,9 +41,9 @@ void __cdecl FireHarpoon(); // 0x0042BFF0 void __cdecl FireRocket(); // 0x0042C4D0 void __cdecl ControlRocket(__int16 itemID); // 0x0042C5C0 -// 0x0042C9D0: draw_shotgun -// 0x0042CB40: undraw_shotgun +#define draw_shotgun ((void(__cdecl*)(int)) 0x0042C9D0) +#define undraw_shotgun ((void(__cdecl*)(int)) 0x0042CB40) -#define AnimateShotgun ((void(__cdecl*)(int)) 0x0042CC50) +void __cdecl AnimateShotgun(int gunType); // 0x0042CC50 #endif // LARA1GUN_H_INCLUDED diff --git a/game/lara2gun.cpp b/game/lara2gun.cpp index 679313e..d9f9a2c 100644 --- a/game/lara2gun.cpp +++ b/game/lara2gun.cpp @@ -24,12 +24,34 @@ #include "3dsystem/phd_math.h" #include "game/draw.h" #include "game/larafire.h" +#include "game/sound.h" #include "global/vars.h" #ifdef FEATURE_INPUT_IMPROVED #include "modding/joy_output.h" #endif // FEATURE_INPUT_IMPROVED +void __cdecl set_pistol_arm(LARA_ARM *arm, int frame) { + __int16 anim; + + if (frame < 5) { + anim = Objects[ID_LARA_PISTOLS].animIndex; + } else { + if (frame < 13) { + anim = Objects[ID_LARA_PISTOLS].animIndex + 1; + } else { + if (frame < 24) { + anim = Objects[ID_LARA_PISTOLS].animIndex + 2; + } else { + anim = Objects[ID_LARA_PISTOLS].animIndex + 3; + } + } + } + arm->anim_number = anim; + arm->frame_number = frame; + arm->frame_base = Anims[anim].framePtr; +} + void __cdecl PistolHandler(int weaponType) { WEAPON_INFO *weapon = &Weapons[weaponType]; @@ -76,11 +98,119 @@ void __cdecl PistolHandler(int weaponType) { } } +void __cdecl AnimatePistols(int gunType) { + BOOL right; + __int16 frame, angles[2]; + WEAPON_INFO *weapon; + static BOOL IsLeftUzi = FALSE; + static BOOL IsRightUzi = FALSE; + + right = FALSE; + frame = Lara.right_arm.frame_number; + weapon = &Weapons[gunType]; + if (!Lara.right_arm.lock && (!CHK_ANY(InputStatus, IN_ACTION) || Lara.target)) { + if (frame >= 24) { + frame = 4; + } else { + if (frame > 0 && frame <= 4) + --frame; + } + if (IsRightUzi) { + PlaySoundEffect(weapon->sampleNum + 1, &LaraItem->pos, 0); + IsRightUzi = FALSE; + } + } else { + if (frame >= 0 && frame < 4) { + ++frame; + } else { + if (frame == 4) { + if (CHK_ANY(InputStatus, IN_ACTION)) { + angles[0] = LaraItem->pos.rotY + Lara.right_arm.y_rot; + angles[1] = Lara.right_arm.x_rot; + if (FireWeapon(gunType, Lara.target, LaraItem, angles)) { + Lara.right_arm.flash_gun = weapon->flashTime; + PlaySoundEffect(weapon->sampleNum, &LaraItem->pos, 0); + right = TRUE; + if (gunType == LGT_Uzis) + IsRightUzi = TRUE; + } + frame = 24; + } else { + if (IsRightUzi) { + PlaySoundEffect(weapon->sampleNum + 1, &LaraItem->pos, 0); + IsRightUzi = FALSE; + } + } + } else { + if (frame >= 24) { + if (gunType == LGT_Uzis) { + PlaySoundEffect(weapon->sampleNum, &LaraItem->pos, 0); + IsRightUzi = TRUE; + } + ++frame; + if (frame == weapon->recoilFrame + 24) + frame = 4; + } + } + } + } + set_pistol_arm(&Lara.right_arm, frame); + frame = Lara.left_arm.frame_number; + if (!Lara.left_arm.lock && (!CHK_ANY(InputStatus, IN_ACTION) || Lara.target)) { + if (frame >= 24) { + frame = 4; + } else { + if (frame > 0 && frame <= 4) + --frame; + } + if (IsLeftUzi) { + PlaySoundEffect(weapon->sampleNum + 1, &LaraItem->pos, 0); + IsLeftUzi = FALSE; + } + } else { + if (frame >= 0 && frame < 4) { + ++frame; + } else { + if (frame == 4) { + if (CHK_ANY(InputStatus, IN_ACTION)) { + angles[0] = LaraItem->pos.rotY + Lara.left_arm.y_rot; + angles[1] = Lara.left_arm.x_rot; + if (FireWeapon(gunType, Lara.target, LaraItem, angles)) { + Lara.left_arm.flash_gun = weapon->flashTime; + if (!right) + PlaySoundEffect(weapon->sampleNum, &LaraItem->pos, 0); + if (gunType == LGT_Uzis) + IsLeftUzi = TRUE; + } + frame = 24; + } else { + if (IsLeftUzi) { + PlaySoundEffect(weapon->sampleNum + 1, &LaraItem->pos, 0); + IsLeftUzi = FALSE; + } + } + } else { + if (frame >= 24) { + if (gunType == LGT_Uzis) { + PlaySoundEffect(weapon->sampleNum, &LaraItem->pos, 0); + IsLeftUzi = TRUE; + } + ++frame; + if (frame == weapon->recoilFrame + 24) + frame = 4; + } + } + } + } + set_pistol_arm(&Lara.left_arm, frame); +} + /* * Inject function */ void Inject_Lara2Gun() { -// INJECT(0x0042D000, set_pistol_arm); + INJECT(0x0042D000, set_pistol_arm); + // INJECT(0x0042D050, draw_pistols); // INJECT(0x0042D0D0, undraw_pistols); // INJECT(0x0042D300, ready_pistols); @@ -89,6 +219,5 @@ void Inject_Lara2Gun() { // INJECT(0x0042D3F0, undraw_pistol_mesh_right); INJECT(0x0042D430, PistolHandler); - -// INJECT(0x0042D5C0, AnimatePistols); + INJECT(0x0042D5C0, AnimatePistols); } diff --git a/game/lara2gun.h b/game/lara2gun.h index 57824f9..f786943 100644 --- a/game/lara2gun.h +++ b/game/lara2gun.h @@ -27,16 +27,17 @@ /* * Function list */ -// 0x0042D000: set_pistol_arm -// 0x0042D050: draw_pistols -// 0x0042D0D0: undraw_pistols +void __cdecl set_pistol_arm(LARA_ARM *arm, int frame); // 0x0042D000 + +#define draw_pistols ((void(__cdecl*)(int)) 0x0042D050) +#define undraw_pistols ((void(__cdecl*)(int)) 0x0042D0D0) + // 0x0042D300: ready_pistols // 0x0042D360: draw_pistol_meshes // 0x0042D3B0: undraw_pistol_mesh_left // 0x0042D3F0: undraw_pistol_mesh_right void __cdecl PistolHandler(int weaponType); // 0x0042D430 - -#define AnimatePistols ((void(__cdecl*)(int)) 0x0042D5C0) +void __cdecl AnimatePistols(int gunType); // 0x0042D5C0 #endif // LARA2GUN_H_INCLUDED diff --git a/game/larafire.cpp b/game/larafire.cpp index 94d5fda..72ef2ff 100644 --- a/game/larafire.cpp +++ b/game/larafire.cpp @@ -21,23 +21,345 @@ #include "global/precompiled.h" #include "game/larafire.h" +#include "3dsystem/3d_gen.h" +#include "game/control.h" +#include "game/effects.h" +#include "game/invfunc.h" +#include "game/items.h" +#include "game/lara1gun.h" +#include "game/lara2gun.h" +#include "game/laraflare.h" +#include "game/objects.h" +#include "game/sound.h" +#include "game/sphere.h" +#include "specific/game.h" #include "global/vars.h" +void __cdecl LaraGun() { + DWORD *ammo; + if (Lara.left_arm.flash_gun > 0) + --Lara.left_arm.flash_gun; + if (Lara.right_arm.flash_gun > 0) + --Lara.right_arm.flash_gun; + if (LaraItem->hitPoints <= 0) { + Lara.gun_status = LGS_Armless; + } else { + if (Lara.gun_status == LGS_Armless) { + if (CHK_ANY(InputStatus, IN_DRAW)) { + Lara.request_gun_type = Lara.last_gun_type; + } else { + if (CHK_ANY(InputStatus, IN_FLARE)) { + if (Lara.gun_type == LGT_Flare) { + Lara.gun_status = LGS_Undraw; + } else { + if (Inv_RequestItem(ID_FLARES_ITEM)) + Lara.request_gun_type = LGT_Flare; + } + } + } + if (Lara.request_gun_type != Lara.gun_type || CHK_ANY(InputStatus, IN_DRAW)) { + if (Lara.request_gun_type != LGT_Flare && + (Lara.skidoo != -1 || + (Lara.request_gun_type != LGT_Harpoon && + Lara.water_status != LWS_AboveWater && + (Lara.water_status != LWS_Wade || + Lara.water_surface_dist <= -Weapons[Lara.gun_type].gunHeight)))) + { + Lara.last_gun_type = Lara.request_gun_type; + if (Lara.gun_type == LGT_Flare) { + Lara.request_gun_type = LGT_Flare; + } else { + Lara.gun_type = Lara.request_gun_type; + } + } else { + if (Lara.gun_type == LGT_Flare) { + CreateFlare(FALSE); + undraw_flare_meshes(); + Lara.flare_control_left = 0; + } + Lara.gun_type = Lara.request_gun_type; + InitialiseNewWeapon(); + Lara.gun_status = LGS_Draw; + Lara.right_arm.frame_number = 0; + Lara.left_arm.frame_number = 0; + } + } + } else { + if (Lara.gun_status == LGS_Ready) { + if (CHK_ANY(InputStatus, IN_FLARE) && Inv_RequestItem(ID_FLARES_ITEM)) + Lara.request_gun_type = LGT_Flare; + if (CHK_ANY(InputStatus, IN_DRAW) || + Lara.request_gun_type != Lara.gun_type || + (Lara.gun_type != LGT_Harpoon && + Lara.water_status != LWS_AboveWater && + (Lara.water_status != LWS_Wade || + Lara.water_surface_dist < -Weapons[Lara.gun_type].gunHeight))) + { + Lara.gun_status = LGS_Undraw; + } + } + } + } + switch (Lara.gun_status) { + case LGS_Armless: + if (Lara.gun_type == LGT_Flare) { + if (Lara.skidoo == -1 && !CheckForHoldingState(LaraItem->currentAnimState)) { + Lara.flare_control_left = 0; + } else { + if (!Lara.flare_control_left) { + Lara.flare_control_left = 1; + Lara.left_arm.frame_number = 95; + } else { + if (Lara.left_arm.frame_number) { + ++Lara.left_arm.frame_number; + if (Lara.left_arm.frame_number == 110) + Lara.left_arm.frame_number = 0; + } + } + } + DoFlareInHand(Lara.flare_age); + set_flare_arm(Lara.left_arm.frame_number); + } + break; + case LGS_HandBusy: + if (Lara.gun_type == LGT_Flare) { + Lara.flare_control_left = Lara.skidoo != -1 || CheckForHoldingState(LaraItem->currentAnimState); + DoFlareInHand(Lara.flare_age); + set_flare_arm(Lara.left_arm.frame_number); + } + break; + case LGS_Draw: + if (Lara.gun_type != LGT_Flare && Lara.gun_type != LGT_Unarmed) + Lara.last_gun_type = Lara.gun_type; + switch (Lara.gun_type) { + case LGT_Pistols: + case LGT_Magnums: + case LGT_Uzis: + if (Camera.type != CAM_Cinematic && Camera.type != CAM_Look) + Camera.type = CAM_Combat; + draw_pistols(Lara.gun_type); + break; + case LGT_Shotgun: + case LGT_M16: + case LGT_Grenade: + case LGT_Harpoon: + if (Camera.type != CAM_Cinematic && Camera.type != CAM_Look) + Camera.type = CAM_Combat; + draw_shotgun(Lara.gun_type); + break; + case LGT_Flare: + draw_flare(); + break; + default: + Lara.gun_status = LGS_Armless; + break; + } + break; + case LGS_Undraw: + Lara.mesh_ptrs[14] = MeshPtr[Objects[ID_LARA].meshIndex + 14]; + switch (Lara.gun_type) { + case LGT_Pistols: + case LGT_Magnums: + case LGT_Uzis: + undraw_pistols(Lara.gun_type); + break; + case LGT_Shotgun: + case LGT_M16: + case LGT_Grenade: + case LGT_Harpoon: + undraw_shotgun(Lara.gun_type); + break; + case LGT_Flare: + undraw_flare(); + break; + } + break; + case LGS_Ready: + if (!Lara.pistol_ammo || !CHK_ANY(InputStatus, IN_ACTION)) { + Lara.mesh_ptrs[14] = MeshPtr[Objects[ID_LARA].meshIndex + 14]; + } else { + Lara.mesh_ptrs[14] = MeshPtr[Objects[ID_LARA_UZIS].meshIndex + 14]; + } + if (Camera.type != CAM_Cinematic && Camera.type != CAM_Look) + Camera.type = CAM_Combat; + switch (Lara.gun_type) { + case LGT_Magnums: + ammo = &Lara.magnum_ammo; + break; + case LGT_Uzis: + ammo = &Lara.uzi_ammo; + break; + case LGT_Shotgun: + ammo = &Lara.shotgun_ammo; + break; + case LGT_M16: + ammo = &Lara.m16_ammo; + break; + case LGT_Grenade: + ammo = &Lara.grenade_ammo; + break; + case LGT_Harpoon: + ammo = &Lara.harpoon_ammo; + break; + default: + ammo = &Lara.pistol_ammo; + break; + } + if (CHK_ANY(InputStatus, IN_ACTION) && *ammo <= 0) { + *ammo = 0; + PlaySoundEffect(48, &LaraItem->pos, 0); + Lara.request_gun_type = Inv_RequestItem(ID_PISTOL_ITEM) ? LGT_Pistols : LGT_Unarmed; + } else { + switch (Lara.gun_type) { + case LGT_Pistols: + case LGT_Magnums: + case LGT_Uzis: + PistolHandler(Lara.gun_type); + break; + case LGT_Shotgun: + case LGT_M16: + case LGT_Grenade: + case LGT_Harpoon: + RifleHandler(Lara.gun_type); + break; + } + } + break; + case LGS_Special: + draw_flare(); + break; + } +} + +int __cdecl FireWeapon(int weaponType, ITEM_INFO *target, ITEM_INFO *item, __int16 *angles) { + DWORD *ammo; + WEAPON_INFO *weapon; + PHD_3DPOS pos; + SPHERE_INFO spheres[33]; + int count, best, distance, i, hit; + GAME_VECTOR source, destination; + __int16 itemID; + BOOL ricochet; + + switch (weaponType) { + case LGT_Magnums: + ammo = &Lara.magnum_ammo; + if (SaveGame.bonusFlag) + *ammo = 1000; + break; + case LGT_Uzis: + ammo = &Lara.uzi_ammo; + if (SaveGame.bonusFlag) + *ammo = 1000; + break; + case LGT_Shotgun: + ammo = &Lara.shotgun_ammo; + if (SaveGame.bonusFlag) + *ammo = 1000; + break; + case LGT_M16: + ammo = &Lara.m16_ammo; + if (SaveGame.bonusFlag) + *ammo = 1000; + break; + default: + ammo = &Lara.pistol_ammo; + *ammo = 1000; + break; + } + if (*ammo > 0) { + --*ammo; + weapon = &Weapons[weaponType]; + pos.x = item->pos.x; + pos.y = item->pos.y - weapon->gunHeight; + pos.z = item->pos.z; + pos.rotX = angles[1] + (GetRandomControl() - 16384) * weapon->shotAccuracy / 65536; + pos.rotZ = 0; + pos.rotY = angles[0] + (GetRandomControl() - 16384) * weapon->shotAccuracy / 65536; + phd_GenerateW2V(&pos); + count = GetSpheres(target, spheres, FALSE); + best = -1; + distance = 2147483647; + for (i = 0; i < count; ++i) { + if (ABS(spheres[i].x) < spheres[i].r && + ABS(spheres[i].y) < spheres[i].r && + spheres[i].z > spheres[i].r && + SQR(spheres[i].x) + SQR(spheres[i].y) <= SQR(spheres[i].r) && + spheres[i].z - spheres[i].r < distance) + { + distance = spheres[i].z - spheres[i].r; + best = i; + } + } + ++SaveGame.statistics.shots; + source.x = pos.x; + source.y = pos.y; + source.z = pos.z; + source.roomNumber = item->roomNumber; + if (best >= 0) { + ++SaveGame.statistics.hits; + destination.x = pos.x + (PhdMatrixPtr->_20 * distance >> W2V_SHIFT); + destination.y = pos.y + (PhdMatrixPtr->_21 * distance >> W2V_SHIFT); + destination.z = pos.z + (PhdMatrixPtr->_22 * distance >> W2V_SHIFT); + itemID = ObjectOnLOS(&source, &destination); + if (itemID != -1) + SmashItem(itemID, weaponType); + HitTarget(target, &destination, weapon->damage); + hit = 1; + } else { + destination.x = pos.x + (PhdMatrixPtr->_20 * weapon->targetDist >> W2V_SHIFT); + destination.y = pos.y + (PhdMatrixPtr->_21 * weapon->targetDist >> W2V_SHIFT); + destination.z = pos.z + (PhdMatrixPtr->_22 * weapon->targetDist >> W2V_SHIFT); + ricochet = !LOS(&source, &destination); + itemID = ObjectOnLOS(&source, &destination); + if (itemID != -1) { + SmashItem(itemID, weaponType); + } else { + if (ricochet) + Richochet(&destination); + } + hit = -1; + } + } else { + *ammo = 0; + hit = 0; + } + return hit; +} + +void __cdecl SmashItem(__int16 itemID, int weaponType) { + ITEM_INFO *item; + + item = &Items[itemID]; + if (item->objectID == ID_WINDOW1) { + SmashWindow(itemID); + } else { + if (item->objectID == ID_BELL && item->status != ITEM_ACTIVE) { + item->status = ITEM_ACTIVE; + AddActiveItem(itemID); + } + } +} /* * Inject function */ void Inject_LaraFire() { -// INJECT(0x0042E740, LaraGun); + INJECT(0x0042E740, LaraGun); + // INJECT(0x0042ECB0, CheckForHoldingState); // INJECT(0x0042ECF0, InitialiseNewWeapon); // INJECT(0x0042EE30, LaraTargetInfo); // INJECT(0x0042EFD0, LaraGetNewTarget); // INJECT(0x0042F1F0, find_target_point); // INJECT(0x0042F2A0, AimWeapon); -// INJECT(0x0042F370, FireWeapon); + + INJECT(0x0042F370, FireWeapon); + // INJECT(0x0042F6E0, HitTarget); -// INJECT(0x0042F780, SmashItem); + + INJECT(0x0042F780, SmashItem); + // INJECT(0x0042F7E0, WeaponObject); } \ No newline at end of file diff --git a/game/larafire.h b/game/larafire.h index 26ca35d..b2f025b 100644 --- a/game/larafire.h +++ b/game/larafire.h @@ -27,16 +27,21 @@ /* * Function list */ -#define LaraGun ((void(__cdecl*)(void)) 0x0042E740) +void __cdecl LaraGun(); // 0x0042E740 + #define CheckForHoldingState ((int(__cdecl*)(int)) 0x0042ECB0) #define InitialiseNewWeapon ((void(__cdecl*)(void)) 0x0042ECF0) #define LaraTargetInfo ((void(__cdecl*)(WEAPON_INFO*)) 0x0042EE30) #define LaraGetNewTarget ((void(__cdecl*)(WEAPON_INFO*)) 0x0042EFD0) #define find_target_point ((void(__cdecl*)(ITEM_INFO*,GAME_VECTOR*)) 0x0042F1F0) #define AimWeapon ((void(__cdecl*)(WEAPON_INFO*,LARA_ARM*)) 0x0042F2A0) -#define FireWeapon ((int(__cdecl*)(int,ITEM_INFO*,ITEM_INFO*,__int16*)) 0x0042F370) + +int __cdecl FireWeapon(int weaponType, ITEM_INFO *target, ITEM_INFO *item, __int16 *angles); // 0x0042F370 + #define HitTarget ((void(__cdecl*)(ITEM_INFO*,GAME_VECTOR*,int)) 0x0042F6E0) -#define SmashItem ((void(__cdecl*)(__int16,int)) 0x0042F780) + +void __cdecl SmashItem(__int16 itemID, int weaponType); // 0x0042F780 + #define WeaponObject ((int(__cdecl*)(int)) 0x0042F7E0) #endif // LARA_FIRE_H_INCLUDED diff --git a/game/laraflare.cpp b/game/laraflare.cpp index c9adf77..6fa6477 100644 --- a/game/laraflare.cpp +++ b/game/laraflare.cpp @@ -22,8 +22,16 @@ #include "global/precompiled.h" #include "game/laraflare.h" #include "3dsystem/3d_gen.h" +#include "3dsystem/phd_math.h" #include "3dsystem/scalespr.h" +#include "game/control.h" #include "game/draw.h" +#include "game/effects.h" +#include "game/invfunc.h" +#include "game/items.h" +#include "game/lara.h" +#include "game/larafire.h" +#include "game/sound.h" #include "specific/game.h" #include "specific/output.h" #include "global/vars.h" @@ -32,6 +40,57 @@ extern DWORD AlphaBlendMode; #endif // FEATURE_VIDEOFX_IMPROVED +int __cdecl DoFlareLight(PHD_VECTOR *pos, int flareAge) { + BOOL light; + int random, x; + + light = TRUE; + if (flareAge < 1800) { + random = GetRandomDraw(); + x = pos->x + (random & 15); + if (flareAge < 30) { + AddDynamicLight(x, pos->y, pos->z, (flareAge - 30) / 5 + 12, 11); + } else { + if (flareAge < 1740) { + AddDynamicLight(x, pos->y, pos->z, 12, 11); + } else { + if (random > 8192) { + AddDynamicLight(x, pos->y, pos->z, 12 - (random & 3), 11); + } else { + AddDynamicLight(x, pos->y, pos->z, 12, 5); + light = FALSE; + } + } + } + } else { + light = FALSE; + } + return light; +} + +void __cdecl DoFlareInHand(int flareAge) { + PHD_VECTOR pos; + + pos.x = 11; + pos.y = 32; + pos.z = 41; + GetLaraJointAbsPosition(&pos, 13); + Lara.left_arm.flash_gun = DoFlareLight(&pos, flareAge); + if (Lara.flare_age < 1800) { + ++Lara.flare_age; + if (CHK_ANY(RoomInfo[LaraItem->roomNumber].flags, ROOM_UNDERWATER)) { + PlaySoundEffect(12, &LaraItem->pos, SFX_UNDERWATER); + if (GetRandomDraw() < 16384) + CreateBubble((PHD_3DPOS *) &pos, LaraItem->roomNumber); + } else { + PlaySoundEffect(12, &LaraItem->pos, 0); + } + } else { + if (Lara.gun_status == LGS_Armless) + Lara.gun_status = LGS_Undraw; + } +} + void __cdecl DrawFlareInAir(ITEM_INFO *item) { int rate; __int16 *ptr[2]; @@ -62,21 +121,301 @@ void __cdecl DrawFlareInAir(ITEM_INFO *item) { phd_PopMatrix(); } +void __cdecl CreateFlare(BOOL isFlying) { + __int16 itemID; + ITEM_INFO *item; + PHD_VECTOR pos; + + itemID = CreateItem(); + if (itemID != -1) { + item = &Items[itemID]; + item->objectID = ID_FLARE_ITEM; + item->roomNumber = LaraItem->roomNumber; + pos.x = -16; + pos.y = 32; + pos.z = 42; + GetLaraJointAbsPosition(&pos, 13); + if (GetHeight(GetFloor(pos.x, pos.y, pos.z, &item->roomNumber), pos.x, pos.y, pos.z) < pos.y) { + item->pos.x = LaraItem->pos.x; + item->pos.y = pos.y; + item->pos.z = LaraItem->pos.z; + item->pos.rotY = -LaraItem->pos.rotY; + item->roomNumber = LaraItem->roomNumber; + } else { + item->pos.x = pos.x; + item->pos.y = pos.y; + item->pos.z = pos.z; + item->pos.rotY = isFlying ? LaraItem->pos.rotY : LaraItem->pos.rotY - PHD_45; + } + InitialiseItem(itemID); + item->pos.rotZ = 0; + item->pos.rotX = 0; + item->shade1 = -1; + if (isFlying) { + item->speed = LaraItem->speed + 50; + item->fallSpeed = LaraItem->fallSpeed - 50; + } else { + item->speed = LaraItem->speed + 10; + item->fallSpeed = LaraItem->fallSpeed + 50; + } + if (DoFlareLight((PHD_VECTOR *) &item->pos, Lara.flare_age)) { + item->data = (LPVOID) (Lara.flare_age | 0x8000); + } else { + item->data = (LPVOID) (Lara.flare_age & 0x7FFF); + } + AddActiveItem(itemID); + item->status = ITEM_ACTIVE; + } +} + +void __cdecl set_flare_arm(int frame) { + if (frame < 1) { + Lara.left_arm.anim_number = Objects[ID_LARA_FLARE].animIndex; + } else { + if (frame < 33) { + Lara.left_arm.anim_number = Objects[ID_LARA_FLARE].animIndex + 1; + } else { + if (frame < 72) { + Lara.left_arm.anim_number = Objects[ID_LARA_FLARE].animIndex + 2; + } else { + if (frame < 95) { + Lara.left_arm.anim_number = Objects[ID_LARA_FLARE].animIndex + 3; + } else { + Lara.left_arm.anim_number = Objects[ID_LARA_FLARE].animIndex + 4; + } + } + } + } + Lara.left_arm.frame_base = Anims[Lara.left_arm.anim_number].framePtr; +} + +void __cdecl draw_flare() { + __int16 frame; + + if (LaraItem->currentAnimState != AS_FLAREPICKUP && LaraItem->currentAnimState != AS_PICKUP) { + Lara.flare_control_left = 1; + frame = Lara.left_arm.frame_number + 1; + if (frame >= 33 && frame <= 94) { + if (frame == 46) { + draw_flare_meshes(); + if (!SaveGame.bonusFlag) + Inv_RemoveItem(ID_FLARES_ITEM); + } else { + if (frame >= 72 && frame <= 93) { + if (frame == 72) { + PlaySoundEffect(11, &LaraItem->pos, CHK_ANY(RoomInfo[LaraItem->roomNumber].flags, ROOM_UNDERWATER) ? SFX_UNDERWATER : 0); + Lara.flare_age = 0; + } + DoFlareInHand(Lara.flare_age); + } else { + if (frame == 94) { + ready_flare(); + DoFlareInHand(Lara.flare_age); + frame = 0; + } + } + } + } else { + frame = 33; + } + } else { + DoFlareInHand(Lara.flare_age); + Lara.flare_control_left = 0; + frame = 93; + } + Lara.left_arm.frame_number = frame; + set_flare_arm(Lara.left_arm.frame_number); +} + +void __cdecl undraw_flare() { + __int16 frame; + + Lara.flare_control_left = 1; + frame = Lara.left_arm.frame_number; + if (LaraItem->goalAnimState == AS_STOP && Lara.skidoo == -1) { + if (LaraItem->animNumber == 103) { + LaraItem->animNumber = 189; + Lara.flare_frame = frame + Anims[LaraItem->animNumber].frameBase; + LaraItem->frameNumber = Lara.flare_frame; + } + if (LaraItem->animNumber == 189) { + Lara.flare_control_left = 0; + if (Lara.flare_frame >= Anims[189].frameBase + 31) { + Lara.request_gun_type = Lara.last_gun_type; + Lara.gun_type = Lara.last_gun_type; + Lara.gun_status = LGS_Armless; + InitialiseNewWeapon(); + Lara.target = NULL; + Lara.right_arm.lock = 0; + Lara.left_arm.lock = 0; + LaraItem->animNumber = 11; + Lara.flare_frame = Anims[LaraItem->animNumber].frameBase; + LaraItem->frameNumber = Lara.flare_frame; + LaraItem->currentAnimState = AS_STOP; + LaraItem->goalAnimState = AS_STOP; + return; + } + ++Lara.flare_frame; + } + } else { + if (LaraItem->currentAnimState == AS_STOP && Lara.skidoo == -1) { + LaraItem->animNumber = 11; + LaraItem->frameNumber = Anims[LaraItem->animNumber].frameBase; + } + } + if (frame) { + if (frame >= 72 && frame < 95) { + ++frame; + if (frame == 94) + frame = 1; + } else { + if (frame >= 1 && frame < 33) { + ++frame; + if (frame == 21) { + CreateFlare(TRUE); + undraw_flare_meshes(); + } else { + if (frame == 33) { + frame = 0; + Lara.request_gun_type = Lara.last_gun_type; + Lara.gun_type = Lara.last_gun_type; + Lara.gun_status = LGS_Armless; + InitialiseNewWeapon(); + Lara.flare_control_left = 0; + Lara.target = NULL; + Lara.right_arm.lock = 0; + Lara.left_arm.lock = 0; + Lara.flare_frame = 0; + } + } + } else { + if (frame >= 95 && frame < 110) { + ++frame; + if (frame == 110) + frame = 1; + } + } + } + } else { + frame = 1; + } + if (frame >= 1 && frame < 21) + DoFlareInHand(Lara.flare_age); + Lara.left_arm.frame_number = frame; + set_flare_arm(Lara.left_arm.frame_number); +} + +void __cdecl draw_flare_meshes() { + Lara.mesh_ptrs[13] = MeshPtr[Objects[ID_LARA_FLARE].meshIndex + 13]; +} + +void __cdecl undraw_flare_meshes() { + Lara.mesh_ptrs[13] = MeshPtr[Objects[ID_LARA].meshIndex + 13]; +} + +void __cdecl ready_flare() { + Lara.gun_status = LGS_Armless; + Lara.left_arm.z_rot = 0; + Lara.left_arm.y_rot = 0; + Lara.left_arm.x_rot = 0; + Lara.right_arm.z_rot = 0; + Lara.right_arm.y_rot = 0; + Lara.right_arm.x_rot = 0; + Lara.right_arm.lock = 0; + Lara.left_arm.lock = 0; + Lara.target = NULL; +} + +void __cdecl FlareControl(__int16 itemID) { + ITEM_INFO *item; + int x, y, z, height, ceiling, age; + __int16 roomID; + FLOOR_INFO *floor; + + item = &Items[itemID]; + if (item->fallSpeed) { + item->pos.rotX += 3 * PHD_DEGREE; + item->pos.rotZ += 5 * PHD_DEGREE; + } else { + item->pos.rotX = 0; + item->pos.rotZ = 0; + } + x = item->pos.x; + z = item->pos.z; + y = item->pos.y; + item->pos.z += phd_cos(item->pos.rotY) * item->speed >> W2V_SHIFT; + item->pos.x += phd_sin(item->pos.rotY) * item->speed >> W2V_SHIFT; + if (CHK_ANY(RoomInfo[item->roomNumber].flags, ROOM_UNDERWATER)) { + item->fallSpeed += (5 - item->fallSpeed) / 2; + item->speed += (5 - item->speed) / 2; + } else { + item->fallSpeed += 6; + } + item->pos.y += item->fallSpeed; + roomID = item->roomNumber; + floor = GetFloor(item->pos.x, item->pos.y, item->pos.z, &roomID); + height = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z); + if (item->pos.y >= height) { + if (y > height) { + item->pos.rotY += PHD_180; + item->pos.y = y; + item->speed /= 2; + item->pos.x = x; + item->pos.z = z; + roomID = item->roomNumber; + } else { + if (item->fallSpeed > 40) { + item->fallSpeed = 40 - item->fallSpeed; + CLAMPL(item->fallSpeed, -100); + } else { + item->speed -= 3; + item->fallSpeed = 0; + CLAMPL(item->speed, 0); + } + item->pos.y = height; + } + } else { + ceiling = GetCeiling(floor, item->pos.x, item->pos.y, item->pos.z); + if (item->pos.y < ceiling) { + item->fallSpeed = -item->fallSpeed; + item->pos.y = ceiling; + } + } + if (roomID != item->roomNumber) + ItemNewRoom(itemID, roomID); + age = (int) item->data & 0x7FFF; + if (age < 1800 || item->fallSpeed || item->speed) { + if (age < 1800) + ++age; + if (DoFlareLight((PHD_VECTOR *) &item->pos, age)) { + age |= 0x8000; + if (CHK_ANY(RoomInfo[item->roomNumber].flags, ROOM_UNDERWATER)) { + PlaySoundEffect(12, &item->pos, SFX_UNDERWATER); + if (GetRandomDraw() < 16384) + CreateBubble(&item->pos, item->roomNumber); + } else { + PlaySoundEffect(12, &item->pos, 0); + } + } + item->data = (LPVOID) age; + } else { + KillItem(itemID); + } +} + /* * Inject function */ void Inject_LaraFlare() { -// INJECT(0x0042F840, DoFlareLight); -// INJECT(0x0042F8E0, DoFlareInHand); - + INJECT(0x0042F840, DoFlareLight); + INJECT(0x0042F8E0, DoFlareInHand); INJECT(0x0042F9C0, DrawFlareInAir); - -// INJECT(0x0042FAC0, CreateFlare); -// INJECT(0x0042FCA0, set_flare_arm); -// INJECT(0x0042FCF0, draw_flare); -// INJECT(0x0042FE60, undraw_flare); -// INJECT(0x00430090, draw_flare_meshes); -// INJECT(0x004300B0, undraw_flare_meshes); -// INJECT(0x004300D0, ready_flare); -// INJECT(0x00430110, FlareControl); + INJECT(0x0042FAC0, CreateFlare); + INJECT(0x0042FCA0, set_flare_arm); + INJECT(0x0042FCF0, draw_flare); + INJECT(0x0042FE60, undraw_flare); + INJECT(0x00430090, draw_flare_meshes); + INJECT(0x004300B0, undraw_flare_meshes); + INJECT(0x004300D0, ready_flare); + INJECT(0x00430110, FlareControl); } diff --git a/game/laraflare.h b/game/laraflare.h index d3794f1..f28d266 100644 --- a/game/laraflare.h +++ b/game/laraflare.h @@ -27,18 +27,16 @@ /* * Function list */ -// 0x0042F840: DoFlareLight -// 0x0042F8E0: DoFlareInHand - +int __cdecl DoFlareLight(PHD_VECTOR *pos, int flareAge); // 0x0042F840 +void __cdecl DoFlareInHand(int flareAge); // 0x0042F8E0 void __cdecl DrawFlareInAir(ITEM_INFO *item); - -// 0x0042FAC0: CreateFlare -// 0x0042FCA0: set_flare_arm -// 0x0042FCF0: draw_flare -// 0x0042FE60: undraw_flare -// 0x00430090: draw_flare_meshes -// 0x004300B0: undraw_flare_meshes -// 0x004300D0: ready_flare -// 0x00430110: FlareControl +void __cdecl CreateFlare(BOOL isFlying); // 0x0042FAC0 +void __cdecl set_flare_arm(int frame); // 0x0042FCA0 +void __cdecl draw_flare(); // 0x0042FCF0 +void __cdecl undraw_flare(); // 0x0042FE60 +void __cdecl draw_flare_meshes(); // 0x00430090 +void __cdecl undraw_flare_meshes(); // 0x004300B0 +void __cdecl ready_flare(); // 0x004300D0 +void __cdecl FlareControl(__int16 itemID); // 0x00430110 #endif // LARA_FLARE_H_INCLUDED diff --git a/game/objects.cpp b/game/objects.cpp index e0aac0c..2371441 100644 --- a/game/objects.cpp +++ b/game/objects.cpp @@ -21,9 +21,205 @@ #include "global/precompiled.h" #include "game/objects.h" +#include "3dsystem/phd_math.h" +#include "game/control.h" +#include "game/effects.h" +#include "game/items.h" +#include "game/missile.h" +#include "game/sound.h" +#include "specific/init.h" #include "global/vars.h" +void __cdecl BellControl(__int16 itemID) { + ITEM_INFO *item; + item = &Items[itemID]; + item->goalAnimState = 1; + item->floor = GetHeight(GetFloor(item->pos.x, item->pos.y, item->pos.z, &item->roomNumber), item->pos.x, item->pos.y, item->pos.z); + TestTriggers(TriggerPtr, TRUE); + AnimateItem(item); + if (!item->currentAnimState) { + item->status = ITEM_INACTIVE; + RemoveActiveItem(itemID); + } +} + +void __cdecl InitialiseWindow(__int16 itemID) { + ITEM_INFO *item; + ROOM_INFO *room; + BOX_INFO *box; + + item = &Items[itemID]; + item->flags = 0; + item->meshBits = 1; + room = &RoomInfo[item->roomNumber]; + box = &Boxes[room->floor[((item->pos.x - room->x) >> WALL_SHIFT) * room->xSize + ((item->pos.z - room->z) >> WALL_SHIFT)].box]; + if (CHK_ANY(box->overlapIndex, 0x8000)) + box->overlapIndex |= 0x4000; +} + +void __cdecl SmashWindow(__int16 itemID) { + ITEM_INFO *item; + ROOM_INFO *room; + BOX_INFO *box; + + item = &Items[itemID]; + room = &RoomInfo[item->roomNumber]; + box = &Boxes[room->floor[((item->pos.x - room->x) >> WALL_SHIFT) * room->xSize + ((item->pos.z - room->z) >> WALL_SHIFT)].box]; + if (CHK_ANY(box->overlapIndex, 0x8000)) + box->overlapIndex &= ~0x4000; + PlaySoundEffect(58, &item->pos, 0); + item->collidable = 0; + item->meshBits = 0xFFFE; + ExplodingDeath(itemID, 0xFEFE, 0); + item->flags |= IFL_INVISIBLE; + if (item->status == ITEM_ACTIVE) + RemoveActiveItem(itemID); + item->status = ITEM_DISABLED; +} + +void __cdecl WindowControl(__int16 itemID) { + ITEM_INFO *item; + int val; + + item = &Items[itemID]; + if (!CHK_ANY(item->flags, IFL_INVISIBLE)) { + if (Lara.skidoo == -1) { + if (item->touchBits) { + item->touchBits = 0; + val = phd_cos(LaraItem->pos.rotY - item->pos.rotY) * LaraItem->speed >> W2V_SHIFT; + if (ABS(val) >= 50) + SmashWindow(itemID); + } + } else { + if (ItemNearLara(&item->pos, 512)) + SmashWindow(itemID); + } + } +} + +void __cdecl InitialiseLift(__int16 itemID) { + ITEM_INFO *item; + int *data; + + item = &Items[itemID]; + item->data = game_malloc(8, GBUF_TempAlloc); + data = (int *) item->data; + data[1] = 0; + data[0] = item->pos.y; +} + +void __cdecl LiftControl(__int16 itemID) { + ITEM_INFO *item; + int *data; + __int16 roomID; + + item = &Items[itemID]; + data = (int *) item->data; + if (TriggerActive(item)) { + if (item->pos.y < data[0] + 5616) { + if (data[1] < 90) { + item->goalAnimState = 1; + ++data[1]; + } else { + item->goalAnimState = 0; + item->pos.y += 16; + } + } else { + item->goalAnimState = 1; + data[1] = 0; + } + } else { + if (item->pos.y > data[0] + 16) { + if (data[1] < 90) { + item->goalAnimState = 1; + ++data[1]; + } else { + item->goalAnimState = 0; + item->pos.y -= 16; + } + } else { + item->goalAnimState = 1; + data[1] = 0; + } + } + AnimateItem(item); + roomID = item->roomNumber; + GetFloor(item->pos.x, item->pos.y, item->pos.z, &roomID); + if (item->roomNumber != roomID) + ItemNewRoom(itemID, roomID); +} + +void __cdecl LiftFloorCeiling(ITEM_INFO *item, int x, int y, int z, int *floor, int *ceiling) { + int liftX, liftZ, laraX, laraZ; + BOOL inside; + + liftX = item->pos.x >> WALL_SHIFT; + liftZ = item->pos.z >> WALL_SHIFT; + laraX = LaraItem->pos.x >> WALL_SHIFT; + laraZ = LaraItem->pos.z >> WALL_SHIFT; + inside = (x >> WALL_SHIFT == liftX || (x >> WALL_SHIFT) + 1 == liftX) && (z >> WALL_SHIFT == liftZ || (z >> WALL_SHIFT) - 1 == liftZ); + *floor = 32767; + *ceiling = -32767; + if ((laraX != liftX && laraX + 1 != liftX) || (laraZ != liftZ && laraZ - 1 != liftZ)) { + if (inside) { + if (y <= item->pos.y - 1280) { + *floor = item->pos.y - 1280; + } else { + if (y < item->pos.y + 256) { + if (!item->currentAnimState) { + *floor = NO_HEIGHT; + *ceiling = 32767; + } else { + *floor = item->pos.y; + *ceiling = item->pos.y - 1024; + } + } else { + *ceiling = item->pos.y + 256; + } + } + } + } else { + if (!item->currentAnimState && LaraItem->pos.y < item->pos.y + 256 && LaraItem->pos.y > item->pos.y - 1024) { + if (inside) { + *floor = item->pos.y; + *ceiling = item->pos.y - 1024; + } else { + *floor = NO_HEIGHT; + *ceiling = 32767; + } + } else { + if (inside) { + if (LaraItem->pos.y < item->pos.y - 1024) { + *floor = item->pos.y - 1280; + } else { + if (LaraItem->pos.y < item->pos.y + 256) { + *floor = item->pos.y; + *ceiling = item->pos.y - 1024; + } else { + *ceiling = item->pos.y + 256; + } + } + } + } + } +} + +void __cdecl LiftFloor(ITEM_INFO *item, int x, int y, int z, int *height) { + int floor, ceiling; + + LiftFloorCeiling(item, x, y, z, &floor, &ceiling); + if (floor < *height) + *height = floor; +} + +void __cdecl LiftCeiling(ITEM_INFO *item, int x, int y, int z, int *height) { + int floor, ceiling; + + LiftFloorCeiling(item, x, y, z, &floor, &ceiling); + if (ceiling > *height) + *height = ceiling; +} /* * Inject function @@ -40,10 +236,12 @@ void Inject_Objects() { // INJECT(0x00434970, DeathSlideCollision); // INJECT(0x00434A30, ControlDeathSlide); // INJECT(0x00434CC0, BigBowlControl); -// INJECT(0x00434DB0, BellControl); -// INJECT(0x00434E30, InitialiseWindow); -// INJECT(0x00434EB0, SmashWindow); -// INJECT(0x00434F80, WindowControl); + + INJECT(0x00434DB0, BellControl); + INJECT(0x00434E30, InitialiseWindow); + INJECT(0x00434EB0, SmashWindow); + INJECT(0x00434F80, WindowControl); + // INJECT(0x00435020, SmashIceControl); // INJECT(0x00435100, ShutThatDoor); // INJECT(0x00435150, OpenThatDoor); @@ -53,11 +251,13 @@ void Inject_Objects() { // INJECT(0x00435700, DrawBridgeFloor); // INJECT(0x00435740, DrawBridgeCeiling); // INJECT(0x00435780, DrawBridgeCollision); -// INJECT(0x004357B0, InitialiseLift); -// INJECT(0x004357F0, LiftControl); -// INJECT(0x004358D0, LiftFloorCeiling); -// INJECT(0x00435A50, LiftFloor); -// INJECT(0x00435A90, LiftCeiling); + + INJECT(0x004357B0, InitialiseLift); + INJECT(0x004357F0, LiftControl); + INJECT(0x004358D0, LiftFloorCeiling); + INJECT(0x00435A50, LiftFloor); + INJECT(0x00435A90, LiftCeiling); + // INJECT(0x00435AD0, BridgeFlatFloor); // INJECT(0x00435AF0, BridgeFlatCeiling); // INJECT(0x00435B10, GetOffset); diff --git a/game/objects.h b/game/objects.h index 4972fa1..d690af6 100644 --- a/game/objects.h +++ b/game/objects.h @@ -38,12 +38,12 @@ // 0x00434970: DeathSlideCollision // 0x00434A30: ControlDeathSlide // 0x00434CC0: BigBowlControl -// 0x00434DB0: BellControl -// 0x00434E30: InitialiseWindow -#define SmashWindow ((void(__cdecl*)(__int16)) 0x00434EB0) +void __cdecl BellControl(__int16 itemID); // 0x00434DB0 +void __cdecl InitialiseWindow(__int16 itemID); // 0x00434E30 +void __cdecl SmashWindow(__int16 itemID); // 0x00434EB0 +void __cdecl WindowControl(__int16 itemID); // 0x00434F80 -// 0x00434F80: WindowControl // 0x00435020: SmashIceControl // 0x00435100: ShutThatDoor // 0x00435150: OpenThatDoor @@ -53,11 +53,13 @@ // 0x00435700: DrawBridgeFloor // 0x00435740: DrawBridgeCeiling // 0x00435780: DrawBridgeCollision -// 0x004357B0: InitialiseLift -// 0x004357F0: LiftControl -// 0x004358D0: LiftFloorCeiling -// 0x00435A50: LiftFloor -// 0x00435A90: LiftCeiling + +void __cdecl InitialiseLift(__int16 itemID); // 0x004357B0 +void __cdecl LiftControl(__int16 itemID); // 0x004357F0 +void __cdecl LiftFloorCeiling(ITEM_INFO *item, int x, int y, int z, int *floor, int *ceiling); // 0x004358D0 +void __cdecl LiftFloor(ITEM_INFO *item, int x, int y, int z, int *height); // 0x00435A50 +void __cdecl LiftCeiling(ITEM_INFO *item, int x, int y, int z, int *height); // 0x00435A90 + // 0x00435AD0: BridgeFlatFloor // 0x00435AF0: BridgeFlatCeiling // 0x00435B10: GetOffset diff --git a/game/people.cpp b/game/people.cpp index 1d4f2e8..45de088 100644 --- a/game/people.cpp +++ b/game/people.cpp @@ -21,8 +21,12 @@ #include "global/precompiled.h" #include "game/people.h" +#include "3dsystem/phd_math.h" +#include "game/box.h" +#include "game/control.h" #include "game/effects.h" #include "game/items.h" +#include "game/larafire.h" #include "game/sound.h" #include "game/sphere.h" #include "specific/game.h" @@ -32,6 +36,26 @@ extern DWORD AlphaBlendMode; #endif // FEATURE_VIDEOFX_IMPROVED +int __cdecl Targetable(ITEM_INFO *item, AI_INFO *info) { + CREATURE_INFO *creature; + ITEM_INFO *enemy; + GAME_VECTOR source, destination; + + creature = (CREATURE_INFO *) item->data; + enemy = creature->enemy; + if (enemy->hitPoints > 0 && info->ahead && info->distance < SQR(8192)) { + source.x = item->pos.x; + source.y = item->pos.y - 768; + source.z = item->pos.z; + source.roomNumber = item->roomNumber; + destination.x = enemy->pos.x; + destination.y = enemy->pos.y - 768; + destination.z = enemy->pos.z; + return LOS(&source, &destination); + } + return 0; +} + __int16 __cdecl GunShot(int x, int y, int z, __int16 speed, __int16 rotY, __int16 roomNumber) { #ifdef FEATURE_VIDEOFX_IMPROVED if( AlphaBlendMode ) { @@ -113,19 +137,120 @@ __int16 __cdecl GunMiss(int x, int y, int z, __int16 speed, __int16 rotY, __int1 return GunShot(x, y, z, speed, rotY, roomNumber); } +int __cdecl ShotLara(ITEM_INFO *item, AI_INFO *info, BITE_INFO *bite, __int16 rotation, int damage) { + CREATURE_INFO *creature; + ITEM_INFO *enemy; + int val; + BOOL hit, shot; + __int16 fxID, itemID; + GAME_VECTOR source, destination; + + creature = (CREATURE_INFO *) item->data; + enemy = creature->enemy; + if (info->distance <= SQR(8192) && Targetable(item, info)) { + val = SQR(8192) * (enemy->speed * phd_sin(info->enemy_facing) >> W2V_SHIFT) / 300; + if (SQR(val) + info->distance > SQR(8192)) { + hit = FALSE; + } else { + hit = GetRandomControl() < (SQR(8192) - info->distance) / 3276 + 8192; + } + shot = TRUE; + } else { + shot = FALSE; + hit = FALSE; + } + fxID = -1; + if (enemy == LaraItem) { + if (hit) { + fxID = CreatureEffect(item, bite, GunHit); + LaraItem->hitPoints -= damage; + LaraItem->hit_status = 1; + } else { + if (shot) + fxID = CreatureEffect(item, bite, GunMiss); + } + } else { + fxID = CreatureEffect(item, bite, GunShot); + if (hit) { + enemy->hitPoints -= damage / 10; + enemy->hit_status = 1; + } + } + if (fxID != -1) + Effects[fxID].pos.rotY += rotation; + source.x = item->pos.x; + source.y = item->pos.y - 768; + source.z = item->pos.z; + source.roomNumber = item->roomNumber; + destination.x = enemy->pos.x; + destination.y = enemy->pos.y - 768; + destination.z = enemy->pos.z; + itemID = ObjectOnLOS(&source, &destination); + if (itemID != -1) + SmashItem(itemID, LGT_Unarmed); + return shot; +} + +void __cdecl WinstonControl(__int16 itemID) { + ITEM_INFO *item; + CREATURE_INFO *winston; + AI_INFO info; + __int16 angle; + + if (CreatureActive(itemID)) { + item = &Items[itemID]; + winston = (CREATURE_INFO *) item->data; + CreatureAIInfo(item, &info); + CreatureMood(item, &info, TRUE); + angle = CreatureTurn(item, winston->maximum_turn); + if (item->currentAnimState == 1) { + if ((info.distance > SQR(1536) || !info.ahead) && item->goalAnimState != 2) { + item->goalAnimState = 2; + PlaySoundEffect(345, &item->pos, 0); + } + } else { + if (info.distance <= SQR(1536)) { + if (info.ahead) { + item->goalAnimState = 1; + if (CHK_ANY(winston->flags, 1)) + --winston->flags; + } else { + if (!CHK_ANY(winston->flags, 1)) { + PlaySoundEffect(344, &item->pos, 0); + PlaySoundEffect(347, &item->pos, 0); + winston->flags |= 1; + } + } + } + } + if (item->touchBits && !CHK_ANY(winston->flags, 2)) { + PlaySoundEffect(346, &item->pos, 0); + PlaySoundEffect(347, &item->pos, 0); + winston->flags |= 2; + } else { + if (!item->touchBits && CHK_ANY(winston->flags, 2)) + winston->flags -= 2; + } + if (GetRandomDraw() < 256) + PlaySoundEffect(347, &item->pos, 0); + CreatureAnimation(itemID, angle, 0); + } +} + /* * Inject function */ void Inject_People() { -// INJECT(0x00435EB0, Targetable); + INJECT(0x00435EB0, Targetable); + // INJECT(0x00435F40, ControlGlow); // INJECT(0x00435F80, ControlGunShot); INJECT(0x00435FD0, GunShot); INJECT(0x00436040, GunHit); INJECT(0x00436100, GunMiss); + INJECT(0x004361B0, ShotLara); -// INJECT(0x004361B0, ShotLara); // INJECT(0x00436380, InitialiseCult1); // INJECT(0x004363D0, Cult1Control); // INJECT(0x00436800, InitialiseCult3); @@ -134,5 +259,6 @@ void Inject_People() { // INJECT(0x004371C0, Worker2Control); // INJECT(0x00437620, BanditControl); // INJECT(0x00437960, Bandit2Control); -// INJECT(0x00437DA0, WinstonControl); + + INJECT(0x00437DA0, WinstonControl); } diff --git a/game/people.h b/game/people.h index bea13a0..66732a3 100644 --- a/game/people.h +++ b/game/people.h @@ -27,15 +27,15 @@ /* * Function list */ -// 0x00435EB0: Targetable +int __cdecl Targetable(ITEM_INFO *item, AI_INFO *info); // 0x00435EB0 + // 0x00435F40: ControlGlow // 0x00435F80: ControlGunShot __int16 __cdecl GunShot(int x, int y, int z, __int16 speed, __int16 rotY, __int16 roomNumber); // 0x00435FD0 __int16 __cdecl GunHit(int x, int y, int z, __int16 speed, __int16 rotY, __int16 roomNumber); // 0x00436040 __int16 __cdecl GunMiss(int x, int y, int z, __int16 speed, __int16 rotY, __int16 roomNumber); // 0x00436100 - -// 0x004361B0: ShotLara +int __cdecl ShotLara(ITEM_INFO *item, AI_INFO *info, BITE_INFO *bite, __int16 rotation, int damage); // 0x004361B0 #define InitialiseCult1 ((void(__cdecl*)(__int16)) 0x00436380) #define Cult1Control ((void(__cdecl*)(__int16)) 0x004363D0) @@ -45,6 +45,7 @@ __int16 __cdecl GunMiss(int x, int y, int z, __int16 speed, __int16 rotY, __int1 #define Worker2Control ((void(__cdecl*)(__int16)) 0x004371C0) #define BanditControl ((void(__cdecl*)(__int16)) 0x00437620) #define Bandit2Control ((void(__cdecl*)(__int16)) 0x00437960) -#define WinstonControl ((void(__cdecl*)(__int16)) 0x00437DA0) + +void __cdecl WinstonControl(__int16 itemID); // 0x00437DA0 #endif // PEOPLE_H_INCLUDED diff --git a/game/sphere.h b/game/sphere.h index 2cfc216..c16fb0b 100644 --- a/game/sphere.h +++ b/game/sphere.h @@ -27,9 +27,8 @@ /* * Function list */ -// 0x0043FA60: TestCollision -// 0x0043FB90: GetSpheres - +#define TestCollision ((int(__cdecl*)(ITEM_INFO*, ITEM_INFO*)) 0x0043FA60) +#define GetSpheres ((int(__cdecl*)(ITEM_INFO*, SPHERE_INFO*, BOOL)) 0x0043FB90) #define GetJointAbsPosition ((void(__cdecl*)(ITEM_INFO*, PHD_VECTOR*, int)) 0x0043FE70) #define BaddieBiteEffect ((void(__cdecl*)(ITEM_INFO*,BITE_INFO*)) 0x00440010) diff --git a/game/traps.cpp b/game/traps.cpp index 0cf3aa7..04c1c5a 100644 --- a/game/traps.cpp +++ b/game/traps.cpp @@ -23,6 +23,7 @@ #include "global/precompiled.h" #include "game/traps.h" #include "3dsystem/phd_math.h" +#include "game/collide.h" #include "game/control.h" #include "game/effects.h" #include "game/items.h" @@ -30,6 +31,7 @@ #include "game/sound.h" #include "game/sphere.h" #include "specific/game.h" +#include "specific/init.h" #include "global/vars.h" #ifdef FEATURE_INPUT_IMPROVED @@ -154,7 +156,7 @@ void __cdecl ControlCeilingSpikes(__int16 itemID) { if (item->touchBits) { LaraItem->hitPoints -= 20; LaraItem->hit_status = 1; - DoLotsOfBlood(LaraItem->pos.x, LaraItem->pos.y + 768, LaraItem->pos.z, 1, item->pos.rotY, LaraItem->roomNumber, 3); + DoLotsOfBlood(LaraItem->pos.x, item->pos.y + 768, LaraItem->pos.z, 1, item->pos.rotY, LaraItem->roomNumber, 3); item->touchBits = 0; PlaySoundEffect(205, &item->pos, 0); } @@ -312,6 +314,191 @@ void __cdecl KillerStatueControl(__int16 itemID) { AnimateItem(item); } +void __cdecl SpringBoardControl(__int16 itemID) { + ITEM_INFO *item; + + item = &Items[itemID]; + if (!item->currentAnimState && + item->pos.y == LaraItem->pos.y && + !CHK_ANY(item->pos.x ^ LaraItem->pos.x, 0xFFFFFC00) && + !CHK_ANY(item->pos.z ^ LaraItem->pos.z, 0xFFFFFC00)) + { + if (LaraItem->hitPoints > 0) { + if (LaraItem->currentAnimState == AS_BACK || LaraItem->currentAnimState == AS_FASTBACK) + LaraItem->speed = -LaraItem->speed; + LaraItem->fallSpeed = -240; + LaraItem->gravity = 1; + LaraItem->animNumber = 34; + LaraItem->frameNumber = Anims[LaraItem->animNumber].frameBase; + LaraItem->currentAnimState = AS_FORWARDJUMP; + LaraItem->goalAnimState = AS_FORWARDJUMP; + item->goalAnimState = 1; + AnimateItem(item); + } + } else { + AnimateItem(item); + } +} + +void __cdecl InitialiseRollingBall(__int16 itemID) { + ITEM_INFO *item; + GAME_VECTOR *pos; + + item = &Items[itemID]; + item->data = game_malloc(sizeof(GAME_VECTOR), GBUF_RollingBallStuff); + pos = (GAME_VECTOR *) item->data; + pos->x = item->pos.x; + pos->y = item->pos.y; + pos->z = item->pos.z; + pos->roomNumber = item->roomNumber; +} + +void __cdecl RollingBallControl(__int16 itemID) { + ITEM_INFO *item; + int oldX, oldZ, distance, x, z; + __int16 roomID; + FLOOR_INFO *floor; + GAME_VECTOR *pos; + + item = &Items[itemID]; + if (item->status == ITEM_ACTIVE) { + if (item->goalAnimState == 2) { + AnimateItem(item); + } else { + if (item->pos.y < item->floor) { + if (!item->gravity) { + item->fallSpeed = -10; + item->gravity = 1; + } + } else { + if (!item->currentAnimState) + item->goalAnimState = 1; + } + oldX = item->pos.x; + oldZ = item->pos.z; + AnimateItem(item); + roomID = item->roomNumber; + floor = GetFloor(item->pos.x, item->pos.y, item->pos.z, &roomID); + if (item->roomNumber != roomID) + ItemNewRoom(itemID, roomID); + item->floor = GetHeight(floor, item->pos.x, item->pos.y, item->pos.z); + TestTriggers(TriggerPtr, TRUE); + if (item->pos.y >= item->floor - 256) { + item->gravity = 0; + item->pos.y = item->floor; + item->fallSpeed = 0; + if (item->objectID == ID_ROLLING_BALL2) { + PlaySoundEffect(222, &item->pos, 0); + } else { + if (item->objectID == ID_ROLLING_BALL3) { + PlaySoundEffect(227, &item->pos, 0); + } else { + PlaySoundEffect(147, &item->pos, 0); + } + } + distance = phd_sqrt(SQR(Camera.micPos.x - item->pos.x) + SQR(Camera.micPos.z - item->pos.z)); + if (distance < 10240) + Camera.bounce = 40 * (distance - 10240) / 10240; + } + distance = item->objectID == ID_ROLLING_BALL1 ? 384 : 1024; + x = item->pos.x + (distance * phd_sin(item->pos.rotY) >> W2V_SHIFT); + z = item->pos.z + (distance * phd_cos(item->pos.rotY) >> W2V_SHIFT); + if (GetHeight(GetFloor(x, item->pos.y, z, &roomID), x, item->pos.y, z) < item->pos.y) { + if (item->objectID == ID_ROLLING_BALL2) { + PlaySoundEffect(223, &item->pos, 0); + item->goalAnimState = 2; + } else { + if (item->objectID == ID_ROLLING_BALL3) { + PlaySoundEffect(228, &item->pos, 0); + item->goalAnimState = 2; + } else { + item->status = ITEM_DISABLED; + } + } + item->pos.y = item->floor; + item->pos.x = oldX; + item->pos.z = oldZ; + item->fallSpeed = 0; + item->speed = 0; + item->touchBits = 0; + } + } + } else { + if (item->status == ITEM_DISABLED && !TriggerActive(item)) { + pos = (GAME_VECTOR *) item->data; + item->status = ITEM_INACTIVE; + item->pos.x = pos->x; + item->pos.y = pos->y; + item->pos.z = pos->z; + if (item->roomNumber != pos->roomNumber) { + RemoveDrawnItem(itemID); + item->nextItem = RoomInfo[pos->roomNumber].itemNumber; + RoomInfo[pos->roomNumber].itemNumber = itemID; + item->roomNumber = pos->roomNumber; + } + item->animNumber = Objects[item->objectID].animIndex; + item->frameNumber = Anims[item->animNumber].frameBase; + item->requiredAnimState = 0; + item->goalAnimState = Anims[item->animNumber].currentAnimState; + item->currentAnimState = item->goalAnimState; + RemoveActiveItem(itemID); + } + } +} + +void __cdecl RollingBallCollision(__int16 itemID, ITEM_INFO *laraItem, COLL_INFO *coll) { + ITEM_INFO *item; + int dx, dy, dz, distance, i; + + item = &Items[itemID]; + if (item->status == ITEM_ACTIVE) { + if (TestBoundsCollide(item, laraItem, coll->radius) && TestCollision(item, laraItem)) { + if (laraItem->gravity) { + if (CHK_ANY(coll->flags, 8)) + ItemPushLara(item, laraItem, coll, CHK_ANY(coll->flags, 0x10), 1); + laraItem->hitPoints -= 100; + dx = laraItem->pos.x - item->pos.x; + dy = laraItem->pos.y - item->pos.y + 162; + dz = laraItem->pos.z - item->pos.z; + distance = (__int16) phd_sqrt(SQR(dx) + SQR(dy) + SQR(dz)); + if (distance < 512) + distance = 512; + DoBloodSplat(item->pos.x + (dx << WALL_SHIFT) / 2 / distance, + item->pos.y + (dy << WALL_SHIFT) / 2 / distance - 512, + item->pos.z + (dz << WALL_SHIFT) / 2 / distance, + item->speed, + item->pos.rotY, + item->roomNumber); + } else { + laraItem->hit_status = 1; + if (laraItem->hitPoints > 0) { + laraItem->hitPoints = -1; + laraItem->pos.rotY = item->pos.rotY; + laraItem->pos.rotZ = 0; + laraItem->pos.rotX = 0; + laraItem->animNumber = 139; + laraItem->frameNumber = Anims[laraItem->animNumber].frameBase; + laraItem->currentAnimState = AS_SPECIAL; + laraItem->goalAnimState = AS_SPECIAL; + Camera.flags = CFL_FollowCenter; + Camera.targetAngle = 170 * PHD_DEGREE; + Camera.targetElevation = -25 * PHD_DEGREE; + for (i = 0; i < 15; ++i) + DoBloodSplat(laraItem->pos.x + (GetRandomControl() - 16384) / 256, + laraItem->pos.y - GetRandomControl() / 64, + laraItem->pos.z + (GetRandomControl() - 16384) / 256, + 2 * item->speed, + item->pos.rotY + (GetRandomControl() - 16384) / 8, + item->roomNumber); + } + } + } + } else { + if (item->status != ITEM_INVISIBLE) + ObjectCollision(itemID, laraItem, coll); + } +} + void __cdecl Pendulum(__int16 itemID) { ITEM_INFO *item; @@ -627,11 +814,11 @@ void Inject_Traps() { INJECT(0x00441900, BladeControl); INJECT(0x004419A0, InitialiseKillerStatue); INJECT(0x004419F0, KillerStatueControl); + INJECT(0x00441B00, SpringBoardControl); + INJECT(0x00441BE0, InitialiseRollingBall); + INJECT(0x00441C20, RollingBallControl); + INJECT(0x00441F70, RollingBallCollision); -// INJECT(0x00441B00, SpringBoardControl); -// INJECT(0x00441BE0, InitialiseRollingBall); -// INJECT(0x00441C20, RollingBallControl); -// INJECT(0x00441F70, RollingBallCollision); // INJECT(0x004421C0, SpikeCollision); // INJECT(0x00442320, TrapDoorControl); // INJECT(0x00442370, TrapDoorFloor); diff --git a/game/traps.h b/game/traps.h index 980aa60..14b9cac 100644 --- a/game/traps.h +++ b/game/traps.h @@ -41,11 +41,11 @@ void __cdecl InitialiseBlade(__int16 itemID); // 0x004418C0 void __cdecl BladeControl(__int16 itemID); // 0x00441900 void __cdecl InitialiseKillerStatue(__int16 itemID); // 0x004419A0 void __cdecl KillerStatueControl(__int16 itemID); // 0x004419F0 +void __cdecl SpringBoardControl(__int16 itemID); // 0x00441B00 +void __cdecl InitialiseRollingBall(__int16 itemID); // 0x00441BE0 +void __cdecl RollingBallControl(__int16 itemID); // 0x00441C20 +void __cdecl RollingBallCollision(__int16 itemID, ITEM_INFO *laraItem, COLL_INFO *coll); // 0x00441F70 -// 0x00441B00: SpringBoardControl -// 0x00441BE0: InitialiseRollingBall -// 0x00441C20: RollingBallControl -// 0x00441F70: RollingBallCollision // 0x004421C0: SpikeCollision // 0x00442320: TrapDoorControl // 0x00442370: TrapDoorFloor diff --git a/global/types.h b/global/types.h index 0a603e2..0534267 100644 --- a/global/types.h +++ b/global/types.h @@ -245,10 +245,17 @@ typedef struct { #define GLOW_GUNSHOT_COLOR (0x7F701F) // Skidoo/Enemy gunfire // Collision types -#define COLL_FRONT (0x01) -#define COLL_LEFT (0x02) -#define COLL_RIGHT (0x04) -#define COLL_TOP (0x08) +#define COLL_FRONT (0x01) +#define COLL_LEFT (0x02) +#define COLL_RIGHT (0x04) +#define COLL_TOP (0x08) +#define COLL_TOPFRONT (0x10) +#define COLL_CLAMP (0x20) + +// Trigger/floordata control bits +#define END_BIT (0x8000) +#define VALUE_BITS (0x03FF) +#define DATA_TYPE (0x00FF) /* * DirectX type definitions @@ -1156,6 +1163,35 @@ typedef enum { CHAR_SECRET3, } CHAR_SECRETS; +typedef enum { + HT_WALL, + HT_SMALL_SLOPE, + HT_BIG_SLOPE, +} HEIGHT_TYPE; + +typedef enum { + TT_TRIGGER, + TT_PAD, + TT_SWITCH, + TT_KEY, + TT_PICKUP, + TT_HEAVY, + TT_ANTIPAD, + TT_COMBAT, + TT_DUMMY, + TT_ANTITRIGGER, +} TRIGGER_TYPE; + +typedef enum { + FT_FLOOR, + FT_DOOR, + FT_TILT, + FT_ROOF, + FT_TRIGGER, + FT_LAVA, + FT_CLIMB, +} FLOOR_TYPE; + /* * Structs */ @@ -1693,6 +1729,13 @@ typedef struct Phd3dPos_t { __int16 rotZ; } PHD_3DPOS; +typedef struct SphereInfo_t { + int x; + int y; + int z; + int r; +} SPHERE_INFO; + typedef struct ItemInfo_t { int floor; DWORD touchBits; diff --git a/global/vars.h b/global/vars.h index f054a5b..acd9105 100644 --- a/global/vars.h +++ b/global/vars.h @@ -151,9 +151,11 @@ extern __int16 InvOptionObjectsCount; #define IsShadeEffect VAR_U_(0x004D6F68, bool) #define CineCurrentFrame VAR_U_(0x004D7770, int) #define IsChunkyCamera VAR_U_(0x004D777C, BOOL) +#define HeightType VAR_U_(0x004D7780, HEIGHT_TYPE) #define NoInputCounter VAR_U_(0x004D7784, int) #define IsResetFlag VAR_U_(0x004D7788, BOOL) #define FlipTimer VAR_U_(0x004D778C, int) +#define LosRoomsCount VAR_U_(0x004D7790, int) #define StopInventory VAR_U_(0x004D7794, BOOL) #define IsDemoLevelType VAR_U_(0x004D779C, BOOL) #define IsDemoLoaded VAR_U_(0x004D77A0, BOOL) @@ -378,6 +380,7 @@ extern APP_SETTINGS SavedAppSettings; #define NextItemActive VAR_U_(0x005207C8, __int16) #define NextEffectActive VAR_U_(0x005207CA, __int16) #define PrevItemActive VAR_U_(0x005207CC, __int16) +#define SkipHairPhysics VAR_U_(0x00521CD0, BOOL) #define SoundFxCount VAR_U_(0x00521FDC, DWORD) #define SoundFx VAR_U_(0x00521FE0, OBJECT_VECTOR*) #define AnimFrames VAR_U_(0x005251B0, __int16*) @@ -406,6 +409,7 @@ extern APP_SETTINGS SavedAppSettings; #define IsCinematicLoaded VAR_U_(0x005262F4, __int16) #define CineFramesCount VAR_U_(0x005262F6, __int16) #define CineFrames VAR_U_(0x005262F8, CINE_FRAME_INFO*) +#define CinematicPos VAR_U_(0x00526300, PHD_3DPOS) #define CineLevelID VAR_U_(0x00526312, __int16) #define CineFrameIdx VAR_U_(0x00526314, __int16) #define Camera VAR_U_(0x00526320, CAMERA_INFO) @@ -646,6 +650,8 @@ extern bool ConflictLayout[ARRAY_SIZE(Layout->key)]; #define SaveGameItemFlags2 ARRAY_(0x00521BE0, DWORD, [24]) #define SaveGameItemFlags1 ARRAY_(0x00521C40, DWORD, [24]) #define PickupInfos ARRAY_(0x00521CA0, PICKUP_INFO, [12]) +#define HairVelocity ARRAY_(0x00521CE0, PHD_VECTOR, [7]) +#define HairPos ARRAY_(0x00521D40, PHD_3DPOS, [7]) #define Objects ARRAY_(0x00522000, OBJECT_INFO, [265]) #ifdef FEATURE_EXTENDED_LIMITS extern LIGHT_INFO DynamicLights[64]; @@ -660,6 +666,7 @@ extern STATIC_INFO StaticObjects[256]; #endif // FEATURE_EXTENDED_LIMITS #define CD_Flags ARRAY_(0x005261C0, __int16, [64]) #define FlipMaps ARRAY_(0x00526260, int, [10]) +#define LosRooms ARRAY_(0x005262A0, int, [20]) #define GroundZones ARRAY_(0x005263A0, __int16*, [8]) #define FlyZones ARRAY_(0x005263C0, __int16*, [2])