#include "../newobjects.h" #include "../../Game/lara.h" #include "../../Game/collide.h" #include "../../Game/effects.h" #include "../../Game/laraflar.h" #include "../../Game/items.h" #include "../../Game/sphere.h" #include "../../Game/draw.h" #include "../../Game/misc.h" extern LaraExtraInfo g_LaraExtra; typedef enum MINECART_STATE { CART_GETIN, CART_GETOUT, CART_GETOUTL, CART_GETOUTR, CART_STILL, CART_DUCK, CART_MOVE, CART_RIGHT, CART_HARDLEFT, CART_LEFT, CART_HARDRIGHT, CART_BRAKE, CART_FWD, CART_BACK, CART_TURNDEATH, CART_FALLDEATH, CART_WALLDEATH, CART_HIT, CART_USE, CART_BRAKING }; typedef enum MINECART_FLAGS { CF_MESH = 1, CF_TURNINGL = 2, CF_TURNINGR = 4, CF_RDIR = 8, CF_CONTROL = 16, CF_STOPPED = 32, CF_NOANIM = 64, CF_DEAD = 128 }; /// ANIMATION: #define GETOFF_DIST 330 #define CART_DEC -1536 #define CART_MIN_SPEED 2560 #define CART_MIN_VEL 32 #define TURN_DEATH_VEL 128 #define CART_FWD_GRAD -128 #define CART_BACK_GRAD 128 #define CART_JUMP_VEL 64512 #define CART_GRAVITY (WALL_SIZE + 1) #define MAX_CART_YVEL 16128 #define TERMINAL_ANGLE (WALL_SIZE * 4) #define CART_RADIUS 100 #define CART_HEIGHT (STEP_SIZE * 3) #define CART_NHITS 25 #define CART_BADDIE_RADIUS STEP_SIZE extern LaraExtraInfo g_LaraExtra; static int TestHeight(ITEM_INFO* v, int x, int z) { PHD_VECTOR pos; FLOOR_INFO* floor; int s, c; short room_number; c = COS(v->pos.yRot); s = SIN(v->pos.yRot); pos.x = v->pos.xPos + (((z * s) + (x * c)) >> W2V_SHIFT); pos.y = v->pos.yPos - (z * SIN(v->pos.xRot) >> W2V_SHIFT) + (x * SIN(v->pos.zRot) >> W2V_SHIFT); pos.z = v->pos.zPos + (((z * c) - (x * s)) >> W2V_SHIFT); room_number = v->roomNumber; floor = GetFloor(pos.x, pos.y, pos.z, &room_number); return GetFloorHeight(floor, pos.x, pos.y, pos.z); } static short GetCollision(ITEM_INFO* v, short ang, int dist, short* ceiling) { FLOOR_INFO* floor; int x, y, z, height, cheight; short room_number; x = v->pos.xPos + ((SIN(ang) * dist) >> W2V_SHIFT); y = v->pos.yPos - LARA_HITE; z = v->pos.zPos + ((COS(ang) * dist) >> W2V_SHIFT); room_number = v->roomNumber; floor = GetFloor(x, y, z, &room_number); height = GetFloorHeight(floor, x, y, z); cheight = GetCeiling(floor, x, y, z); *ceiling = ((short)cheight); if (height != NO_HEIGHT) height -= v->pos.yPos; return short(height); } static bool GetInMineCart(ITEM_INFO* v, ITEM_INFO* l, COLL_INFO* coll) { int dist; int x, z; FLOOR_INFO* floor; short room_number; if (!(TrInput & IN_ACTION) || Lara.gunStatus != LG_NO_ARMS || l->gravityStatus) return 0; /* -------- is Lara close enough to use the vehicle */ if (!TestBoundsCollide(v, l, coll->radius)) return false; if (!TestCollision(v, l)) return false; x = l->pos.xPos - v->pos.xPos; z = l->pos.zPos - v->pos.zPos; dist = SQUARE(x) + SQUARE(z); if (dist > SQUARE(WALL_SIZE/2)) return false; room_number = v->roomNumber; floor = GetFloor(v->pos.xPos, v->pos.yPos, v->pos.zPos, &room_number); if (GetFloorHeight(floor, v->pos.xPos, v->pos.yPos, v->pos.zPos) < -32000) return false; return true; } static bool CanGetOut(int direction) { ITEM_INFO* v; FLOOR_INFO* floor; short room_number, angle; int x, y, z, height, ceiling; v = &Items[g_LaraExtra.Vehicle]; if (direction < 0) angle = v->pos.yRot + 0x4000; else angle = v->pos.yRot - 0x4000; x = v->pos.xPos - (GETOFF_DIST * SIN(angle) >> W2V_SHIFT); y = v->pos.yPos; z = v->pos.zPos - (GETOFF_DIST * COS(angle) >> W2V_SHIFT); room_number = v->roomNumber; floor = GetFloor(x, y, z, &room_number); height = GetFloorHeight(floor, x, y, z); if ((HeightType == BIG_SLOPE) || (HeightType == DIAGONAL) || (height == NO_HEIGHT)) return false; if (abs(height - v->pos.yPos) > WALL_SIZE / 2) return false; ceiling = GetCeiling(floor, x, y, z); if ((ceiling - v->pos.yPos > -LARA_HITE) || (height - ceiling < LARA_HITE)) return false; return true; } static void CartToBaddieCollision(ITEM_INFO* v) { vector roomsList; short* door, numDoors; roomsList.push_back(v->roomNumber); door = Rooms[v->roomNumber].door; if (door) { numDoors = *door; door++; for (int i = 0; i < numDoors; i++) { roomsList.push_back(*door); door += 16; } } for (int i = 0; i < roomsList.size(); i++) { short itemNum = Rooms[roomsList[i]].itemNumber; while (itemNum != NO_ITEM) { ITEM_INFO* item = &Items[itemNum]; if (item->collidable && item->status != ITEM_INVISIBLE && item != LaraItem && item != v) { OBJECT_INFO* object = &Objects[item->objectNumber]; if (object->collision && (object->intelligent || item->objectNumber == ID_ROLLINGBALL || item->objectNumber == ID_ANIMATING2)) { int x = v->pos.xPos - item->pos.xPos; int y = v->pos.yPos - item->pos.yPos; int z = v->pos.zPos - item->pos.zPos; if (x > -2048 && x < 2048 && z > -2048 && z < 2048 && y > -2048 && y < 2048) { if (TestBoundsCollide(item, LaraItem, CART_BADDIE_RADIUS)) { if (item->objectNumber == ID_ANIMATING2) { if ((item->frameNumber == Anims[item->animNumber].frameBase) && (LaraItem->currentAnimState == CART_USE) && (LaraItem->animNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 6)) { FLOOR_INFO* floor; short frame, room_number; frame = LaraItem->frameNumber - Anims[LaraItem->animNumber].frameBase; if ((frame >= 12) && (frame <= 22)) { SoundEffect(220, &item->pos, 2); room_number = item->roomNumber; floor = GetFloor(item->pos.xPos, item->pos.yPos, item->pos.zPos, &room_number); TestTriggers(TriggerIndex, TRUE, 0); // heavytrigger enabled item->frameNumber++; } } } else if (item->objectNumber == ID_ROLLINGBALL) { // KILL lara and stop rolling ball and minecart ! } else { DoLotsOfBlood(item->pos.xPos, v->pos.yPos - STEP_SIZE, item->pos.zPos, GetRandomControl() & 3, v->pos.yRot, item->roomNumber, 3); item->hitPoints = 0; } } } } } itemNum = item->nextItem; } } } // TODO: add special trigger (MINER_TYPE and MINEL_TYPE) and Lara.MineR and Lara.MineL to have a fully minecart working ! static void MoveCart(ITEM_INFO* v, ITEM_INFO* l, CART_INFO* cart) { short val; // check for end of track if (cart->StopDelay) cart->StopDelay--; if (((g_LaraExtra.mineL) && (g_LaraExtra.mineR) && (!cart->StopDelay)) && (((v->pos.xPos & 0x380) == 512) || ((v->pos.zRot & 0x380) == 512))) { if (cart->Speed < 0xf000) // can't do this - bastard { cart->Flags |= CF_STOPPED | CF_CONTROL; cart->Speed = v->speed = 0; return; } else cart->StopDelay = 16; } // initiate turns if ((g_LaraExtra.mineL || g_LaraExtra.mineR) && (!(g_LaraExtra.mineL && g_LaraExtra.mineR)) && (!cart->StopDelay) && (!(cart->Flags & (CF_TURNINGL | CF_TURNINGR)))) { short ang; unsigned short rot = (((unsigned short)v->pos.yRot) >> 14) | (g_LaraExtra.mineL << 2); switch (rot) { case 0: cart->TurnX = (v->pos.xPos + 4096) & ~1023; cart->TurnZ = v->pos.zPos & ~1023; break; case 1: cart->TurnX = v->pos.xPos & ~1023; cart->TurnZ = (v->pos.zPos - 4096) | 1023; break; case 2: cart->TurnX = (v->pos.xPos - 4096) | 1023; cart->TurnZ = v->pos.zPos | 1023; break; case 3: cart->TurnX = v->pos.xPos | 1023; cart->TurnZ = (v->pos.zPos + 4096) & ~1023; break; case 4: cart->TurnX = (v->pos.xPos - 4096) | 1023; cart->TurnZ = v->pos.zPos & ~1023; break; case 5: cart->TurnX = v->pos.xPos & ~1023; cart->TurnZ = (v->pos.zPos + 4096) & ~1023; break; case 6: cart->TurnX = (v->pos.xPos + 4096) & ~1023; cart->TurnZ = v->pos.zPos | 1023; break; case 7: cart->TurnX = v->pos.xPos | 1023; cart->TurnZ = (v->pos.zPos - 4096) | 1023; break; } ang = mGetAngle(v->pos.xPos, v->pos.zPos, cart->TurnX, cart->TurnZ) & 0x3fff; if (rot < 4) { cart->TurnRot = v->pos.yRot; cart->TurnLen = ang; } else { cart->TurnRot = v->pos.yRot; if (ang) ang = 16384 - ang; cart->TurnLen = ang; } cart->Flags |= (g_LaraExtra.mineL) ? CF_TURNINGL : CF_TURNINGR; } // move vehicle if (cart->Speed < CART_MIN_SPEED) cart->Speed = CART_MIN_SPEED; cart->Speed += (-cart->Gradient << 2); if ((v->speed = cart->Speed >> 8) < CART_MIN_VEL) { v->speed = CART_MIN_VEL; StopSoundEffect(209); if (cart->YVel) StopSoundEffect(210); else SoundEffect(210, &v->pos, 2); } else { StopSoundEffect(210); if (cart->YVel) StopSoundEffect(209); else SoundEffect(209, &v->pos, (2 | 4) + 0x1000000 + (v->speed << 15)); } // move cart around corners if (cart->Flags & (CF_TURNINGL | CF_TURNINGR)) { int x, z; unsigned short quad, deg; if ((cart->TurnLen += (v->speed * 3)) > ANGLE(90)) { if (cart->Flags & CF_TURNINGL) v->pos.yRot = cart->TurnRot - 16384; else v->pos.yRot = cart->TurnRot + 16384; cart->Flags &= ~(CF_TURNINGL | CF_TURNINGR); } else { if (cart->Flags & CF_TURNINGL) v->pos.yRot = cart->TurnRot - cart->TurnLen; else v->pos.yRot = cart->TurnRot + cart->TurnLen; } if (cart->Flags & (CF_TURNINGL | CF_TURNINGR)) { quad = ((unsigned short)v->pos.yRot) >> 14; deg = v->pos.yRot & 16383; switch (quad) { case 0: x = -COS(deg); z = SIN(deg); break; case 1: x = SIN(deg); z = COS(deg); break; case 2: x = COS(deg); z = -SIN(deg); break; default: x = -SIN(deg); z = -COS(deg); break; } if (cart->Flags & CF_TURNINGL) { x = -x; z = -z; } v->pos.xPos = cart->TurnX + ((x * 3584) >> W2V_SHIFT); v->pos.zPos = cart->TurnZ + ((z * 3584) >> W2V_SHIFT); } } else { // move cart normally v->pos.xPos += (v->speed * SIN(v->pos.yRot)) >> W2V_SHIFT; v->pos.zPos += (v->speed * COS(v->pos.yRot)) >> W2V_SHIFT; } // tilt cart on slopes cart->MidPos = TestHeight(v, 0, 0); if (!cart->YVel) { cart->FrontPos = TestHeight(v, 0, 256); cart->Gradient = cart->MidPos - cart->FrontPos; v->pos.yPos = cart->MidPos; } else { if (v->pos.yPos > cart->MidPos) { if (cart->YVel > 0) SoundEffect(202, &v->pos, 2); v->pos.yPos = cart->MidPos; cart->YVel = 0; } else { cart->YVel += CART_GRAVITY; if (cart->YVel > MAX_CART_YVEL) cart->YVel = MAX_CART_YVEL; v->pos.yPos += cart->YVel >> 8; } } v->pos.xRot = cart->Gradient << 5; // tilt cart around corners val = v->pos.yRot & 16383; if (cart->Flags & (CF_TURNINGL | CF_TURNINGR)) { if (cart->Flags & CF_TURNINGR) v->pos.zRot = -(val * v->speed) >> 9; else v->pos.zRot = ((0x4000 - val) * v->speed) >> 9; } else { v->pos.zRot -= v->pos.zRot >> 3; } } static void DoUserInput(ITEM_INFO* v, ITEM_INFO* l, CART_INFO* cart) { short fh, ch; switch (l->currentAnimState) { case CART_MOVE: if (TrInput & IN_ACTION) l->goalAnimState = CART_USE; else if (TrInput & IN_DUCK) l->goalAnimState = CART_DUCK; else if (TrInput & IN_JUMP) l->goalAnimState = CART_BRAKE; else if ((cart->Speed == CART_MIN_VEL) || (cart->Flags & CF_STOPPED)) l->goalAnimState = CART_STILL; else if (cart->Gradient < CART_FWD_GRAD) l->goalAnimState = CART_FWD; else if (cart->Gradient > CART_BACK_GRAD) l->goalAnimState = CART_BACK; else if (TrInput & IN_LEFT) l->goalAnimState = CART_LEFT; else if (TrInput & IN_RIGHT) l->goalAnimState = CART_RIGHT; break; case CART_FWD: if (TrInput & IN_ACTION) l->goalAnimState = CART_USE; else if (TrInput & IN_DUCK) l->goalAnimState = CART_DUCK; else if (TrInput & IN_JUMP) l->goalAnimState = CART_BRAKE; else if (cart->Gradient > CART_FWD_GRAD) l->goalAnimState = CART_MOVE; break; case CART_BACK: if (TrInput & IN_ACTION) l->goalAnimState = CART_USE; else if (TrInput & IN_DUCK) l->goalAnimState = CART_DUCK; else if (TrInput & IN_JUMP) l->goalAnimState = CART_BRAKE; else if (cart->Gradient < CART_BACK_GRAD) l->goalAnimState = CART_MOVE; break; case CART_LEFT: if (TrInput & IN_ACTION) l->goalAnimState = CART_USE; else if (TrInput & IN_DUCK) l->goalAnimState = CART_DUCK; else if (TrInput & IN_JUMP) l->goalAnimState = CART_BRAKE; if (!(TrInput & IN_LEFT)) l->goalAnimState = CART_MOVE; break; case CART_RIGHT: if (TrInput & IN_ACTION) l->goalAnimState = CART_USE; else if (TrInput & IN_DUCK) l->goalAnimState = CART_DUCK; else if (TrInput & IN_JUMP) l->goalAnimState = CART_BRAKE; if (!(TrInput & IN_RIGHT)) l->goalAnimState = CART_MOVE; break; case CART_STILL: if (!(cart->Flags & CF_CONTROL)) { SoundEffect(211, &v->pos, 2); cart->Flags |= CF_CONTROL; cart->StopDelay = 64; } if (TrInput & IN_ROLL && (cart->Flags & CF_STOPPED)) { if ((TrInput & IN_LEFT) && (CanGetOut(-1))) { l->goalAnimState = CART_GETOUT; cart->Flags &= ~CF_RDIR; } else if ((TrInput & IN_RIGHT) && (CanGetOut(1))) { l->goalAnimState = CART_GETOUT; cart->Flags |= CF_RDIR; } } if (TrInput & IN_DUCK) l->goalAnimState = CART_DUCK; else if (cart->Speed > CART_MIN_VEL) l->goalAnimState = CART_MOVE; break; case CART_DUCK: if (TrInput & IN_ACTION) l->goalAnimState = CART_USE; else if (TrInput & IN_JUMP) l->goalAnimState = CART_BRAKE; else if (!(TrInput & IN_DUCK)) l->goalAnimState = CART_STILL; break; case CART_USE: l->goalAnimState = CART_MOVE; break; case CART_BRAKING: if (TrInput & IN_DUCK) { l->goalAnimState = CART_DUCK; StopSoundEffect(219); } else if ((!(TrInput & IN_JUMP)) || (cart->Flags & CF_STOPPED)) { l->goalAnimState = CART_MOVE; StopSoundEffect(219); } else { cart->Speed += CART_DEC; SoundEffect(219, &l->pos, 2); } break; case CART_BRAKE: l->goalAnimState = CART_BRAKING; break; case CART_GETOUT: if (l->animNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 7) { if ((l->frameNumber == GF2(ID_MINECART, 7, 0) + 20) && (cart->Flags & CF_MESH)) { short* tmp; tmp = Lara.meshPtrs[LM_RHAND]; LARA_MESHES(ID_MINECART_LARA_ANIMS, LM_RHAND); Meshes[Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND] = tmp; cart->Flags &= ~CF_MESH; } if (cart->Flags & CF_RDIR) l->goalAnimState = CART_GETOUTR; else l->goalAnimState = CART_GETOUTL; } break; case CART_GETOUTL: if ((l->animNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 1) && (l->frameNumber == Anims[l->animNumber].frameEnd)) { PHD_VECTOR vec = { 0, 640, 0 }; GetLaraJointPosition(&vec, LM_HIPS); l->pos.xPos = vec.x; l->pos.yPos = vec.y; l->pos.zPos = vec.z; l->pos.xRot = 0; l->pos.yRot = v->pos.yRot + 0x4000; l->pos.zRot = 0; l->animNumber = 13; l->frameNumber = GF(11, 0); l->currentAnimState = l->goalAnimState = 2; g_LaraExtra.Vehicle = NO_ITEM; Lara.gunStatus = LG_NO_ARMS; } break; case CART_GETOUTR: if ((l->animNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 47) && (l->frameNumber == Anims[l->animNumber].frameEnd)) { PHD_VECTOR vec = { 0, 640, 0 }; GetLaraJointPosition(&vec, LM_HIPS); l->pos.xPos = vec.x; l->pos.yPos = vec.y; l->pos.zPos = vec.z; l->pos.xRot = 0; l->pos.yRot = v->pos.yRot - 0x4000; l->pos.zRot = 0; l->animNumber = 11; l->frameNumber = GF(11, 0); l->currentAnimState = l->goalAnimState = 2; g_LaraExtra.Vehicle = NO_ITEM; Lara.gunStatus = LG_NO_ARMS; } break; case CART_GETIN: if ((l->animNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 5) && (l->frameNumber == GF2(ID_MINECART, 5, 0) + 20) && (!cart->Flags & CF_MESH)) { short* tmp; tmp = Lara.meshPtrs[LM_RHAND]; Lara.meshPtrs[LM_RHAND] = Meshes[Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND]; Meshes[Objects[ID_MINECART_LARA_ANIMS].meshIndex + LM_RHAND] = tmp; cart->Flags |= CF_MESH; } break; case CART_WALLDEATH: Camera.targetElevation = -ANGLE(25); Camera.targetDistance = WALL_SIZE * 4; break; case CART_TURNDEATH: Camera.targetElevation = -ANGLE(45); Camera.targetDistance = WALL_SIZE * 2; fh = GetCollision(v, v->pos.yRot, 512, &ch); if ((fh > -STEP_SIZE) && (fh < STEP_SIZE)) { if ((Wibble & 7) == 0) SoundEffect(SFX_TR3_QUAD_FRONT_IMPACT, &v->pos, 2); v->pos.xPos += (TURN_DEATH_VEL * SIN(v->pos.yRot)) >> W2V_SHIFT; v->pos.zPos += (TURN_DEATH_VEL * COS(v->pos.yRot)) >> W2V_SHIFT; } else { if (l->animNumber == Objects[ID_MINECART_LARA_ANIMS].animIndex + 30) { cart->Flags |= CF_NOANIM; l->hitPoints = -1; } } break; case CART_HIT: if ((l->hitPoints <= 0) && (l->frameNumber == GF2(ID_MINECART, 34, 0) + 28)) { l->frameNumber = GF2(ID_MINECART, 34, 0) + 28; cart->Flags = (cart->Flags & ~CF_CONTROL) | (CF_NOANIM); cart->Speed = v->speed = 0; } break; } /* -------- sync vehicle's anims with Lara */ if ((g_LaraExtra.Vehicle != NO_ITEM) && (!(cart->Flags & CF_NOANIM))) { AnimateItem(l); v->animNumber = Objects[ID_MINECART].animIndex + (l->animNumber - Objects[ID_MINECART_LARA_ANIMS].animIndex); v->frameNumber = Anims[v->animNumber].frameBase + (l->frameNumber - Anims[l->animNumber].frameBase); } /* -------- initiate animations according to collision */ if ((l->currentAnimState != CART_TURNDEATH) && (l->currentAnimState != CART_WALLDEATH) && (l->hitPoints > 0)) { /* -------- fall off corners */ if ((v->pos.zRot > TERMINAL_ANGLE) || (v->pos.zRot < -TERMINAL_ANGLE)) { l->animNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 31; l->frameNumber = Anims[l->animNumber].frameBase; l->currentAnimState = l->goalAnimState = CART_TURNDEATH; cart->Flags = (cart->Flags & ~CF_CONTROL) | CF_STOPPED | CF_DEAD; cart->Speed = v->speed = 0; return; } /* -------- smack into walls */ fh = GetCollision(v, v->pos.yRot, 512, &ch); if (fh < -(STEP_SIZE * 2)) { l->animNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 23; l->frameNumber = Anims[l->animNumber].frameBase; l->currentAnimState = l->goalAnimState = CART_WALLDEATH; cart->Flags = (cart->Flags & ~CF_CONTROL) | (CF_STOPPED | CF_DEAD); cart->Speed = v->speed = 0; l->hitPoints = -1; return; } /* -------- smack into ceilings */ if ((l->currentAnimState != CART_DUCK) && (l->currentAnimState != CART_HIT)) { COLL_INFO coll; coll.quadrant = short((v->pos.yRot + 0x2000) / 0x4000); coll.radius = CART_RADIUS; if (CollideStaticObjects(&coll, v->pos.xPos, v->pos.yPos, v->pos.zPos, v->roomNumber, CART_HEIGHT)) { int hits; l->animNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 34; l->frameNumber = Anims[l->animNumber].frameBase; l->currentAnimState = l->goalAnimState = CART_HIT; DoLotsOfBlood(l->pos.xPos, l->pos.yPos - 768, l->pos.zPos, v->speed, v->pos.yRot, l->roomNumber, 3); hits = (CART_NHITS * short((cart->Speed) >> 11)); if (hits < 20) hits = 20; l->hitPoints -= hits; return; } } /* -------- initiate jumps */ if ((fh > 512 + 64) && (!cart->YVel)) cart->YVel = CART_JUMP_VEL; /* -------- collide with baddies */ CartToBaddieCollision(v); } } void InitialiseMineCart(short itemNum) { ITEM_INFO* v; CART_INFO* cart; v = &Items[itemNum]; cart = (CART_INFO*)GameMalloc(sizeof(CART_INFO)); v->data = (void*)cart; cart->Flags = NULL; cart->Speed = 0; cart->YVel = 0; cart->Gradient = 0; } void MineCartCollision(short itemNum, ITEM_INFO* l, COLL_INFO* coll) { ITEM_INFO* v; CART_INFO* cart; int geton; short ang; if ((l->hitPoints < 0) || (g_LaraExtra.Vehicle != NO_ITEM)) return; v = &Items[itemNum]; if ((geton = GetInMineCart(v, l, coll))) { g_LaraExtra.Vehicle = itemNum; /* -------- throw flare away if using */ if (Lara.gunType == WEAPON_FLARE) { CreateFlare(ID_FLARE_ITEM, FALSE); undraw_flare_meshes(); Lara.flareControlLeft = false; Lara.requestGunType = Lara.gunType = LG_NO_ARMS; } Lara.gunStatus = LG_HANDS_BUSY; /* -------- initiate animation */ ang = short(mGetAngle(v->pos.xPos, v->pos.zPos, l->pos.xPos, l->pos.zPos) - v->pos.yRot); if ((ang > -ANGLE(45)) && (ang < ANGLE(135))) l->animNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 46; else l->animNumber = Objects[ID_MINECART_LARA_ANIMS].animIndex + 0; l->frameNumber = Anims[l->animNumber].frameBase; l->currentAnimState = l->goalAnimState = CART_GETIN; l->pos.xPos = v->pos.xPos; l->pos.yPos = v->pos.yPos; l->pos.zPos = v->pos.zPos; l->pos.xRot = v->pos.xRot; l->pos.yRot = v->pos.yRot; l->pos.zRot = v->pos.zRot; S_CDPlay(12, 0); } else { ObjectCollision(itemNum, l, coll); } } int MineCartControl() { CART_INFO* cart; ITEM_INFO* v; FLOOR_INFO* floor; short room_number; v = &Items[g_LaraExtra.Vehicle]; if (v->data == NULL) { printf("v->data is nullptr !"); return 0; } cart = (CART_INFO*)v->data; DoUserInput(v, LaraItem, cart); if (cart->Flags & CF_CONTROL) MoveCart(v, LaraItem, cart); /* -------- move Lara to vehicle pos */ if (g_LaraExtra.Vehicle != NO_ITEM) { LaraItem->pos.xPos = v->pos.xPos; LaraItem->pos.yPos = v->pos.yPos; LaraItem->pos.zPos = v->pos.zPos; LaraItem->pos.xRot = v->pos.xRot; LaraItem->pos.yRot = v->pos.yRot; LaraItem->pos.zRot = v->pos.zRot; } room_number = v->roomNumber; floor = GetFloor(v->pos.xPos, v->pos.yPos, v->pos.zPos, &room_number); if (room_number != v->roomNumber) { ItemNewRoom(g_LaraExtra.Vehicle, room_number); ItemNewRoom(Lara.itemNumber, room_number); } TestTriggers(TriggerIndex, FALSE, 0); if (!(cart->Flags & CF_DEAD)) { Camera.targetElevation = -ANGLE(45); Camera.targetDistance = WALL_SIZE * 2; } return (g_LaraExtra.Vehicle == NO_ITEM) ? 0 : 1; }