#include "../newobjects.h" #include "../../Game/Box.h" #include "../../Game/effects.h" #include "../../Game/people.h" BITE_INFO civvy_hit = { 0,0,0, 13 }; enum civvy_anims { CIVVY_EMPTY, CIVVY_STOP, CIVVY_WALK, CIVVY_PUNCH2, CIVVY_AIM2, CIVVY_WAIT, CIVVY_AIM1, CIVVY_AIM0, CIVVY_PUNCH1, CIVVY_PUNCH0, CIVVY_RUN, CIVVY_DEATH, CIVVY_CLIMB3, CIVVY_CLIMB1, CIVVY_CLIMB2, CIVVY_FALL3 }; #define CIVVY_WALK_TURN ANGLE(5) #define CIVVY_RUN_TURN ANGLE(6) #define CIVVY_HIT_DAMAGE 40 #define CIVVY_SWIPE_DAMAGE 50 #define CIVVY_ATTACK0_RANGE SQUARE(WALL_SIZE/3) #define CIVVY_ATTACK1_RANGE SQUARE(WALL_SIZE*2/3) #define CIVVY_ATTACK2_RANGE SQUARE(WALL_SIZE) #define CIVVY_WALK_RANGE SQUARE(WALL_SIZE) #define CIVVY_ESCAPE_RANGE SQUARE(WALL_SIZE*3) #define CIVVY_WALK_CHANCE 0x100 #define CIVVY_WAIT_CHANCE 0x100 #define CIVVY_DIE_ANIM 26 #define CIVVY_STOP_ANIM 6 #define CIVVY_CLIMB1_ANIM 28 #define CIVVY_CLIMB2_ANIM 29 #define CIVVY_CLIMB3_ANIM 27 #define CIVVY_FALL3_ANIM 30 #define CIVVY_TOUCH 0x2400 #define CIVVY_VAULT_SHIFT 260 #define CIVVY_AWARE_DISTANCE SQUARE(WALL_SIZE) void InitialiseCivvy(short item_number) { ITEM_INFO* item; item = &Items[item_number]; InitialiseCreature(item_number); /* Start Civvy in stop pose*/ item->animNumber = Objects[item->objectNumber].animIndex + CIVVY_STOP_ANIM; item->frameNumber = Anims[item->animNumber].frameBase; item->currentAnimState = item->goalAnimState = CIVVY_STOP; } void CivvyControl(short item_number) { if (!CreatureActive(item_number)) return; // Area 51 - Civvy Man ITEM_INFO* item, *real_enemy; CREATURE_INFO* civvy; short angle, torso_y, torso_x, head, tilt; int lara_dx, lara_dz; AI_INFO info, lara_info; item = &Items[item_number]; civvy = (CREATURE_INFO*)item->data; torso_y = torso_x = head = angle = tilt = 0; if (Boxes[item->boxNumber].overlapIndex & BLOCKED) { // DoLotsOfBloodD DoLotsOfBlood(item->pos.xPos, item->pos.yPos - (GetRandomControl() & 255) - 32, item->pos.zPos, (GetRandomControl() & 127) + 128, GetRandomControl() << 1, item->roomNumber, 3); item->hitPoints -= 20; } if (item->hitPoints <= 0) { if (item->currentAnimState != CIVVY_DEATH) { item->animNumber = Objects[item->objectNumber].animIndex + CIVVY_DIE_ANIM; item->frameNumber = Anims[item->animNumber].frameBase; item->currentAnimState = CIVVY_DEATH; civvy->LOT.step = STEP_SIZE; } } else { if (item->aiBits) GetAITarget(civvy); else civvy->enemy = LaraItem; CreatureAIInfo(item, &info); if (civvy->enemy == LaraItem) { lara_info.angle = info.angle; lara_info.distance = info.distance; } else { lara_dz = LaraItem->pos.zPos - item->pos.zPos; lara_dx = LaraItem->pos.xPos - item->pos.xPos; lara_info.angle = ATAN(lara_dz, lara_dx) - item->pos.yRot; //only need to fill out the bits of lara_info that will be needed by TargetVisible lara_info.distance = lara_dz * lara_dz + lara_dx * lara_dx; } GetCreatureMood(item, &info, VIOLENT); if (civvy->enemy == LaraItem && info.distance > CIVVY_ESCAPE_RANGE&& info.enemyFacing < 0x3000 && info.enemyFacing > -0x3000) civvy->mood = ESCAPE_MOOD; CreatureMood(item, &info, VIOLENT); angle = CreatureTurn(item, civvy->maximumTurn); real_enemy = civvy->enemy; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things civvy->enemy = LaraItem; if ((lara_info.distance < CIVVY_AWARE_DISTANCE || item->hitStatus || TargetVisible(item, &lara_info)) && !(item->aiBits & FOLLOW)) //Maybe move this into LONDSEC_WAIT case? { if (!civvy->alerted) SoundEffect(SFX_AL, &item->pos, 0); AlertAllGuards(item_number); } civvy->enemy = real_enemy; switch (item->currentAnimState) { case CIVVY_WAIT: if (civvy->alerted || item->goalAnimState == CIVVY_RUN) { item->goalAnimState = CIVVY_STOP; break; } case CIVVY_STOP: civvy->flags = 0; civvy->maximumTurn = 0; head = lara_info.angle; if (item->aiBits & GUARD) { head = AIGuard(civvy); if (!(GetRandomControl() & 0xFF)) { if (item->currentAnimState == CIVVY_STOP) item->goalAnimState = CIVVY_WAIT; else item->goalAnimState = CIVVY_STOP; } break; } else if (item->aiBits & PATROL1) item->goalAnimState = CIVVY_WALK; else if (civvy->mood == ESCAPE_MOOD) { if (Lara.target != item && info.ahead) item->goalAnimState = CIVVY_STOP; else item->goalAnimState = CIVVY_RUN; } else if (civvy->mood == BORED_MOOD || ((item->aiBits & FOLLOW) && (civvy->reachedGoal || lara_info.distance > SQUARE(WALL_SIZE * 2)))) { if (item->requiredAnimState) item->goalAnimState = item->requiredAnimState; else if (info.ahead) item->goalAnimState = CIVVY_STOP; else item->goalAnimState = CIVVY_RUN; } else if (info.bite && info.distance < CIVVY_ATTACK0_RANGE) item->goalAnimState = CIVVY_AIM0; else if (info.bite && info.distance < CIVVY_ATTACK1_RANGE) item->goalAnimState = CIVVY_AIM1; else if (info.bite && info.distance < CIVVY_WALK_RANGE) item->goalAnimState = CIVVY_WALK; else item->goalAnimState = CIVVY_RUN; break; case CIVVY_WALK: head = lara_info.angle; civvy->maximumTurn = CIVVY_WALK_TURN; if (item->aiBits & PATROL1) { item->goalAnimState = CIVVY_WALK; head = 0; } else if (civvy->mood == ESCAPE_MOOD) item->goalAnimState = CIVVY_RUN; else if (civvy->mood == BORED_MOOD) { if (GetRandomControl() < CIVVY_WAIT_CHANCE) { item->requiredAnimState = CIVVY_WAIT; item->goalAnimState = CIVVY_STOP; } } else if (info.bite && info.distance < CIVVY_ATTACK0_RANGE) item->goalAnimState = CIVVY_STOP; else if (info.bite && info.distance < CIVVY_ATTACK2_RANGE) item->goalAnimState = CIVVY_AIM2; else //if (!info.ahead || info.distance > CIVVY_WALK_RANGE) item->goalAnimState = CIVVY_RUN; break; case CIVVY_RUN: if (info.ahead) head = info.angle; civvy->maximumTurn = CIVVY_RUN_TURN; tilt = angle / 2; if (item->aiBits & GUARD) item->goalAnimState = CIVVY_WAIT; else if (civvy->mood == ESCAPE_MOOD) { if (Lara.target != item && info.ahead) item->goalAnimState = CIVVY_STOP; break; } else if ((item->aiBits & FOLLOW) && (civvy->reachedGoal || lara_info.distance > SQUARE(WALL_SIZE * 2))) item->goalAnimState = CIVVY_STOP; //Maybe CIVVY_STOP else if (civvy->mood == BORED_MOOD) item->goalAnimState = CIVVY_WALK; else if (info.ahead && info.distance < CIVVY_WALK_RANGE) item->goalAnimState = CIVVY_WALK; break; case CIVVY_AIM0: if (info.ahead) { torso_y = info.angle; torso_x = info.xAngle; } civvy->maximumTurn = CIVVY_WALK_TURN; civvy->flags = 0; if (info.bite && info.distance < CIVVY_ATTACK0_RANGE) item->goalAnimState = CIVVY_PUNCH0; else item->goalAnimState = CIVVY_STOP; break; case CIVVY_AIM1: if (info.ahead) { torso_y = info.angle; torso_x = info.xAngle; } civvy->maximumTurn = CIVVY_WALK_TURN; civvy->flags = 0; if (info.ahead && info.distance < CIVVY_ATTACK1_RANGE) item->goalAnimState = CIVVY_PUNCH1; else item->goalAnimState = CIVVY_STOP; break; case CIVVY_AIM2: if (info.ahead) { torso_y = info.angle; torso_x = info.xAngle; } civvy->maximumTurn = CIVVY_WALK_TURN; civvy->flags = 0; if (info.bite && info.distance < CIVVY_ATTACK2_RANGE) item->goalAnimState = CIVVY_PUNCH2; else item->goalAnimState = CIVVY_WALK; break; case CIVVY_PUNCH0: if (info.ahead) { torso_y = info.angle; torso_x = info.xAngle; } civvy->maximumTurn = CIVVY_WALK_TURN; if (!civvy->flags && (item->touchBits & CIVVY_TOUCH)) { LaraItem->hitPoints -= CIVVY_HIT_DAMAGE; LaraItem->hitStatus = true; CreatureEffect(item, &civvy_hit, DoBloodSplat); SoundEffect(70, &item->pos, 0); civvy->flags = 1; } break; case CIVVY_PUNCH1: if (info.ahead) { torso_y = info.angle; torso_x = info.xAngle; } civvy->maximumTurn = CIVVY_WALK_TURN; if (!civvy->flags && (item->touchBits & CIVVY_TOUCH)) { LaraItem->hitPoints -= CIVVY_HIT_DAMAGE; LaraItem->hitStatus = true; CreatureEffect(item, &civvy_hit, DoBloodSplat); SoundEffect(70, &item->pos, 0); civvy->flags = 1; } if (info.ahead && info.distance > CIVVY_ATTACK1_RANGE&& info.distance < CIVVY_ATTACK2_RANGE) item->goalAnimState = CIVVY_PUNCH2; break; case CIVVY_PUNCH2: if (info.ahead) { torso_y = info.angle; torso_x = info.xAngle; } civvy->maximumTurn = CIVVY_WALK_TURN; if (civvy->flags != 2 && (item->touchBits & CIVVY_TOUCH)) { LaraItem->hitPoints -= CIVVY_SWIPE_DAMAGE; LaraItem->hitStatus = true; CreatureEffect(item, &civvy_hit, DoBloodSplat); SoundEffect(70, &item->pos, 0); civvy->flags = 2; } break; } } CreatureTilt(item, tilt); CreatureJoint(item, 0, torso_y); CreatureJoint(item, 1, torso_x); CreatureJoint(item, 2, head); /* Actually do animation allowing for collisions */ if (item->currentAnimState < CIVVY_DEATH) // Know CLIMB3 marks the start of the CLIMB states { switch (CreatureVault(item_number, angle, 2, CIVVY_VAULT_SHIFT)) { case 2: /* Half block jump */ civvy->maximumTurn = 0; item->animNumber = Objects[item->objectNumber].animIndex + CIVVY_CLIMB1_ANIM; item->frameNumber = Anims[item->animNumber].frameBase; item->currentAnimState = CIVVY_CLIMB1; break; case 3: /* 3/4 block jump */ civvy->maximumTurn = 0; item->animNumber = Objects[item->objectNumber].animIndex + CIVVY_CLIMB2_ANIM; item->frameNumber = Anims[item->animNumber].frameBase; item->currentAnimState = CIVVY_CLIMB2; break; case 4: /* Full block jump */ civvy->maximumTurn = 0; item->animNumber = Objects[item->objectNumber].animIndex + CIVVY_CLIMB3_ANIM; item->frameNumber = Anims[item->animNumber].frameBase; item->currentAnimState = CIVVY_CLIMB3; break; case -4: /* Full block fall */ civvy->maximumTurn = 0; item->animNumber = Objects[item->objectNumber].animIndex + CIVVY_FALL3_ANIM; item->frameNumber = Anims[item->animNumber].frameBase; item->currentAnimState = CIVVY_FALL3; break; } } else { civvy->maximumTurn = 0; CreatureAnimation(item_number, angle, 0); } } /* #define FENCE_WIDTH 128 #define FENCE_LENGTH 1024+32 void ControlElectricFence(short item_number) { ITEM_INFO *item; long x,z,xsize,zsize; long dx,dz,tx,ty,tz,xand,zand; item = &items[item_number]; if (!TriggerActive(item)) return; dx = lara_item->pos.x_pos - item->pos.x_pos; dz = lara_item->pos.z_pos - item->pos.z_pos; if (dx < -0x5000 || dx > 0x5000 || dz < -0x5000 || dz > 0x5000) return; switch (item->pos.y_rot) { case 0: x = item->pos.x_pos + 512; z = item->pos.z_pos + 512; tx = x-FENCE_LENGTH; tz = z-256; xand = 2047; zand = 0; xsize = FENCE_LENGTH; zsize = FENCE_WIDTH; break; case 16384: x = item->pos.x_pos + 512; z = item->pos.z_pos - 512; tx = x-256; tz = z-FENCE_LENGTH; xand = 0; zand = 2047; xsize = FENCE_WIDTH; zsize = FENCE_LENGTH; break; case -32768: x = item->pos.x_pos - 512; z = item->pos.z_pos - 512; tx = x-FENCE_LENGTH; tz = z+256; xand = 2047; zand = 0; xsize = FENCE_LENGTH; zsize = FENCE_WIDTH; break; case -16384: x = item->pos.x_pos - 512; z = item->pos.z_pos + 512; tx = x+256; tz = z-FENCE_LENGTH; xand = 0; zand = 2047; xsize = FENCE_WIDTH; zsize = FENCE_LENGTH; break; default: x = z = xsize = zsize = tx = tz = xand = zand = 0; break; } if ((GetRandomControl()&63) == 0) { long lp,cnt; cnt = (GetRandomControl()&3)+3; if (xand) tx += (GetRandomControl()&xand); else tz += (GetRandomControl()&zand); if (CurrentLevel != LV_OFFICE) ty = item->pos.y_pos-(GetRandomControl()&2047)-(GetRandomControl()&1023); else ty = item->pos.y_pos - (GetRandomControl()&0x1F); for (lp=0;lppos.x_pos < x-xsize || lara_item->pos.x_pos > x+xsize || lara_item->pos.z_pos < z-zsize || lara_item->pos.z_pos > z+zsize || lara_item->pos.y_pos > item->pos.y_pos + 32 || lara_item->pos.y_pos < item->pos.y_pos - 3072) return; { long lp,cnt,lp2,cnt2,sx,sz; sx = tx; sz = tz; cnt = (GetRandomControl()&15)+3; for (lp=0;lppos.x_pos + (GetRandomControl()&511) - 256; else tz = lara_item->pos.z_pos + (GetRandomControl()&511) - 256; ty = lara_item->pos.y_pos - (GetRandomControl()%768); cnt2 = (GetRandomControl()&3)+6; for (lp2=0;lp2hit_points = 0; } static void TriggerFenceSparks(long x, long y, long z, long kill) { SPARKS *sptr; sptr = &spark[GetFreeSpark()]; sptr->On = 1; sptr->sB = (GetRandomControl()&63)+192; sptr->sR = sptr->sB; sptr->sG = sptr->sB; sptr->dB = (GetRandomControl()&63)+192; sptr->dR = sptr->sB>>2; sptr->dG = sptr->sB>>1; sptr->ColFadeSpeed = 8; sptr->FadeToBlack = 16; sptr->sLife = sptr->Life = 32+(GetRandomControl()&7); sptr->TransType = COLADD; sptr->Dynamic = -1; sptr->x = x; sptr->y = y; sptr->z = z; sptr->Xvel = ((GetRandomControl()&255)-128)<<1; sptr->Yvel = (GetRandomControl()&15)-8-(kill<<5); sptr->Zvel = ((GetRandomControl()&255)-128)<<1; sptr->Friction = 4;//|(4<<4); sptr->Flags = SP_SCALE; sptr->Scalar = 1+kill; sptr->Width = sptr->sWidth = (GetRandomControl()&3)+4; sptr->dWidth = sptr->sWidth = 1; sptr->Height = sptr->sHeight = sptr->Width; sptr->dHeight = sptr->dWidth; sptr->Gravity = 16+(GetRandomControl()&15); sptr->MaxYvel = 0; } */