wolf3d-ios/wolf3d/newCode/wolf/wolf_actor_ai.c

969 lines
22 KiB
C

/*
Copyright (C) 2004 Michael Liebscher
Copyright (C) 2001 by DarkOne the Hacker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
/*
* wolf_actor_ai.c: Wolfenstein3-D artificial intelligence.
*
* Author: Michael Liebscher <johnnycanuck@users.sourceforge.net>
* Date: 2004
*
* Acknowledgement:
* This code was derived from NewWolf, and was originally
* written by DarkOne the Hacker.
*
*/
#include "../wolfiphone.h"
const char dsounds[ 7 ][ 32 ] =
{
"sfx/025.wav",
"sfx/026.wav",
"sfx/086.wav",
"sfx/088.wav",
"sfx/105.wav",
"sfx/107.wav",
"sfx/109.wav"
};
const char dsodsounds[ 7 ][ 32 ] =
{
"sfx/021.wav",
"sfx/022.wav",
"sfx/052.wav",
"sfx/054.wav",
"sfx/057.wav",
"sfx/059.wav",
"sfx/061.wav"
};
/*
-----------------------------------------------------------------------------
Function: A_DeathScream() -Do a death scream sound depending on actor type.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_DeathScream( entity_t *self )
{
switch( self->type )
{
case en_mutant:
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/033.wav" ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/037.wav" ), 1, ATTN_NORM, 0 );
}
break;
case en_guard:
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( dsodsounds[ US_RndT() % 6 ] ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( dsounds[ US_RndT() % 6 ] ), 1, ATTN_NORM, 0 );
}
break;
case en_officer:
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/046.wav" ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/074.wav" ), 1, ATTN_NORM, 0 );
}
break;
case en_ss:
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/035.wav" ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/046.wav" ), 1, ATTN_NORM, 0 );
}
break;
case en_dog:
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/031.wav" ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/035.wav" ), 1, ATTN_NORM, 0 );
}
break;
case en_boss:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/019.wav" ), 1, ATTN_NORM, 0 );
break;
case en_schabbs:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/061.wav" ), 1, ATTN_NORM, 0 );
break;
case en_fake:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/069.wav" ), 1, ATTN_NORM, 0 );
break;
case en_mecha:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/084.wav" ), 1, ATTN_NORM, 0 );
break;
case en_hitler:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/044.wav" ), 1, ATTN_NORM, 0 );
break;
case en_gretel:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/115.wav" ), 1, ATTN_NORM, 0 );
break;
case en_gift:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/091.wav" ), 1, ATTN_NORM, 0 );
break;
case en_fat:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/119.wav" ), 1, ATTN_NORM, 0 );
break;
case en_spectre:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "lsfx/062.wav" ), 1, ATTN_NORM, 0 );
break;
case en_angel:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/098.wav" ), 1, ATTN_NORM, 0 );
break;
case en_trans:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/070.wav" ), 1, ATTN_NORM, 0 );
break;
case en_uber:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/082.wav" ), 1, ATTN_NORM, 0 );
break;
case en_will:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/072.wav" ), 1, ATTN_NORM, 0 );
break;
case en_death:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/090.wav" ), 1, ATTN_NORM, 0 );
break;
}
}
/*
-----------------------------------------------------------------------------
Function: A_FirstSighting() -Puts an actor into attack mode and possibly
reverses the direction if the player is
behind it.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_FirstSighting( entity_t *self )
{
switch( self->type )
{
case en_guard:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/001.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_officer:
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/043.wav" ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/071.wav" ), 1, ATTN_NORM, 0 );
}
self->speed *= 5; // go faster when chasing player
break;
case en_mutant:
self->speed *= 3; // go faster when chasing player
break;
case en_ss:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/015.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 4; // go faster when chasing player
break;
case en_dog:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/002.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 2; // go faster when chasing player
break;
case en_boss:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/017.wav" ), 1, ATTN_NORM, 0 );
self->speed = SPDPATROL * 3; // go faster when chasing player
break;
case en_gretel:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/112.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_gift:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/096.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_fat:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/102.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_schabbs:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/065.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_fake:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/054.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_mecha:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/040.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 3; // go faster when chasing player
break;
case en_hitler:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/040.wav" ), 1, ATTN_NORM, 0 );
self->speed *= 5; // go faster when chasing player
break;
case en_blinky:
case en_clyde:
case en_pinky:
case en_inky:
self->speed *= 2; // go faster when chasing player
break;
//
// Spear of Destiny
//
case en_spectre:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "lsfx/003.wav" ), 1, ATTN_NORM, 0 );
self->speed = 800; // go faster when chasing player
break;
case en_angel:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/095.wav" ), 1, ATTN_NORM, 0 );
self->speed = 1536; // go faster when chasing player
break;
case en_trans:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/066.wav" ), 1, ATTN_NORM, 0 );
self->speed = 1536; // go faster when chasing player
break;
case en_uber:
self->speed = 3000; // go faster when chasing player
break;
case en_will:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/073.wav" ), 1, ATTN_NORM, 0 );
self->speed = 2048; // go faster when chasing player
break;
case en_death:
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/085.wav" ), 1, ATTN_NORM, 0 );
self->speed = 2048; // go faster when chasing player
break;
default:
return;
}
A_StateChange( self, st_chase1 );
if( self->waitfordoorx )
{
self->waitfordoorx = self->waitfordoory = 0; // ignore the door opening command
}
self->dir = dir8_nodir;
self->flags |= FL_ATTACKMODE | FL_FIRSTATTACK;
}
/*
-----------------------------------------------------------------------------
Function: A_KillActor() -Actor has been killed, so give points and spawn
powerups.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE void A_KillActor( entity_t *self )
{
int tilex, tiley;
tilex = self->tilex = self->x >> TILESHIFT; // drop item on center
tiley = self->tiley = self->y >> TILESHIFT;
switch( self->type )
{
case en_guard:
PL_GivePoints( &Player, 100 );
Powerup_Spawn( tilex, tiley, pow_clip2, r_world );
break;
case en_officer:
PL_GivePoints( &Player, 400 );
Powerup_Spawn( tilex, tiley, pow_clip2, r_world );
break;
case en_mutant:
PL_GivePoints( &Player, 700 );
Powerup_Spawn( tilex, tiley, pow_clip2, r_world );
break;
case en_ss:
PL_GivePoints( &Player, 500 );
if( Player.items & ITEM_WEAPON_3 ) // have a schmeiser?
{
Powerup_Spawn( tilex, tiley, pow_clip2, r_world );
}
else
{
Powerup_Spawn( tilex, tiley, pow_machinegun, r_world );
}
break;
case en_dog:
PL_GivePoints( &Player, 200 );
break;
case en_boss:
PL_GivePoints( &Player, 5000 );
Powerup_Spawn( tilex, tiley, pow_key1, r_world );
break;
case en_gretel:
PL_GivePoints( &Player, 5000 );
Powerup_Spawn( tilex, tiley, pow_key1, r_world );
break;
case en_gift:
PL_GivePoints( &Player, 5000 );
A_StartDeathCam( self );
break;
case en_fat:
PL_GivePoints( &Player, 5000 );
A_StartDeathCam( self );
break;
case en_schabbs:
PL_GivePoints( &Player, 5000 );
A_DeathScream( self );
A_StartDeathCam( self );
break;
case en_fake:
PL_GivePoints( &Player, 2000 );
break;
case en_mecha:
PL_GivePoints( &Player, 5000 );
break;
case en_hitler:
PL_GivePoints( &Player, 5000 );
A_DeathScream( self );
A_StartDeathCam( self );
break;
case en_spectre:
PL_GivePoints( &Player, 200 );
break;
case en_angel:
PL_GivePoints( &Player, 5000 );
break;
case en_trans:
PL_GivePoints( &Player, 5000 );
Powerup_Spawn( tilex, tiley, pow_key1, r_world );
break;
case en_uber:
PL_GivePoints( &Player, 5000 );
Powerup_Spawn( tilex, tiley, pow_key1, r_world );
break;
case en_will:
PL_GivePoints( &Player, 5000 );
Powerup_Spawn( tilex, tiley, pow_key1, r_world );
break;
case en_death:
PL_GivePoints( &Player, 5000 );
Powerup_Spawn( tilex, tiley, pow_key1, r_world );
break;
}
A_StateChange( self, st_die1 );
if ( ++levelstate.killed_monsters == levelstate.total_monsters ) {
iphoneSetNotifyText( "You killed the last enemy!" );
}
self->flags &= ~FL_SHOOTABLE;
self->flags |= FL_NONMARK;
}
/*
-----------------------------------------------------------------------------
Function: A_DamageActor() -Called when the player succesfully hits an enemy.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
Does damage points to enemy ob, either putting it into a stun frame or
killing it.
-----------------------------------------------------------------------------
*/
PUBLIC void A_DamageActor( entity_t *self, int damage )
{
Player.madenoise = 1;
// do double damage if shooting a non attack mode actor
if( ! (self->flags & FL_ATTACKMODE) )
{
damage <<= 1;
}
self->health -= damage;
if( self->health <= 0 )
{
A_KillActor( self );
}
else
{
if( ! (self->flags & FL_ATTACKMODE) )
{
A_FirstSighting( self ); // put into combat mode
}
switch( self->type ) // dogs only have one hit point
{
case en_guard:
case en_officer:
case en_mutant:
case en_ss:
if( self->health & 1 )
{
A_StateChange( self, st_pain );
}
else
{
A_StateChange( self, st_pain1 );
}
break;
}
}
}
///////////////////////////
//
// Hitler
//
///////////////////////////
/*
-----------------------------------------------------------------------------
Function: A_MechaSound -Play Mecha sound.
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_MechaSound( entity_t *self )
{
if( areabyplayer[ self->areanumber ] )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "sfx/080.wav" ), 1, ATTN_NORM, 0 );
}
}
/*
-----------------------------------------------------------------------------
Function: A_Slurpie -Play Slurpie sound.
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_Slurpie( entity_t *self )
{
Sound_StartSound( NULL, 1, CHAN_VOICE, Sound_RegisterSound( "lsfx/061.wav" ), 1, ATTN_NORM, 0 );
}
/*
-----------------------------------------------------------------------------
Function: A_HitlerMorph() -Spawn new actor, when Mecha Hitler is dead.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_HitlerMorph( entity_t *self )
{
int hitpoints[ 4 ] = { 500, 700, 800, 900 };
entity_t *hitler;
hitler = GetNewActor();
if( ! hitler )
{
return;
}
hitler->x = self->x;//
hitler->y = self->y;//
hitler->distance = self->distance;
hitler->tilex = self->tilex;//
hitler->tiley = self->tiley;//
hitler->angle = self->angle;//
hitler->dir = self->dir;//
hitler->health = hitpoints[ (int)skill->value ];
hitler->areanumber = self->areanumber;
hitler->state = st_chase1;//
hitler->type = en_hitler; //
hitler->speed = SPDPATROL * 5;//
hitler->ticcount = 0;//
hitler->flags=self->flags | FL_SHOOTABLE; //
hitler->sprite = Sprite_GetNewSprite();
if ( ++levelstate.killed_monsters == levelstate.total_monsters ) {
iphoneSetNotifyText( "You killed the last enemy!" );
}
}
///////////////////////////
//
// Angel of Death
//
///////////////////////////
/*
Angel can't shoot more then 3 sparks in a row.
It will get tired!
*/
PRIVATE int angel_temp = 0;
//
/*
-----------------------------------------------------------------------------
Function: A_Breathing -Play Angel of Death Breathing sound.
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_Breathing( entity_t *self )
{
Sound_StartSound( NULL, 0, CHAN_VOICE, Sound_RegisterSound( "lsfx/080.wav" ), 1, ATTN_NORM, 0 );
}
/*
-----------------------------------------------------------------------------
Function:
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_StartAttack( entity_t *self )
{
angel_temp = 0;
}
/*
-----------------------------------------------------------------------------
Function:
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_Relaunch( entity_t *self )
{
if( ++angel_temp == 3 )
{
A_StateChange( self, st_pain );
return;
}
if( US_RndT() & 1 )
{
A_StateChange( self, st_chase1 );
return;
}
}
/*
-----------------------------------------------------------------------------
Function:
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_Victory( entity_t *self )
{
iphoneStartIntermission( 0 );
}
/*
-----------------------------------------------------------------------------
Function: A_Dormant() -Entity is dormant state.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_Dormant( entity_t *self )
{
int deltax, deltay;
int xl, xh, yl, yh, x, y, n;
deltax = self->x - Player.position.origin[ 0 ];
if( deltax < -MINACTORDIST || deltax > MINACTORDIST )
{
goto moveok;
}
deltay = self->y - Player.position.origin[ 1 ];
if( deltay < -MINACTORDIST || deltay > MINACTORDIST )
{
goto moveok;
}
return;
moveok:
xl = (self->x - MINDIST) >> TILESHIFT;
xh = (self->x + MINDIST) >> TILESHIFT;
yl = (self->y - MINDIST) >> TILESHIFT;
yh = (self->y + MINDIST) >> TILESHIFT;
for( y = yl ; y <= yh ; ++y )
for( x = xl ; x <= xh ; ++x )
{
if( r_world->tilemap[ x ][ y ] & SOLID_TILE )
{
return;
}
for( n = 0 ; n < NumGuards ; ++n )
{
if( Guards[ n ].state >= st_die1 )
{
continue;
}
if( Guards[ n ].tilex == x && Guards[ n ].tiley == y )
{
return; // another guard in path
}
}
}
self->flags |= FL_AMBUSH | FL_SHOOTABLE;
self->flags &= ~FL_ATTACKMODE;
self->dir = dir8_nodir;
A_StateChange( self, st_path1 );
}
/*
-----------------------------------------------------------------------------
Function:
Parameters:
Returns:
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_StartDeathCam( entity_t *self )
{
// the DeathCam feature isn't implimented, but we want to give the animation time
// to play before declaring victory.
iphoneStartIntermission( 50 );
}
/*
-----------------------------------------------------------------------------
Function: A_Smoke() -Rockets emmit smoke.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void A_Smoke( entity_t *self )
{
entity_t *smoke;
smoke = GetNewActor();
if( ! smoke )
{
return;
}
smoke->x = self->x;
smoke->y = self->y;
smoke->tilex = self->tilex;
smoke->tiley = self->tiley;
smoke->state = st_die1;
smoke->type = (self->type==en_hrocket) ? en_hsmoke : en_smoke;
smoke->ticcount = 6;
smoke->flags = FL_NEVERMARK;
smoke->sprite = Sprite_GetNewSprite();
}
/*
-----------------------------------------------------------------------------
Function: ProjectileTryMove() -Called when projectile is airborne.
Parameters: self -[in] Valid Pointer to an entity_t structure.
lvl -[in] Valid Pointer to LevelData_t structure.
Returns: true if move ok, otherwise false.
Notes:
-----------------------------------------------------------------------------
*/
PRIVATE _boolean ProjectileTryMove( entity_t *self, LevelData_t *lvl )
{
#define PROJSIZE 0x2000
int xl, yl, xh, yh, x, y;
xl = (self->x - PROJSIZE) >> TILESHIFT;
yl = (self->y - PROJSIZE) >> TILESHIFT;
xh = (self->x + PROJSIZE) >> TILESHIFT;
yh = (self->y + PROJSIZE) >> TILESHIFT;
// Checking for solid walls:
for( y = yl ; y <= yh ; ++y )
{
for( x = xl ; x <= xh ; ++x )
{
// FIXME: decide what to do with statics & Doors!
if( lvl->tilemap[ x ][ y ] & (WALL_TILE | BLOCK_TILE) )
{
return false;
}
if( lvl->tilemap[ x ][ y ] & DOOR_TILE )
{
if( Door_Opened( &lvl->Doors, x, y ) != DOOR_FULLOPEN )
{
return false;
}
}
}
}
// FIXME: Projectile will fly through objects (even guards & columns) - must fix to create rocket launcher!
return true;
}
/*
-----------------------------------------------------------------------------
Function: T_Projectile() -Called when projectile is airborne.
Parameters: self -[in] Valid Pointer to an entity_t structure.
Returns: Nothing.
Notes:
-----------------------------------------------------------------------------
*/
PUBLIC void T_Projectile( entity_t *self )
{
#define PROJECTILESIZE 0xC000
int deltax, deltay, speed, damage;
speed = self->speed * tics;
deltax = (int)(speed * CosTable[ self->angle ]);
deltay = (int)(speed * SinTable[ self->angle ]);
if( deltax > TILEGLOBAL )
{
deltax = TILEGLOBAL;
}
if( deltax < -TILEGLOBAL )
{
deltax = -TILEGLOBAL; // my
}
if( deltay > TILEGLOBAL)
{
deltay = TILEGLOBAL;
}
if( deltay < -TILEGLOBAL)
{
deltay = -TILEGLOBAL; // my
}
self->x += deltax;
self->y += deltay;
deltax = ABS( self->x-Player.position.origin[ 0 ] );
deltay = ABS( self->y-Player.position.origin[ 1 ] );
if( ! ProjectileTryMove( self, r_world ) )
{
if( self->type == en_rocket || self->type == en_hrocket )
{ // rocket ran into obstacle, draw explosion!
if( g_version->value == SPEAROFDESTINY )
{
Sound_StartSound( NULL, 1, CHAN_WEAPON, Sound_RegisterSound( "lsfx/001.wav" ), 1, ATTN_NORM, 0 );
}
else
{
Sound_StartSound( NULL, 1, CHAN_WEAPON, Sound_RegisterSound( "lsfx/086.wav" ), 1, ATTN_NORM, 0 );
}
A_StateChange( self, st_die1 );
}
else
{
A_StateChange( self, st_remove ); // mark for removal
}
return;
}
if( deltax < PROJECTILESIZE && deltay < PROJECTILESIZE )
{ // hit the player
switch( self->type )
{
case en_needle:
damage = (US_RndT() >> 3) + 20;
break;
case en_rocket:
case en_hrocket:
case en_spark:
damage = (US_RndT()>>3) + 30;
break;
case en_fire:
damage = (US_RndT() >> 3);
break;
default:
damage = 0;
break;
}
PL_Damage( &Player, self, damage );
A_StateChange( self, st_remove ); // mark for removal
return;
}
self->tilex = self->x >> TILESHIFT;
self->tiley = self->y >> TILESHIFT;
}