2019-12-05 17:35:57 +01:00
# include "../newobjects.h"
# include "../../Game/items.h"
# include "../../Game/effect2.h"
# include "../../Game/lot.h"
# include "../../Game/Box.h"
# include "../../Game/sphere.h"
# include "../../Game/people.h"
# include "../../Game/draw.h"
2019-12-22 00:20:10 +01:00
# include "../../Game/effects.h"
2019-12-15 19:07:38 +01:00
# include "../../Game/misc.h"
2019-12-02 14:49:19 +01:00
# define MAX_TRIGGER_RANGE 0x4000
# define SMALL_FLASH 10
# define BIG_FLASH 16
# define BOLT_SPEED 384
enum { NOTHING , SUMMONING , KNOCKBACK } ;
enum { NORMAL_BOLT , LARGE_BOLT , SUMMON_BOLT } ;
2019-12-05 17:35:57 +01:00
enum { RIGHT_PRONG , ICONPOS , LEFT_PRONG } ;
2019-12-02 14:49:19 +01:00
enum { ATTACK_HEAD , ATTACK_HAND1 , ATTACK_HAND2 } ;
enum londonboss_anims {
LONDONBOSS_EMPTY ,
LONDONBOSS_STAND ,
LONDONBOSS_WALK ,
LONDONBOSS_RUN ,
LONDONBOSS_SUMMON ,
LONDONBOSS_BIGZAP ,
LONDONBOSS_DEATH ,
LONDONBOSS_LAUGH ,
LONDONBOSS_LILZAP ,
LONDONBOSS_VAULT2 ,
LONDONBOSS_VAULT3 ,
LONDONBOSS_VAULT4 ,
LONDONBOSS_GODOWN
} ;
# define LONDONBOSS_VAULT2_ANIM 9
# define LONDONBOSS_VAULT3_ANIM 18
# define LONDONBOSS_VAULT4_ANIM 15
# define LONDONBOSS_GODOWN_ANIM 21
# define LONDONBOSS_STND2SUM_ANIM 1
# define LONDONBOSS_SUMMON_ANIM 2
# define LONDONBOSS_GODOWN_ANIM 21
# define LONDONBOSS_VAULT_SHIFT 96
# define LONDONBOSS_AWARE_DISTANCE SQUARE(WALL_SIZE)
# define LONDONBOSS_WALK_TURN ANGLE(4)
# define LONDONBOSS_RUN_TURN ANGLE(7)
# define LONDONBOSS_WALK_RANGE SQUARE(WALL_SIZE)
# define LONDONBOSS_WALK_CHANCE 0x100
# define LONDONBOSS_LAUGH_CHANCE 0x100
# define LONDONBOSS_TURN ANGLE(2)
# define LONDONBOSS_DIE_ANIM 17
# define LONDONBOSS_FINAL_HEIGHT -11776
# define BIGZAP_TIMER 600
static long death_radii [ 5 ] ;
static long death_heights [ 5 ] ;
static long radii [ 5 ] = { 200 , 400 , 500 , 500 , 475 } ;
static long heights [ 5 ] = { - 1536 , - 1280 , - 832 , - 384 , 0 } ;
static long dradii [ 5 ] = { 100 < < 4 , 350 < < 4 , 400 < < 4 , 350 < < 4 , 100 < < 4 } ;
static long dheights1 [ 5 ] = { - 1536 - ( 768 < < 3 ) , - 1152 - ( 384 < < 3 ) , - 768 , - 384 + ( 384 < < 3 ) , 0 + ( 768 < < 3 ) } ;
static long dheights2 [ 5 ] = { - 1536 , - 1152 , - 768 , - 384 , 0 } ;
static BITE_INFO londonboss_points [ 3 ] = {
{ 16 , 56 , 356 , 10 } , // Right prong.
{ - 28 , 48 , 304 , 10 } , // Icon.
{ - 72 , 48 , 356 , 10 } , // Left prong.
} ;
static SHIELD_POINTS LondonBossShield [ 40 ] ;
static EXPLOSION_RING ExpRings [ 6 ] ;
static EXPLOSION_RING KBRings [ 3 ] ;
static BOSS_STRUCT bossdata ;
static char links [ 20 ] [ 4 ] = {
{ 0 , 0 , 1 , 2 } ,
{ 0 , 0 , 2 , 3 , } ,
{ 0 , 0 , 3 , 4 , } ,
{ 0 , 0 , 4 , 1 , } ,
{ 1 , 2 , 5 , 6 , } ,
{ 2 , 3 , 6 , 7 , } ,
{ 3 , 4 , 7 , 8 , } ,
{ 4 , 1 , 8 , 5 , } ,
{ 1 + 4 , 2 + 4 , 5 + 4 , 6 + 4 , } ,
{ 2 + 4 , 3 + 4 , 6 + 4 , 7 + 4 , } ,
{ 3 + 4 , 4 + 4 , 7 + 4 , 8 + 4 , } ,
{ 4 + 4 , 1 + 4 , 8 + 4 , 5 + 4 , } ,
{ 1 + 8 , 2 + 8 , 5 + 8 , 6 + 8 , } ,
{ 2 + 8 , 3 + 8 , 6 + 8 , 7 + 8 , } ,
{ 3 + 8 , 4 + 8 , 7 + 8 , 8 + 8 , } ,
{ 4 + 8 , 1 + 8 , 8 + 8 , 5 + 8 , } ,
{ 1 + 12 , 2 + 12 , 5 + 12 , 5 + 12 , } ,
{ 2 + 12 , 3 + 12 , 5 + 12 , 5 + 12 , } ,
{ 3 + 12 , 4 + 12 , 5 + 12 , 5 + 12 , } ,
{ 4 + 12 , 1 + 12 , 5 + 12 , 5 + 12 , }
} ;
static char sumlinks [ 8 ] [ 4 ] = {
{ 0 , 0 , 1 , 2 } ,
{ 0 , 0 , 2 , 3 } ,
{ 0 , 0 , 3 , 4 } ,
{ 0 , 0 , 4 , 1 } ,
{ 1 , 2 , 5 , 5 } ,
{ 2 , 3 , 5 , 5 } ,
{ 3 , 4 , 5 , 5 } ,
{ 4 , 1 , 5 , 5 }
} ;
static void DrawLondonBossShield ( ITEM_INFO * item )
{
2019-12-05 17:35:57 +01:00
// PSX
2019-12-02 14:49:19 +01:00
}
static void DrawExplosionRings ( )
{
2019-12-05 17:35:57 +01:00
// PSX
2019-12-02 14:49:19 +01:00
}
static void DrawSummonRings ( )
{
2019-12-05 17:35:57 +01:00
// PSX
2019-12-02 14:49:19 +01:00
}
static void DrawKnockBackRings ( )
{
2019-12-05 17:35:57 +01:00
// PSX
2019-12-02 14:49:19 +01:00
}
static void TriggerLaserBolt ( PHD_VECTOR * pos , ITEM_INFO * item , long type , short yang )
{
ITEM_INFO * bolt_item ;
short item_number ;
short angles [ 2 ] ;
/* Create a laser bolt and launch it on its way */
item_number = CreateItem ( ) ;
if ( item_number ! = NO_ITEM )
{
bolt_item = & Items [ item_number ] ;
bolt_item - > objectNumber = ID_LASER_BOLT ;
bolt_item - > roomNumber = item - > roomNumber ;
bolt_item - > pos . xPos = pos - > x ;
bolt_item - > pos . yPos = pos - > y ;
bolt_item - > pos . zPos = pos - > z ;
InitialiseItem ( item_number ) ;
if ( type = = SUMMON_BOLT )
{
bolt_item - > pos . yPos + = item - > pos . yPos - 384 ;
bolt_item - > pos . xRot = - pos - > y < < 5 ;
bolt_item - > pos . yRot = GetRandomControl ( ) < < 1 ;
}
else
{
2019-12-05 17:35:57 +01:00
phd_GetVectorAngles ( LaraItem - > pos . xPos - pos - > x , LaraItem - > pos . yPos - STEP_SIZE - pos - > y , LaraItem - > pos . zPos - pos - > z , angles ) ;
2019-12-02 14:49:19 +01:00
bolt_item - > pos . xRot = angles [ 1 ] ;
bolt_item - > pos . yRot = yang ;
bolt_item - > pos . zRot = 0 ;
}
if ( type ! = LARGE_BOLT )
{
bolt_item - > speed = 16 ;
bolt_item - > itemFlags [ 0 ] = - 24 ;
bolt_item - > itemFlags [ 1 ] = 4 ;
if ( type = = SUMMON_BOLT )
bolt_item - > itemFlags [ 2 ] = 1 ; // Set the 'just draw front and back' flag.
}
else
{
bolt_item - > speed = 24 ;
bolt_item - > itemFlags [ 0 ] = 31 ;
bolt_item - > itemFlags [ 1 ] = 16 ;
}
AddActiveItem ( item_number ) ;
}
}
static void TriggerPlasmaBallFlame ( short fx_number , long type , long xv , long yv , long zv )
{
SPARKS * sptr ;
long size ;
long dx , dz ;
dx = LaraItem - > pos . xPos - Effects [ fx_number ] . pos . xPos ;
dz = LaraItem - > pos . zPos - Effects [ fx_number ] . pos . zPos ;
if ( dx < - MAX_TRIGGER_RANGE | | dx > MAX_TRIGGER_RANGE | | dz < - MAX_TRIGGER_RANGE | | dz > MAX_TRIGGER_RANGE )
return ;
sptr = & Sparks [ GetFreeSpark ( ) ] ;
sptr - > on = 1 ;
sptr - > sG = 255 ;
sptr - > sB = 48 + ( GetRandomControl ( ) & 31 ) ;
sptr - > sR = 48 ;
sptr - > dG = 192 + ( GetRandomControl ( ) & 63 ) ;
sptr - > dB = 128 + ( GetRandomControl ( ) & 63 ) ;
sptr - > dR = 32 ;
sptr - > colFadeSpeed = 12 + ( GetRandomControl ( ) & 3 ) ;
sptr - > fadeToBlack = 8 ;
sptr - > sLife = sptr - > life = ( GetRandomControl ( ) & 7 ) + 24 ;
sptr - > transType = 2 ;
sptr - > extras = 0 ;
sptr - > dynamic = - 1 ;
sptr - > x = ( ( GetRandomControl ( ) & 15 ) - 8 ) ;
sptr - > y = 0 ;
sptr - > z = ( ( GetRandomControl ( ) & 15 ) - 8 ) ;
sptr - > xVel = xv + ( GetRandomControl ( ) & 255 ) - 128 ;
sptr - > yVel = yv ;
sptr - > zVel = zv + ( GetRandomControl ( ) & 255 ) - 128 ;
sptr - > friction = 5 ;
if ( GetRandomControl ( ) & 1 )
{
sptr - > flags = SP_SCALE | SP_DEF | SP_ROTATE | SP_EXPDEF | SP_FX ;
sptr - > rotAng = GetRandomControl ( ) & 4095 ;
if ( GetRandomControl ( ) & 1 )
sptr - > rotAdd = - ( GetRandomControl ( ) & 15 ) - 16 ;
else
sptr - > rotAdd = ( GetRandomControl ( ) & 15 ) + 16 ;
}
else
{
sptr - > flags = SP_SCALE | SP_DEF | SP_EXPDEF | SP_FX ;
}
sptr - > fxObj = fx_number ;
sptr - > scalar = 1 ;
size = ( GetRandomControl ( ) & 31 ) + 64 ;
sptr - > size = sptr - > sSize = size ;
sptr - > dSize = size > > 2 ;
sptr - > gravity = sptr - > maxYvel = 0 ;
}
static void TriggerPlasmaBall ( ITEM_INFO * item , long type , PHD_VECTOR * pos1 , short room_number , short angle )
{
FX_INFO * fx ;
PHD_VECTOR pos ;
short fx_number , angles [ 2 ] ;
long speed ;
pos . x = pos1 - > x ;
pos . y = pos1 - > y ;
pos . z = pos1 - > z ;
speed = ( GetRandomControl ( ) & 31 ) + 64 ;
angles [ 0 ] = angle + GetRandomControl ( ) + 0x4000 ;
angles [ 1 ] = 0x2000 ;
fx_number = CreateNewEffect ( room_number ) ;
if ( fx_number ! = NO_ITEM )
{
fx = & Effects [ fx_number ] ;
fx - > pos . xPos = pos . x ;
fx - > pos . yPos = pos . y ;
fx - > pos . zPos = pos . z ;
fx - > pos . yRot = angles [ 0 ] ;
fx - > pos . xRot = angles [ 1 ] ;
fx - > objectNumber = ID_LASER_BOLT ;
fx - > speed = speed ;
fx - > fallspeed = 0 ;
fx - > flag1 = 1 ;
if ( type = = 2 )
fx - > flag2 = 1 ;
else
fx - > flag2 = 0 ;
}
}
static long KnockBackCollision ( EXPLOSION_RING * erptr )
{
int radius , x , z , dist ;
short angle , diff ;
radius = erptr - > radius ;
x = LaraItem - > pos . xPos - erptr - > x ;
z = LaraItem - > pos . zPos - erptr - > z ;
if ( x > 16000 | | x < - 16000 | | z > 16000 | | z < - 16000 )
dist = 0x7FFF ;
else
dist = SQUARE ( x ) + SQUARE ( z ) ;
if ( dist < SQUARE ( radius ) )
{
/* Whump! Been hit by sphere - throw Lara through air */
LaraItem - > hitPoints - = 200 ;
LaraItem - > hitStatus = true ;
angle = ATAN ( z , x ) ;
diff = LaraItem - > pos . yRot - angle ;
if ( abs ( diff ) < 0x4000 )
{
/* Facing away from blast */
LaraItem - > speed = 75 ;
LaraItem - > pos . yRot = angle ;
}
else
{
/* Facing towards blast */
LaraItem - > pos . yRot = short ( angle - 0x8000 ) ;
LaraItem - > speed = - 75 ;
}
LaraItem - > gravityStatus = true ;
LaraItem - > fallspeed = - 50 ;
LaraItem - > pos . xRot = LaraItem - > pos . zRot = 0 ;
LaraItem - > animNumber = 34 ;
LaraItem - > frameNumber = GF ( 34 , 0 ) ;
LaraItem - > currentAnimState = 3 ;
LaraItem - > goalAnimState = 3 ;
TriggerExplosionSparks ( LaraItem - > pos . xPos , LaraItem - > pos . yPos , LaraItem - > pos . zPos , 3 , - 2 , 2 , LaraItem - > roomNumber ) ; // -2 = Set off a dynamic light controller.
for ( x = 0 ; x < 3 ; x + + )
TriggerPlasmaBall ( LaraItem , 2 , ( PHD_VECTOR * ) & LaraItem - > pos , LaraItem - > roomNumber , GetRandomControl ( ) < < 1 ) ;
2019-12-05 17:35:57 +01:00
2019-12-02 14:49:19 +01:00
return 1 ;
}
return 0 ;
}
static void ExplodeLondonBoss ( ITEM_INFO * item )
{
SHIELD_POINTS * shptr ;
long lp , lp1 , angle , y , r , g , b ;
if ( bossdata . explode_count = = 1 | |
bossdata . explode_count = = 15 | |
bossdata . explode_count = = 25 | |
bossdata . explode_count = = 35 | |
bossdata . explode_count = = 45 | |
bossdata . explode_count = = 55 ) // Trigger explosion & ring ?
{
long x , y , z ;
x = item - > pos . xPos + ( ( GetRandomControl ( ) & 1023 ) - 512 ) ;
y = item - > pos . yPos - ( GetRandomControl ( ) & 1023 ) - 256 ;
z = item - > pos . zPos + ( ( GetRandomControl ( ) & 1023 ) - 512 ) ;
ExpRings [ bossdata . ring_count ] . x = x ;
ExpRings [ bossdata . ring_count ] . y = y ;
ExpRings [ bossdata . ring_count ] . z = z ;
ExpRings [ bossdata . ring_count ] . on = true ;
bossdata . ring_count + + ;
TriggerExplosionSparks ( x , y , z , 3 , - 2 , 2 , 0 ) ; // -2 = Set off a dynamic light controller.
for ( lp = 0 ; lp < 2 ; lp + + )
TriggerExplosionSparks ( x , y , z , 3 , - 1 , 2 , 0 ) ;
2020-03-02 09:49:11 +01:00
SoundEffect ( SFX_TR3_BLAST_CIRCLE , & item - > pos , PITCH_SHIFT | 0x800000 ) ;
2019-12-02 14:49:19 +01:00
}
// Adjust shield coordinates.
for ( lp = 0 ; lp < 5 ; lp + + )
{
if ( bossdata . explode_count < 128 ) // Expand.
{
death_radii [ lp ] = ( dradii [ lp ] > > 4 ) + ( ( ( dradii [ lp ] ) * bossdata . explode_count ) > > 7 ) ;
death_heights [ lp ] = dheights2 [ lp ] + ( ( ( dheights1 [ lp ] - dheights2 [ lp ] ) * bossdata . explode_count ) > > 7 ) ;
}
}
// Setup shield coordinates.
shptr = & LondonBossShield [ 0 ] ; // x,y,z,rgb.
for ( lp = 0 ; lp < 5 ; lp + + )
{
y = death_heights [ lp ] ;
angle = ( Wibble < < 3 ) & 511 ;
for ( lp1 = 0 ; lp1 < 8 ; lp1 + + )
{
shptr - > x = ( rcossin_tbl [ angle < < 1 ] * death_radii [ lp ] ) > > 11 ;
shptr - > y = y ;
shptr - > z = ( rcossin_tbl [ ( angle < < 1 ) + 1 ] * death_radii [ lp ] ) > > 11 ;
if ( lp ! = 0 & & lp ! = 4 & & bossdata . explode_count < 64 )
{
g = ( GetRandomControl ( ) & 31 ) + 224 ;
b = ( g > > 2 ) + ( GetRandomControl ( ) & 63 ) ;
r = ( GetRandomControl ( ) & 63 ) ;
r = ( r * ( 64 - bossdata . explode_count ) ) > > 6 ;
g = ( g * ( 64 - bossdata . explode_count ) ) > > 6 ;
b = ( b * ( 64 - bossdata . explode_count ) ) > > 6 ;
shptr - > rgb = r | ( g < < 8 ) | ( b < < 16 ) ;
}
else
shptr - > rgb = 0 ;
angle + = 512 ;
angle & = 4095 ;
shptr + + ;
}
}
}
static void LondonBossDie ( short item_number )
{
ITEM_INFO * item ;
item = & Items [ item_number ] ;
item - > collidable = false ;
item - > hitPoints = - 16384 ;
KillItem ( item_number ) ;
DisableBaddieAI ( item_number ) ;
item - > flags | = ONESHOT ; // Don't want bad guys triggered ever again
}
void ControlLaserBolts ( short item_number )
{
FLOOR_INFO * floor ;
ITEM_INFO * item ;
PHD_VECTOR oldpos ;
long g , b , rad ;
short room_number , oldroom , hitlara ;
int speed ;
item = & Items [ item_number ] ;
oldpos . x = item - > pos . xPos ;
oldpos . y = item - > pos . yPos ;
oldpos . z = item - > pos . zPos ;
oldroom = item - > roomNumber ;
speed = ( item - > speed * COS ( item - > pos . xRot ) ) > > W2V_SHIFT ;
item - > pos . zPos + = ( speed * COS ( item - > pos . yRot ) ) > > W2V_SHIFT ;
item - > pos . xPos + = ( speed * SIN ( item - > pos . yRot ) ) > > W2V_SHIFT ;
item - > pos . yPos + = - ( ( item - > speed * SIN ( item - > pos . xRot ) ) > > W2V_SHIFT ) ;
if ( item - > speed < BOLT_SPEED )
item - > speed + = ( item - > speed > > 3 ) + 2 ;
if ( item - > itemFlags [ 2 ] & & item - > speed > ( BOLT_SPEED > > 1 ) )
{
item - > itemFlags [ 3 ] + + ;
if ( item - > itemFlags [ 3 ] > = 16 )
{
KillItem ( item_number ) ;
return ;
}
}
room_number = item - > roomNumber ;
floor = GetFloor ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , & room_number ) ;
if ( item - > roomNumber ! = room_number )
ItemNewRoom ( item_number , room_number ) ;
if ( ! item - > itemFlags [ 2 ] )
{
if ( ItemNearLara ( & item - > pos , 400 ) )
hitlara = 1 ;
else
hitlara = 0 ;
item - > floor = GetFloorHeight ( floor , item - > pos . xPos , item - > pos . yPos , item - > pos . zPos ) ;
if ( hitlara | | item - > pos . yPos > = item - > floor | | item - > pos . yPos < = GetCeiling ( floor , item - > pos . xPos , item - > pos . yPos , item - > pos . zPos ) )
{
SoundEffect ( SFX_EXPLOSION1 , & item - > pos , 0 ) ;
if ( item - > itemFlags [ 0 ] < 0 )
rad = 2 ;
else
rad = 3 ;
TriggerExplosionSparks ( oldpos . x , oldpos . y , oldpos . z , rad , - 2 , 2 , item - > roomNumber ) ; // -2 = Set off a dynamic light controller.
for ( g = 0 ; g < rad ; g + + )
TriggerExplosionSparks ( oldpos . x , oldpos . y , oldpos . z , 2 , - 1 , 2 , item - > roomNumber ) ;
rad + + ;
for ( g = 0 ; g < rad ; g + + )
TriggerPlasmaBall ( item , 1 , & oldpos , oldroom , item - > pos . yRot ) ;
if ( hitlara )
{
LaraItem - > hitPoints - = 30 + ( ( item - > itemFlags [ 0 ] > = 0 ) < < 9 ) ;
LaraItem - > hitStatus = true ;
}
else
{
long dx , dy , dz ;
dx = SQUARE ( LaraItem - > pos . xPos - item - > pos . xPos ) ;
dy = SQUARE ( LaraItem - > pos . yPos - 256 - item - > pos . yPos ) ;
dz = SQUARE ( LaraItem - > pos . zPos - item - > pos . zPos ) ;
dx = SQRT_ASM ( dx + dy + dz ) ;
if ( dx < 0x400 )
{
LaraItem - > hitPoints - = ( 0x400 - dx ) > > ( 6 - ( ( item - > itemFlags [ 0 ] > = 0 ) < < 1 ) ) ;
LaraItem - > hitStatus = true ;
}
}
KillItem ( item_number ) ;
return ;
}
}
g = 31 - ( GetRandomControl ( ) & 7 ) ;
b = g > > 1 ;
if ( item - > itemFlags [ 0 ] < 0 ) // Small bolt?
{
if ( item - > itemFlags [ 2 ] )
{
g = ( g * ( 16 - item - > itemFlags [ 3 ] ) ) > > 4 ;
b = ( b * ( 16 - item - > itemFlags [ 3 ] ) ) > > 4 ;
}
rad = - item - > itemFlags [ 0 ] ;
if ( rad > SMALL_FLASH )
{
item - > itemFlags [ 0 ] + + ;
item - > itemFlags [ 1 ] + = 2 ;
}
}
else
{
rad = item - > itemFlags [ 0 ] ;
if ( rad > BIG_FLASH )
{
item - > itemFlags [ 0 ] - - ;
item - > itemFlags [ 1 ] + = 4 ;
}
}
TriggerDynamicLight ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , rad , 0 , g , b ) ;
}
void ControlLondBossPlasmaBall ( short fx_number )
{
FX_INFO * fx ;
FLOOR_INFO * floor ;
long speed ;
long rnd , r , g , b , old_y ;
byte radtab [ 2 ] = { 13 , 7 } ;
short room_number ;
fx = & Effects [ fx_number ] ;
old_y = fx - > pos . yPos ;
fx - > fallspeed + + ;
if ( fx - > speed > 8 )
fx - > speed - = 2 ;
if ( fx - > pos . xRot > - 0x3c00 )
fx - > pos . xRot - = 0x100 ;
speed = ( fx - > speed * COS ( fx - > pos . xRot ) ) > > W2V_SHIFT ;
fx - > pos . zPos + = ( speed * COS ( fx - > pos . yRot ) ) > > W2V_SHIFT ;
fx - > pos . xPos + = ( speed * SIN ( fx - > pos . yRot ) ) > > W2V_SHIFT ;
fx - > pos . yPos + = - ( ( fx - > speed * SIN ( fx - > pos . xRot ) ) > > W2V_SHIFT ) + fx - > fallspeed ;
if ( ( Wibble & 15 ) = = 0 )
TriggerPlasmaBallFlame ( fx_number , 0 , 0 , abs ( old_y - fx - > pos . yPos ) < < 3 , 0 ) ;
room_number = fx - > roomNumber ;
floor = GetFloor ( fx - > pos . xPos , fx - > pos . yPos , fx - > pos . zPos , & room_number ) ;
if ( fx - > pos . yPos > = GetFloorHeight ( floor , fx - > pos . xPos , fx - > pos . yPos , fx - > pos . zPos ) | |
fx - > pos . yPos < GetCeiling ( floor , fx - > pos . xPos , fx - > pos . yPos , fx - > pos . zPos ) )
{
KillEffect ( fx_number ) ;
return ;
}
if ( Rooms [ room_number ] . flags & ENV_FLAG_WATER )
{
KillEffect ( fx_number ) ;
return ;
}
if ( ! fx - > flag2 & & ItemNearLara ( & fx - > pos , 200 ) )
{
LaraItem - > hitPoints - = 25 ;
LaraItem - > hitStatus = true ;
KillEffect ( fx_number ) ;
return ;
}
if ( room_number ! = fx - > roomNumber )
EffectNewRoom ( fx_number , LaraItem - > roomNumber ) ;
rnd = GetRandomControl ( ) ;
g = 31 - ( ( rnd > > 4 ) & 3 ) ;
b = 24 - ( ( rnd > > 6 ) & 3 ) ;
r = rnd & 7 ;
TriggerDynamicLight ( fx - > pos . xPos , fx - > pos . yPos , fx - > pos . zPos , radtab [ fx - > flag1 ] , r , g , b ) ;
}
void InitialiseLondonBoss ( short item_number )
{
SHIELD_POINTS * shptr ;
long lp , lp1 , angle , y ;
bossdata . explode_count = 0 ;
bossdata . ring_count = 0 ;
bossdata . dead = 0 ;
bossdata . dropped_icon = 0 ;
shptr = & LondonBossShield [ 0 ] ;
for ( lp = 0 ; lp < 5 ; lp + + )
{
y = heights [ lp ] ;
angle = 0 ;
for ( lp1 = 0 ; lp1 < 8 ; lp1 + + )
{
shptr - > x = ( rcossin_tbl [ angle < < 1 ] * radii [ lp ] ) > > 11 ;
shptr - > y = y ;
shptr - > z = ( rcossin_tbl [ ( angle < < 1 ) + 1 ] * radii [ lp ] ) > > 11 ;
shptr - > rgb = 0 ; // rgb.
angle + = 512 ;
shptr + + ;
}
}
}
void LondonBossControl ( short item_number )
{
if ( ! CreatureActive ( item_number ) )
return ;
ITEM_INFO * item , * enemy ;
CREATURE_INFO * londonboss ;
short angle , head , tilt , lp , torso_y , torso_x ;
int lara_dx , lara_dz , lara_dy ;
AI_INFO info , lara_info ;
PHD_VECTOR pos1 , trident [ 3 ] ;
item = & Items [ item_number ] ;
londonboss = ( CREATURE_INFO * ) item - > data ;
head = angle = tilt = torso_x = torso_y = 0 ;
if ( item - > itemFlags [ 2 ] )
{
if ( item - > itemFlags [ 2 ] = = 1 )
item - > hitPoints = 0 ;
if ( item - > itemFlags [ 2 ] > = 12 )
TriggerDynamicLight ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , ( GetRandomControl ( ) & 3 ) + 8 , 0 , ( GetRandomControl ( ) & 7 ) + 8 , ( GetRandomControl ( ) & 7 ) + 16 ) ;
else
TriggerDynamicLight ( item - > pos . xPos , item - > pos . yPos , item - > pos . zPos , 25 - ( item - > itemFlags [ 2 ] < < 1 ) + ( GetRandomControl ( ) & 1 ) , ( 16 - item - > itemFlags [ 2 ] ) + ( GetRandomControl ( ) & 7 ) , 32 - item - > itemFlags [ 2 ] , 31 ) ;
}
for ( lp = 0 ; lp < 3 ; lp + + )
{
trident [ lp ] . x = londonboss_points [ lp ] . x ;
trident [ lp ] . y = londonboss_points [ lp ] . y ;
trident [ lp ] . z = londonboss_points [ lp ] . z ;
GetJointAbsPosition ( item , & trident [ lp ] , londonboss_points [ lp ] . meshNum ) ;
}
if ( item - > hitPoints < = 0 )
{
if ( item - > currentAnimState ! = LONDONBOSS_DEATH )
{
item - > animNumber = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_DIE_ANIM ;
item - > frameNumber = Anims [ item - > animNumber ] . frameBase ;
item - > currentAnimState = LONDONBOSS_DEATH ;
}
if ( Anims [ item - > animNumber ] . frameEnd - item - > frameNumber = = 1 )
{
item - > frameNumber = Anims [ item - > animNumber ] . frameEnd - 1 ;
item - > meshBits = 0 ; // Don't draw any of the boss while I'm killing it.
if ( bossdata . explode_count = = 0 )
{
bossdata . ring_count = 0 ;
for ( lp = 0 ; lp < 6 ; lp + + )
{
ExpRings [ lp ] . on = false ;
ExpRings [ lp ] . life = 32 ;
ExpRings [ lp ] . radius = 512 ;
ExpRings [ lp ] . speed = 128 + ( lp < < 5 ) ;
ExpRings [ lp ] . xrot = ( ( GetRandomControl ( ) & 511 ) - 256 ) < < 4 ;
ExpRings [ lp ] . zrot = ( ( GetRandomControl ( ) & 511 ) - 256 ) < < 4 ;
}
if ( bossdata . dropped_icon = = false )
{
//BossDropIcon(item_number);
bossdata . dropped_icon = true ;
}
}
if ( bossdata . explode_count < 256 )
bossdata . explode_count + + ;
if ( bossdata . explode_count > 128 & & bossdata . ring_count = = 6 & & ExpRings [ 5 ] . life = = 0 )
{
LondonBossDie ( item_number ) ;
bossdata . dead = true ;
}
else
{
ExplodeLondonBoss ( item ) ;
}
return ;
}
}
else
{
if ( item - > aiBits )
GetAITarget ( londonboss ) ;
CreatureAIInfo ( item , & info ) ;
if ( londonboss - > enemy = = LaraItem )
{
lara_info . angle = info . angle ;
lara_info . distance = info . distance ;
lara_info . xAngle = info . xAngle ;
}
else
{
lara_dz = LaraItem - > pos . zPos - item - > pos . zPos ;
lara_dx = LaraItem - > pos . xPos - item - > pos . xPos ;
lara_dy = item - > pos . yPos - LaraItem - > pos . yPos ;
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 ;
if ( abs ( lara_dx ) > abs ( lara_dz ) )
lara_info . xAngle = ATAN ( abs ( lara_dx ) + ( abs ( lara_dz ) > > 1 ) , lara_dy ) ;
else
lara_info . xAngle = ATAN ( abs ( lara_dz ) + ( abs ( lara_dx ) > > 1 ) , lara_dy ) ;
2019-12-05 17:35:57 +01:00
2019-12-02 14:49:19 +01:00
}
GetCreatureMood ( item , & info , VIOLENT ) ;
CreatureMood ( item , & info , VIOLENT ) ;
angle = CreatureTurn ( item , londonboss - > maximumTurn ) ;
enemy = londonboss - > enemy ; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things
londonboss - > enemy = LaraItem ;
if ( item - > hitStatus | | lara_info . distance < LONDONBOSS_AWARE_DISTANCE | | TargetVisible ( item , & lara_info ) | | LaraItem - > pos . yPos < item - > pos . yPos )
AlertAllGuards ( item_number ) ;
londonboss - > enemy = enemy ;
if ( LaraItem - > pos . yPos < item - > pos . yPos )
londonboss - > hurtByLara = true ;
if ( item - > timer > 0 )
item - > timer - - ;
item - > hitPoints = 300 ;
switch ( item - > currentAnimState )
{
case LONDONBOSS_LAUGH :
if ( abs ( lara_info . angle ) < LONDONBOSS_WALK_TURN )
item - > pos . yRot + = lara_info . angle ;
else if ( lara_info . angle < 0 )
item - > pos . yRot - = LONDONBOSS_WALK_TURN ;
else
item - > pos . yRot + = LONDONBOSS_WALK_TURN ;
if ( londonboss - > alerted )
{
item - > goalAnimState = LONDONBOSS_STAND ;
break ;
}
break ;
case LONDONBOSS_STAND :
londonboss - > flags = 0 ;
londonboss - > maximumTurn = 0 ;
if ( londonboss - > reachedGoal ) //She's found this ambush point, so set up the next one
{
londonboss - > reachedGoal = false ;
item - > aiBits | = AMBUSH ;
item - > itemFlags [ 3 ] + = 0x2000 ;
}
head = lara_info . angle ;
if ( item - > aiBits & GUARD )
{
if ( ( head < - 0x3000 | | head > 0x3000 ) & & item - > pos . yPos > LONDONBOSS_FINAL_HEIGHT )
{
item - > goalAnimState = LONDONBOSS_WALK ;
londonboss - > maximumTurn = LONDONBOSS_WALK_TURN ;
}
break ;
head = AIGuard ( londonboss ) ;
if ( ! ( GetRandomControl ( ) & 0xF ) )
item - > goalAnimState = LONDONBOSS_LAUGH ;
break ;
}
else if ( ( item - > pos . yPos < = LONDONBOSS_FINAL_HEIGHT | | item - > pos . yPos < LaraItem - > pos . yPos ) & & ! ( GetRandomControl ( ) & 0xF ) & & ! bossdata . charged & & item - > timer )
{
item - > goalAnimState = LONDONBOSS_LAUGH ;
}
else if ( londonboss - > reachedGoal | | LaraItem - > pos . yPos > item - > pos . yPos | | item - > pos . yPos < = LONDONBOSS_FINAL_HEIGHT )
{
if ( bossdata . charged )
item - > goalAnimState = LONDONBOSS_BIGZAP ;
else if ( ! item - > timer )
item - > goalAnimState = LONDONBOSS_SUMMON ;
else
item - > goalAnimState = LONDONBOSS_LILZAP ;
}
else if ( item - > aiBits & PATROL1 )
{
item - > goalAnimState = LONDONBOSS_WALK ;
}
else if ( londonboss - > mood = = ESCAPE_MOOD | | item - > pos . yPos > LaraItem - > pos . yPos )
{
item - > goalAnimState = LONDONBOSS_RUN ;
}
else if ( londonboss - > mood = = BORED_MOOD | | ( ( item - > aiBits & FOLLOW ) & & ( londonboss - > reachedGoal | | lara_info . distance > SQUARE ( WALL_SIZE * 2 ) ) ) )
{
if ( item - > requiredAnimState )
item - > goalAnimState = item - > requiredAnimState ;
else if ( info . ahead )
item - > goalAnimState = LONDONBOSS_STAND ;
else
item - > goalAnimState = LONDONBOSS_RUN ;
}
else if ( info . bite & & info . distance < LONDONBOSS_WALK_RANGE )
item - > goalAnimState = LONDONBOSS_WALK ;
else
item - > goalAnimState = LONDONBOSS_RUN ;
break ;
case LONDONBOSS_WALK :
head = lara_info . angle ;
londonboss - > flags = 0 ;
londonboss - > maximumTurn = LONDONBOSS_WALK_TURN ;
if ( item - > aiBits & GUARD | | ( londonboss - > reachedGoal & & ! ( item - > aiBits & FOLLOW ) ) )
{
}
else if ( item - > aiBits & PATROL1 )
{
item - > goalAnimState = LONDONBOSS_WALK ;
head = 0 ;
}
else if ( londonboss - > mood = = ESCAPE_MOOD )
{
item - > goalAnimState = LONDONBOSS_RUN ;
}
else if ( londonboss - > mood = = BORED_MOOD )
{
if ( GetRandomControl ( ) < LONDONBOSS_LAUGH_CHANCE )
{
item - > requiredAnimState = LONDONBOSS_LAUGH ;
item - > goalAnimState = LONDONBOSS_STAND ;
}
}
else if ( info . distance > LONDONBOSS_WALK_RANGE )
{
item - > goalAnimState = LONDONBOSS_RUN ;
}
break ;
case LONDONBOSS_RUN :
if ( info . ahead )
head = info . angle ;
londonboss - > maximumTurn = LONDONBOSS_RUN_TURN ;
tilt = angle / 2 ;
if ( item - > aiBits & GUARD | | ( londonboss - > reachedGoal & & ! ( item - > aiBits & FOLLOW ) ) )
item - > goalAnimState = LONDONBOSS_STAND ;
else if ( londonboss - > mood = = ESCAPE_MOOD )
break ;
else if ( ( item - > aiBits & FOLLOW ) & & ( londonboss - > reachedGoal | | lara_info . distance > SQUARE ( WALL_SIZE * 2 ) ) )
item - > goalAnimState = LONDONBOSS_STAND ;
else if ( londonboss - > mood = = BORED_MOOD )
item - > goalAnimState = LONDONBOSS_WALK ;
else if ( info . ahead & & info . distance < LONDONBOSS_WALK_RANGE )
item - > goalAnimState = LONDONBOSS_WALK ;
break ;
case LONDONBOSS_SUMMON :
head = lara_info . angle ;
if ( londonboss - > reachedGoal ) //She's found this ambush point, so set up the next one
{
londonboss - > reachedGoal = false ;
item - > aiBits = AMBUSH ;
item - > itemFlags [ 3 ] + = 0x2000 ;
}
if ( item - > animNumber = = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_STND2SUM_ANIM )
{
if ( item - > frameNumber = = Anims [ item - > animNumber ] . frameBase )
{
bossdata . hp_counter = item - > hitPoints ;
item - > timer = BIGZAP_TIMER ;
}
else if ( item - > hitStatus & & item - > goalAnimState ! = LONDONBOSS_STAND ) //if she takes *any* damage during the stand2summon anim, break off the summoning
{
StopSoundEffect ( 352 ) ;
SoundEffect ( 353 , & item - > pos , 0 ) ; // Take Hit
SoundEffect ( 355 , & item - > pos , 0 ) ; // Summon wind-down noise
item - > goalAnimState = LONDONBOSS_STAND ; //Put a condition in here so she can do more than one attack per waypoint?
}
}
else if ( item - > animNumber = = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_SUMMON_ANIM & & item - > frameNumber = = Anims [ item - > animNumber ] . frameEnd )
bossdata . charged = true ;
if ( abs ( lara_info . angle ) < LONDONBOSS_WALK_TURN )
item - > pos . yRot + = lara_info . angle ;
else if ( lara_info . angle < 0 )
item - > pos . yRot - = LONDONBOSS_WALK_TURN ;
else
item - > pos . yRot + = LONDONBOSS_WALK_TURN ;
// Summon.
if ( ( Wibble & 7 ) = = 0 )
{
pos1 . x = item - > pos . xPos ;
pos1 . y = ( GetRandomControl ( ) & 511 ) - 256 ;
pos1 . z = item - > pos . zPos ;
TriggerLaserBolt ( & pos1 , item , SUMMON_BOLT , 0 ) ;
for ( lp = 0 ; lp < 6 ; lp + + )
{
long rnd ;
if ( ! ExpRings [ lp ] . on )
{
ExpRings [ lp ] . on = true ;
ExpRings [ lp ] . life = 64 ;
ExpRings [ lp ] . speed = ( GetRandomControl ( ) & 15 ) + 16 ;
ExpRings [ lp ] . x = item - > pos . xPos ;
ExpRings [ lp ] . y = item - > pos . yPos + 128 - ( rnd = ( GetRandomControl ( ) & 1023 ) ) ;
ExpRings [ lp ] . z = item - > pos . zPos ;
ExpRings [ lp ] . xrot = ( ( GetRandomControl ( ) & 511 ) - 256 ) < < 4 ;
ExpRings [ lp ] . zrot = ( ( GetRandomControl ( ) & 511 ) - 256 ) < < 4 ;
ExpRings [ lp ] . radius = ( 1024 + ( 1024 - ( abs ( rnd - 512 ) ) ) ) ;
break ;
}
}
}
londonboss - > maximumTurn = 0 ;
break ;
case LONDONBOSS_BIGZAP :
if ( londonboss - > reachedGoal ) //She's found this ambush point, so set up the next one
{
londonboss - > reachedGoal = false ;
item - > aiBits = AMBUSH ;
item - > itemFlags [ 3 ] + = 0x2000 ;
}
bossdata . charged = false ;
if ( abs ( lara_info . angle ) < LONDONBOSS_WALK_TURN )
item - > pos . yRot + = lara_info . angle ;
else if ( lara_info . angle < 0 )
item - > pos . yRot - = LONDONBOSS_WALK_TURN ;
else
item - > pos . yRot + = LONDONBOSS_WALK_TURN ;
torso_y = lara_info . angle ;
torso_x = lara_info . xAngle ;
londonboss - > maximumTurn = 0 ;
if ( item - > frameNumber = = Anims [ item - > animNumber ] . frameBase + 36 )
{
TriggerLaserBolt ( & trident [ RIGHT_PRONG ] , item , NORMAL_BOLT , item - > pos . yRot + 0x200 ) ;
TriggerLaserBolt ( & trident [ ICONPOS ] , item , LARGE_BOLT , item - > pos . yRot ) ;
TriggerLaserBolt ( & trident [ LEFT_PRONG ] , item , NORMAL_BOLT , item - > pos . yRot - 0x200 ) ;
}
break ;
case LONDONBOSS_LILZAP :
if ( londonboss - > reachedGoal ) //She's found this ambush point, so set up the next one
{
londonboss - > reachedGoal = false ;
item - > aiBits = AMBUSH ;
item - > itemFlags [ 3 ] + = 0x2000 ;
}
if ( abs ( lara_info . angle ) < LONDONBOSS_WALK_TURN )
item - > pos . yRot + = lara_info . angle ;
else if ( lara_info . angle < 0 )
item - > pos . yRot - = LONDONBOSS_WALK_TURN ;
else
item - > pos . yRot + = LONDONBOSS_WALK_TURN ;
torso_y = lara_info . angle ;
torso_x = lara_info . xAngle ;
londonboss - > maximumTurn = 0 ;
if ( item - > frameNumber = = Anims [ item - > animNumber ] . frameBase + 14 )
{
TriggerLaserBolt ( & trident [ RIGHT_PRONG ] , item , NORMAL_BOLT , item - > pos . yRot + 0x200 ) ;
TriggerLaserBolt ( & trident [ LEFT_PRONG ] , item , NORMAL_BOLT , item - > pos . yRot - 0x200 ) ;
}
break ;
}
}
CreatureTilt ( item , tilt ) ;
CreatureJoint ( item , 0 , torso_y ) ;
CreatureJoint ( item , 1 , torso_x ) ;
CreatureJoint ( item , 2 , head ) ;
if ( ( item - > currentAnimState < LONDONBOSS_VAULT2 | | item - > currentAnimState > LONDONBOSS_GODOWN ) & & item - > currentAnimState ! = LONDONBOSS_DEATH )
{
switch ( CreatureVault ( item_number , angle , 2 , LONDONBOSS_VAULT_SHIFT ) )
{
case 2 :
/* Half block jump */
londonboss - > maximumTurn = 0 ;
item - > animNumber = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_VAULT2_ANIM ;
item - > frameNumber = Anims [ item - > animNumber ] . frameBase ;
item - > currentAnimState = LONDONBOSS_VAULT2 ;
break ;
case 3 :
/* 3/4 block jump */
londonboss - > maximumTurn = 0 ;
item - > animNumber = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_VAULT3_ANIM ;
item - > frameNumber = Anims [ item - > animNumber ] . frameBase ;
item - > currentAnimState = LONDONBOSS_VAULT3 ;
break ;
case 4 :
/* Full block jump */
londonboss - > maximumTurn = 0 ;
item - > animNumber = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_VAULT4_ANIM ;
item - > frameNumber = Anims [ item - > animNumber ] . frameBase ;
item - > currentAnimState = LONDONBOSS_VAULT4 ;
break ;
case - 4 :
/* Full block fall */
londonboss - > maximumTurn = 0 ;
item - > animNumber = Objects [ item - > objectNumber ] . animIndex + LONDONBOSS_GODOWN_ANIM ;
item - > frameNumber = Anims [ item - > animNumber ] . frameBase ;
item - > currentAnimState = LONDONBOSS_GODOWN ;
break ;
}
}
else
{
londonboss - > maximumTurn = 0 ;
CreatureAnimation ( item_number , angle , 0 ) ;
}
// Do light.
{
long g , b ;
g = abs ( rcossin_tbl [ item - > itemFlags [ 1 ] < < 7 ] > > 7 ) ;
g + = ( GetRandomControl ( ) & 7 ) ;
if ( g > 31 )
g = 31 ;
b = g > > 1 ;
TriggerDynamicLight ( trident [ ICONPOS ] . x , trident [ ICONPOS ] . y , trident [ ICONPOS ] . z , 10 , 0 , g > > 1 , b > > 1 ) ;
item - > itemFlags [ 1 ] + + ;
item - > itemFlags [ 1 ] & = 63 ;
}
// Knockback.
if ( item - > hitPoints > 0 & & item - > itemFlags [ 0 ] ! = KNOCKBACK & & LaraItem - > hitPoints > 0 )
{
long dx , dy , dz ;
dx = LaraItem - > pos . xPos - item - > pos . xPos ;
dy = LaraItem - > pos . yPos - 256 - item - > pos . yPos ;
dz = LaraItem - > pos . zPos - item - > pos . zPos ;
if ( dx > 8000 | | dx < - 8000 | | dy > 8000 | | dy < - 8000 | | dz > 8000 | | dz < - 8000 )
{
dx = 0xFFF ;
}
else
{
dx = SQUARE ( dx ) ;
dy = SQUARE ( dy ) ;
dz = SQUARE ( dz ) ;
dx = SQRT_ASM ( dx + dy + dz ) ;
}
if ( dx < 0xB00 )
{
item - > itemFlags [ 0 ] = KNOCKBACK ;
for ( lp = 0 ; lp < 3 ; lp + + )
{
KBRings [ lp ] . on = true ;
KBRings [ lp ] . life = 32 ;
KBRings [ lp ] . speed = 64 + ( ( lp = = 1 ) < < 4 ) ;
KBRings [ lp ] . x = item - > pos . xPos ;
KBRings [ lp ] . y = item - > pos . yPos - 384 - 128 + ( lp < < 7 ) ;
KBRings [ lp ] . z = item - > pos . zPos ;
KBRings [ lp ] . xrot = KBRings [ lp ] . zrot = 0 ;
KBRings [ lp ] . radius = 512 + ( ( lp = = 1 ) < < 8 ) ;
}
}
}
else if ( KBRings [ 0 ] . on = = false & & KBRings [ 1 ] . on = = false & & KBRings [ 2 ] . on = = false )
{
item - > itemFlags [ 0 ] = 0 ;
}
}
void S_DrawLondonBoss ( ITEM_INFO * item )
{
DrawAnimatingItem ( item ) ;
if ( bossdata . explode_count )
{
DrawLondonBossShield ( item ) ;
DrawExplosionRings ( ) ;
}
else
{
DrawSummonRings ( ) ;
DrawKnockBackRings ( ) ;
}
if ( item - > hitPoints < = 0 & & bossdata . explode_count = = 0 )
{
//UpdateElectricityPoints();
//LaraElectricDeath(0, item);
//LaraElectricDeath(1, item);
}
}