mirror of
https://github.com/id-Software/Wolf3D-iOS.git
synced 2024-11-10 07:22:02 +00:00
471 lines
10 KiB
C
471 lines
10 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_actors.c: Wolfenstein3-D actor manager.
|
|
*
|
|
* 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"
|
|
|
|
#include "wolf_act_stat.h"
|
|
|
|
entity_t Guards[ MAX_GUARDS + 1 ], *New;
|
|
W16 NumGuards = 0;
|
|
W8 add8dir[ 9 ] = { 4, 5, 6, 7, 0, 1, 2, 3, 0 };
|
|
W8 r_add8dir[ 9 ]= { 4, 7, 6, 5, 0, 1, 2, 3, 0 };
|
|
|
|
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: A_StateChange -Changes guard's state to that defined in NewState.
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void A_StateChange( entity_t *ent, en_state NewState )
|
|
{
|
|
ent->state = NewState;
|
|
assert( ent->type >= 0 && ent->type < NUMENEMIES );
|
|
if ( NewState == st_remove ) {
|
|
ent->ticcount = 0;
|
|
} else {
|
|
assert( ent->state >= 0 && ent->state < NUMSTATES );
|
|
ent->ticcount = objstate[ ent->type ][ ent->state ].timeout; //0;
|
|
}
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PRIVATE int DoGuard( entity_t *ent ) // FIXME: revise!
|
|
{ // returns 0 if we must remove this Guard from Guards list, otherwise 1;
|
|
think_t think;
|
|
|
|
assert( ent->tilex >= 0 && ent->tilex < 64 );
|
|
assert( ent->tiley >= 0 && ent->tiley < 64 );
|
|
assert( ent->dir >= 0 && ent->dir <= 8 );
|
|
|
|
// ticcounts fire discrete actions separate from think functions
|
|
if ( ent->ticcount ) {
|
|
ent->ticcount -= tics;
|
|
while( ent->ticcount <= 0 )
|
|
{
|
|
assert( ent->type >= 0 && ent->type < NUMENEMIES );
|
|
assert( ent->state >= 0 && ent->state < NUMSTATES );
|
|
think = objstate[ ent->type ][ ent->state ].action; // end of state action
|
|
if( think )
|
|
{
|
|
think( ent );
|
|
if( ent->state == st_remove )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
ent->state = objstate[ ent->type ][ ent->state ].next_state;
|
|
if( ent->state == st_remove )
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
if( ! objstate[ ent->type ][ ent->state ].timeout )
|
|
{
|
|
ent->ticcount = 0;
|
|
break;
|
|
}
|
|
|
|
ent->ticcount += objstate[ ent->type ][ ent->state ].timeout;
|
|
}
|
|
}
|
|
|
|
//
|
|
// think
|
|
//
|
|
assert( ent->type >= 0 && ent->type < NUMENEMIES );
|
|
assert( ent->state >= 0 && ent->state < NUMSTATES );
|
|
think = objstate[ ent->type ][ ent->state ].think;
|
|
if( think )
|
|
{
|
|
think( ent );
|
|
if( ent->state == st_remove )
|
|
{
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PRIVATE void RemoveActor( entity_t *actor )
|
|
{
|
|
Sprite_RemoveSprite( actor->sprite );
|
|
memmove( actor, actor+1, (int)(&Guards[ NumGuards ]) - (int)(actor+1) );
|
|
NumGuards--;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void ProcessGuards( void )
|
|
{
|
|
int n, tex;
|
|
assert( NumGuards < MAX_GUARDS );
|
|
for( n = 0 ; n < NumGuards ; ++n )
|
|
{
|
|
if( ! DoGuard( &Guards[ n ] ) )
|
|
{ // remove guard from the game forever!
|
|
RemoveActor( &Guards[ n-- ] );
|
|
continue;
|
|
}
|
|
|
|
Sprite_SetPos( Guards[ n ].sprite, Guards[ n ].x, Guards[ n ].y, Guards[ n ].angle );
|
|
tex = objstate[ Guards[ n ].type ][ Guards[ n ].state ].texture;
|
|
|
|
if( objstate[ Guards[ n ].type ][ Guards[ n ].state ].rotate )
|
|
{
|
|
if( Guards[ n ].type == en_rocket || Guards[ n ].type == en_hrocket )
|
|
{
|
|
tex += r_add8dir[ Get8dir( angle_wise( FINE2RAD(Player.position.angle), FINE2RAD(Guards[ n ].angle) ) ) ];
|
|
}
|
|
else
|
|
{
|
|
tex += add8dir[ Get8dir( angle_wise( FINE2RAD(Player.position.angle), FINE2RAD(Guards[ n ].angle) ) ) ];
|
|
}
|
|
}
|
|
|
|
Sprite_SetTex( Guards[ n ].sprite, 0, tex );
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function: ResetGuards -Reset actors status
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void ResetGuards( void )
|
|
{
|
|
memset( Guards, 0, sizeof( Guards ) );
|
|
NumGuards = 0;
|
|
New = NULL;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC entity_t *GetNewActor( void )
|
|
{
|
|
if( NumGuards > MAX_GUARDS )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
memset( &Guards[ NumGuards ], 0, sizeof( Guards[ 0 ] ) );
|
|
|
|
return &Guards[ NumGuards++ ];
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC entity_t *SpawnActor( enemy_t which, int x, int y, dir4type dir, LevelData_t *lvl )
|
|
{
|
|
entity_t *new_actor;
|
|
|
|
new_actor = GetNewActor();
|
|
if( ! new_actor )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
new_actor->x = TILE2POS( x );
|
|
new_actor->y = TILE2POS( y );
|
|
|
|
new_actor->tilex = x;
|
|
new_actor->tiley = y;
|
|
|
|
assert( dir >= 0 && dir <= 4 );
|
|
new_actor->angle = dir4angle[ dir ];
|
|
new_actor->dir = dir4to8[ dir ];
|
|
|
|
new_actor->areanumber = lvl->areas[ x ][ y ];
|
|
// Com_Printf( "Actor at %i,%i had areaNum: %i\n", x, y, new_actor->areanumber );
|
|
if ( new_actor->areanumber < 0 ) {
|
|
// ambush marker tiles are listed as -3 area
|
|
new_actor->areanumber = 0;
|
|
}
|
|
|
|
assert( new_actor->areanumber >= 0 && new_actor->areanumber < NUMAREAS );
|
|
new_actor->type = which;
|
|
|
|
new_actor->health = starthitpoints[ (int)skill->value ][ which ];
|
|
new_actor->sprite = Sprite_GetNewSprite();
|
|
|
|
return new_actor;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void SpawnStand( enemy_t which, int x, int y, int dir, LevelData_t *lvl )
|
|
{
|
|
entity_t *self;
|
|
|
|
self = SpawnActor( which, x, y, dir, r_world );
|
|
if( ! self )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self->state = st_stand;
|
|
self->speed = SPDPATROL;
|
|
self->ticcount = objstate[ which ][ st_stand ].timeout ? US_RndT() % objstate[ which ][ st_stand ].timeout + 1 : 0;
|
|
self->flags |= FL_SHOOTABLE;
|
|
if( lvl->tilemap[ x ][ y ] & AMBUSH_TILE )
|
|
{
|
|
self->flags |= FL_AMBUSH;
|
|
}
|
|
|
|
levelstate.total_monsters++;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void SpawnPatrol( enemy_t which, int x, int y, int dir )
|
|
{
|
|
entity_t *self;
|
|
|
|
self = SpawnActor( which, x, y, dir, r_world );
|
|
if( ! self )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self->state = st_path1;
|
|
self->speed = (which == en_dog) ? SPDDOG : SPDPATROL;
|
|
self->distance = TILEGLOBAL;
|
|
self->ticcount = objstate[ which ][ st_path1 ].timeout ? US_RndT() % objstate[ which ][ st_path1 ].timeout + 1 : 0;
|
|
self->flags |= FL_SHOOTABLE;
|
|
|
|
levelstate.total_monsters++;
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void SpawnDeadGuard( enemy_t which, int x, int y )
|
|
{
|
|
entity_t *self;
|
|
|
|
self = SpawnActor( which, x, y, dir4_nodir, r_world );
|
|
if( ! self )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self->state = st_dead;
|
|
self->speed = 0;
|
|
self->health = 0;
|
|
self->ticcount = objstate[ which ][ st_dead ].timeout ? US_RndT() % objstate[ which ][ st_dead ].timeout + 1 : 0;
|
|
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void SpawnBoss( enemy_t which, int x, int y )
|
|
{
|
|
entity_t *self;
|
|
dir4type face;
|
|
|
|
switch( which )
|
|
{
|
|
case en_boss:
|
|
case en_schabbs:
|
|
case en_fat:
|
|
case en_hitler:
|
|
face = dir4_south;
|
|
break;
|
|
|
|
case en_fake:
|
|
case en_gretel:
|
|
case en_gift:
|
|
face = dir4_north;
|
|
break;
|
|
|
|
case en_trans:
|
|
case en_uber:
|
|
case en_will:
|
|
case en_death:
|
|
case en_angel:
|
|
case en_spectre:
|
|
face = dir4_nodir;
|
|
break;
|
|
|
|
default:
|
|
face = dir4_nodir;
|
|
break;
|
|
}
|
|
|
|
self = SpawnActor( which, x, y, face, r_world );
|
|
if( ! self )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self->state = which == en_spectre ? st_path1 : st_stand;
|
|
self->speed = SPDPATROL;
|
|
self->health = starthitpoints[ (int)skill->value ][ which ];
|
|
self->ticcount = objstate[ which ][ st_stand ].timeout ? US_RndT() % objstate[ which ][ st_stand ].timeout + 1 : 0;
|
|
self->flags |= FL_SHOOTABLE | FL_AMBUSH;
|
|
|
|
levelstate.total_monsters++;
|
|
|
|
}
|
|
|
|
/*
|
|
-----------------------------------------------------------------------------
|
|
Function:
|
|
|
|
Parameters:
|
|
|
|
Returns:
|
|
|
|
Notes:
|
|
-----------------------------------------------------------------------------
|
|
*/
|
|
PUBLIC void SpawnGhosts( enemy_t which, int x, int y )
|
|
{
|
|
entity_t *self;
|
|
|
|
self = SpawnActor( which, x, y, dir4_nodir, r_world );
|
|
if( ! self )
|
|
{
|
|
return;
|
|
}
|
|
|
|
self->state = st_chase1;
|
|
self->speed = SPDPATROL * 3;
|
|
self->health = starthitpoints[ (int)skill->value ][ which ];
|
|
self->ticcount = objstate[ which ][ st_chase1 ].timeout ? US_RndT() % objstate[ which ][ st_chase1 ].timeout + 1: 0;
|
|
self->flags |= FL_AMBUSH;
|
|
|
|
levelstate.total_monsters++;
|
|
}
|