Find file
Fetching contributors…
Cannot retrieve contributors at this time
2547 lines (2101 sloc) 39 KB
#include "wl_def.h"
/*
=============================================================================
LOCAL CONSTANTS
=============================================================================
*/
#define PROJECTILESIZE 0xc000l
#define BJRUNSPEED 2048
#define BJJUMPSPEED 680
/*
=============================================================================
LOCAL VARIABLES
=============================================================================
*/
static const myshort starthitpoints[4][NUMENEMIES] =
//
// BABY MODE
//
{
{25, // guards
50, // officer
100, // SS
1, // dogs
850, // Hans
850, // Schabbs
200, // fake hitler
800, // mecha hitler
45, // mutants
25, // ghosts
25, // ghosts
25, // ghosts
25, // ghosts
850, // Gretel
850, // Gift
850, // Fat
5, // en_spectre,
1450, // en_angel,
850, // en_trans,
1050, // en_uber,
950, // en_will,
1250 // en_death
},
//
// DON'T HURT ME MODE
//
{25, // guards
50, // officer
100, // SS
1, // dogs
950, // Hans
950, // Schabbs
300, // fake hitler
950, // mecha hitler
55, // mutants
25, // ghosts
25, // ghosts
25, // ghosts
25, // ghosts
950, // Gretel
950, // Gift
950, // Fat
10, // en_spectre,
1550, // en_angel,
950, // en_trans,
1150, // en_uber,
1050, // en_will,
1350 // en_death
},
//
// BRING 'EM ON MODE
//
{25, // guards
50, // officer
100, // SS
1, // dogs
1050, // Hans
1550, // Schabbs
400, // fake hitler
1050, // mecha hitler
55, // mutants
25, // ghosts
25, // ghosts
25, // ghosts
25, // ghosts
1050, // Gretel
1050, // Gift
1050, // Fat
15, // en_spectre,
1650, // en_angel,
1050, // en_trans,
1250, // en_uber,
1150, // en_will,
1450 // en_death
},
//
// DEATH INCARNATE MODE
//
{25, // guards
50, // officer
100, // SS
1, // dogs
1200, // Hans
2400, // Schabbs
500, // fake hitler
1200, // mecha hitler
65, // mutants
25, // ghosts
25, // ghosts
25, // ghosts
25, // ghosts
1200, // Gretel
1200, // Gift
1200, // Fat
25, // en_spectre,
2000, // en_angel,
1200, // en_trans,
1400, // en_uber,
1300, // en_will,
1600 // en_death
}};
/*
=================
=
= A_Smoke
=
=================
*/
void A_Smoke(objtype *ob)
{
GetNewActor();
#ifdef SPEAR
if (ob->obclass == hrocketobj)
new->state = s_hsmoke1;
else
#endif
new->state = s_smoke1;
new->ticcount = 6;
new->tilex = ob->tilex;
new->tiley = ob->tiley;
new->x = ob->x;
new->y = ob->y;
new->obclass = inertobj;
new->active = ac_yes;
new->flags = FL_NEVERMARK;
}
/*
===================
=
= ProjectileTryMove
=
= returns true if move ok
===================
*/
#define PROJSIZE 0x2000
boolean ProjectileTryMove(objtype *ob)
{
myint xl,yl,xh,yh,x,y;
xl = (ob->x-PROJSIZE) >>TILESHIFT;
yl = (ob->y-PROJSIZE) >>TILESHIFT;
xh = (ob->x+PROJSIZE) >>TILESHIFT;
yh = (ob->y+PROJSIZE) >>TILESHIFT;
/* check for solid walls */
for (y=yl;y<=yh;y++) {
for (x=xl;x<=xh;x++) {
if (solid_actor_at(x, y))
return false;
}
}
return true;
}
/*
=================
=
= T_Projectile
=
=================
*/
void T_Projectile(objtype *ob)
{
long deltax,deltay;
myint damage;
long speed;
speed = (long)ob->speed*tics;
deltax = FixedByFrac(speed,cosfix(ob->angle));
deltay = -FixedByFrac(speed,sinfix(ob->angle));
if (deltax>0x10000l)
deltax = 0x10000l;
if (deltay>0x10000l)
deltay = 0x10000l;
ob->x += deltax;
ob->y += deltay;
deltax = labs(ob->x - player->x);
deltay = labs(ob->y - player->y);
if (!ProjectileTryMove(ob))
{
if (ob->obclass == rocketobj)
{
PlaySoundLocActor(MISSILEHITSND,ob);
ob->state = s_boom1;
}
#ifdef SPEAR
else if (ob->obclass == hrocketobj)
{
PlaySoundLocActor(MISSILEHITSND,ob);
ob->state = s_hboom1;
}
#endif
else
ob->state = s_none; // mark for removal
return;
}
if (deltax < PROJECTILESIZE && deltay < PROJECTILESIZE)
{ // hit the player
switch (ob->obclass)
{
case needleobj:
damage = (US_RndT() >>3) + 20;
break;
case rocketobj:
case hrocketobj:
case sparkobj:
damage = (US_RndT() >>3) + 30;
break;
case fireobj:
damage = (US_RndT() >>3);
break;
default:
return;
}
TakeDamage(damage, ob);
ob->state = s_none; // mark for removal
return;
}
ob->tilex = ob->x >> TILESHIFT;
ob->tiley = ob->y >> TILESHIFT;
}
/*
=============================================================================
GUARD
=============================================================================
*/
/*
===============
=
= SpawnStand
=
===============
*/
void SpawnStand (enemy_t which, myint tilex, myint tiley, myint dir)
{
switch (which)
{
case en_guard:
SpawnNewObj (tilex,tiley,s_grdstand);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_officer:
SpawnNewObj (tilex,tiley,s_ofcstand);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_mutant:
SpawnNewObj (tilex,tiley,s_mutstand);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_ss:
SpawnNewObj (tilex,tiley,s_ssstand);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
default:
break;
}
new->obclass = guardobj+which;
new->hitpoints = starthitpoints[gamestate_difficulty][which];
new->dir = dir*2;
new->flags |= FL_SHOOTABLE;
}
/*
===============
=
= SpawnDeadGuard
=
===============
*/
void SpawnDeadGuard (myint tilex, myint tiley)
{
SpawnNewObj (tilex,tiley,s_grddie4);
new->obclass = inertobj;
}
/*
===============
=
= SpawnPatrol
=
===============
*/
void SpawnPatrol (enemy_t which, myint tilex, myint tiley, myint dir)
{
switch (which)
{
case en_guard:
SpawnNewObj (tilex,tiley,s_grdpath1);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_officer:
SpawnNewObj (tilex,tiley,s_ofcpath1);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_ss:
SpawnNewObj (tilex,tiley,s_sspath1);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_mutant:
SpawnNewObj (tilex,tiley,s_mutpath1);
new->speed = SPDPATROL;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
case en_dog:
SpawnNewObj (tilex,tiley,s_dogpath1);
new->speed = SPDDOG;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
break;
default:
break;
}
new->obclass = guardobj+which;
new->dir = dir*2;
new->hitpoints = starthitpoints[gamestate_difficulty][which];
new->distance = TILEGLOBAL;
new->flags |= FL_SHOOTABLE;
new->active = ac_yes;
clear_actor(new->tilex, new->tiley); // don't use original spot
switch (dir)
{
case 0:
new->tilex++;
break;
case 1:
new->tiley--;
break;
case 2:
new->tilex--;
break;
case 3:
new->tiley++;
break;
}
move_actor(new);
}
/*
==================
=
= A_DeathScream
=
==================
*/
void A_DeathScream (objtype *ob)
{
#ifndef SPEAR
if (mapon==9 && !US_RndT())
#else
if ((mapon==18 || mapon==19) && !US_RndT())
#endif
{
switch(ob->obclass)
{
case mutantobj:
case guardobj:
case officerobj:
case ssobj:
case dogobj:
PlaySoundLocActor(DEATHSCREAM6SND,ob);
return;
default:
break;
}
}
switch (ob->obclass)
{
case mutantobj:
PlaySoundLocActor(AHHHGSND, ob);
break;
case guardobj:
{
#ifdef ENABLE_AUDIO
#ifndef UPLOAD
myint sounds[8]={ DEATHSCREAM1SND, DEATHSCREAM2SND,
DEATHSCREAM3SND, DEATHSCREAM4SND,
DEATHSCREAM5SND, DEATHSCREAM7SND,
DEATHSCREAM8SND, DEATHSCREAM9SND
};
PlaySoundLocActor(sounds[US_RndT()%8], ob);
#else
myint sounds[3]={ DEATHSCREAM1SND,
DEATHSCREAM2SND,
DEATHSCREAM3SND
};
PlaySoundLocActor(sounds[US_RndT()%3], ob);
#endif
#endif
}
break;
case officerobj:
PlaySoundLocActor(NEINSOVASSND,ob);
break;
case ssobj:
PlaySoundLocActor(LEBENSND,ob);
break;
case dogobj:
PlaySoundLocActor(DOGDEATHSND,ob);
break;
#ifndef SPEAR
case bossobj:
SD_PlaySound(MUTTISND);
break;
case schabbobj:
SD_PlaySound(MEINGOTTSND);
break;
case fakeobj:
SD_PlaySound(HITLERHASND);
break;
case mechahitlerobj:
SD_PlaySound(SCHEISTSND);
break;
case realhitlerobj:
SD_PlaySound(EVASND);
break;
case gretelobj:
SD_PlaySound(MEINSND);
break;
case giftobj:
SD_PlaySound(DONNERSND);
break;
case fatobj:
SD_PlaySound(ROSESND);
break;
#else
case spectreobj:
SD_PlaySound(GHOSTFADESND);
break;
case angelobj:
SD_PlaySound(ANGELDEATHSND);
break;
case transobj:
SD_PlaySound(TRANSDEATHSND);
break;
case uberobj:
SD_PlaySound(UBERDEATHSND);
break;
case willobj:
SD_PlaySound(WILHELMDEATHSND);
break;
case deathobj:
SD_PlaySound(KNIGHTDEATHSND);
break;
#endif
default:
break;
}
}
/*
============================================================================
PATH
============================================================================
*/
/*
===============
=
= SelectPathDir
=
===============
*/
void SelectPathDir(objtype *ob)
{
unsigned spot;
spot = getmapspecial(ob->tilex, ob->tiley);
if (spot & ms_arrow)
{
// new direction
ob->dir = spot & 7;
}
ob->distance = TILEGLOBAL;
if (!TryWalk (ob))
ob->dir = nodir;
}
/*
===============
=
= T_Path
=
===============
*/
void T_Path (objtype *ob)
{
long move;
if (SightPlayer (ob))
return;
if (ob->dir == nodir)
{
SelectPathDir (ob);
if (ob->dir == nodir)
return; // all movement is blocked
}
move = ob->speed*tics;
while (move)
{
if (ob->distance < 0)
{
//
// waiting for a door to open
//
OpenDoor (-ob->distance-1);
if (doorobjlist[-ob->distance-1].action != dr_open)
return;
ob->distance = TILEGLOBAL; // go ahead, the door is now opoen
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
if (ob->tilex>MAPSIZE || ob->tiley>MAPSIZE)
{
#ifdef EMBEDDED
Quit("T_Path hit a wall");
#else
sprintf(str,"T_Path hit a wall at %u,%u, dir %u"
,ob->tilex,ob->tiley,ob->dir);
Quit(str);
#endif
}
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
SelectPathDir (ob);
if (ob->dir == nodir)
return; /* all movement is blocked */
}
}
/*
=============================================================================
FIGHT
=============================================================================
*/
/*
===============
=
= T_Shoot
=
= Try to damage the player, based on skill level and player's speed
=
===============
*/
void T_Shoot (objtype *ob)
{
myint dx,dy,dist;
myint hitchance,damage;
hitchance = 128;
if (!getareabyplayer(ob->areanumber))
return;
if (!CheckLine (ob)) // player is behind a wall
return;
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx:dy;
if (ob->obclass == ssobj || ob->obclass == bossobj)
dist = dist*2/3; // ss are better shots
if (thrustspeed >= RUNSPEED)
{
if (ob->flags&FL_VISABLE)
hitchance = 160-dist*16; // player can see to dodge
else
hitchance = 160-dist*8;
}
else
{
if (ob->flags&FL_VISABLE)
hitchance = 256-dist*16; // player can see to dodge
else
hitchance = 256-dist*8;
}
// see if the shot was a hit
if (US_RndT()<hitchance)
{
if (dist<2)
damage = US_RndT()>>2;
else if (dist<4)
damage = US_RndT()>>3;
else
damage = US_RndT()>>4;
TakeDamage (damage,ob);
}
switch(ob->obclass)
{
case ssobj:
PlaySoundLocActor(SSFIRESND,ob);
break;
#ifndef SPEAR
case giftobj:
case fatobj:
PlaySoundLocActor(MISSILEFIRESND,ob);
break;
case mechahitlerobj:
case realhitlerobj:
case bossobj:
PlaySoundLocActor(BOSSFIRESND,ob);
break;
case schabbobj:
PlaySoundLocActor(SCHABBSTHROWSND,ob);
break;
case fakeobj:
PlaySoundLocActor(FLAMETHROWERSND,ob);
break;
#endif
default:
PlaySoundLocActor(NAZIFIRESND,ob);
}
}
/*
===============
=
= T_Bite
=
===============
*/
void T_Bite (objtype *ob)
{
long dx,dy;
PlaySoundLocActor(DOGATTACKSND,ob); // JAB
dx = player->x - ob->x;
if (dx<0)
dx = -dx;
dx -= TILEGLOBAL;
if (dx <= MINACTORDIST)
{
dy = player->y - ob->y;
if (dy<0)
dy = -dy;
dy -= TILEGLOBAL;
if (dy <= MINACTORDIST)
{
if (US_RndT()<180)
{
TakeDamage (US_RndT()>>4,ob);
return;
}
}
}
return;
}
/*
=============================================================================
SPEAR ACTORS
=============================================================================
*/
#ifdef SPEAR
/*
===============
=
= SpawnTrans
=
===============
*/
void SpawnTrans (myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (SoundBlasterPresent && DigiMode != sds_Off)
gamestates[s_transdie01].tictime = 105;
#endif
SpawnNewObj(tilex,tiley,s_transstand);
new->obclass = transobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_trans];
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
//
// uber
//
/*
===============
=
= SpawnUber
=
===============
*/
void SpawnUber (myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (SoundBlasterPresent && DigiMode != sds_Off)
gamestates[s_uberdie01].tictime = 70;
#endif
SpawnNewObj (tilex,tiley,s_uberstand);
new->obclass = uberobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_uber];
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= T_UShoot
=
===============
*/
void T_UShoot(objtype *ob)
{
myint dx, dy, dist;
T_Shoot(ob);
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx : dy;
if (dist <= 1)
TakeDamage (10,ob);
}
/*
===============
=
= SpawnWill
=
===============
*/
void SpawnWill(myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (SoundBlasterPresent && DigiMode != sds_Off)
gamestates[s_willdie2].tictime = 70;
#endif
SpawnNewObj (tilex,tiley,s_willstand);
new->obclass = willobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_will];
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
================
=
= T_Will
=
================
*/
void T_Will(objtype *ob)
{
long move;
myint dx,dy,dist;
boolean dodge;
dodge = false;
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx : dy;
if (CheckLine(ob)) // got a shot at player?
{
if ( US_RndT() < (tics<<3) )
{
//
// go into attack frame
//
if (ob->obclass == willobj)
NewState (ob,s_willshoot1);
else if (ob->obclass == angelobj)
NewState (ob,s_angelshoot1);
else
NewState (ob,s_deathshoot1);
return;
}
dodge = true;
}
if (ob->dir == nodir)
{
if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (ob->distance < 0)
{
//
// waiting for a door to open
//
OpenDoor (-ob->distance-1);
if (doorobjlist[-ob->distance-1].action != dr_open)
return;
ob->distance = TILEGLOBAL; // go ahead, the door is now opoen
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
if (dist <4)
SelectRunDir (ob);
else if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
/*
===============
=
= SpawnDeath
=
===============
*/
void SpawnDeath(myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (SoundBlasterPresent && DigiMode != sds_Off)
gamestates[s_deathdie2].tictime = 105;
#endif
SpawnNewObj (tilex,tiley,s_deathstand);
new->obclass = deathobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_death];
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= T_Launch
=
===============
*/
void T_Launch(objtype *ob)
{
long deltax, deltay;
myint iangle;
deltax = player->x - ob->x;
deltay = ob->y - player->y;
iangle = atan2fix (deltay,deltax);
if (ob->obclass == deathobj)
{
T_Shoot (ob);
if (ob->state == s_deathshoot2)
{
iangle-=4;
if (iangle<0)
iangle+=ANGLES;
}
else
{
iangle+=4;
if (iangle>=ANGLES)
iangle-=ANGLES;
}
}
GetNewActor();
new->state = s_rocket;
new->ticcount = 1;
new->tilex = ob->tilex;
new->tiley = ob->tiley;
new->x = ob->x;
new->y = ob->y;
new->obclass = rocketobj;
switch(ob->obclass)
{
case deathobj:
new->state = s_hrocket;
new->obclass = hrocketobj;
PlaySoundLocActor(KNIGHTMISSILESND,new);
break;
case angelobj:
new->state = s_spark1;
new->obclass = sparkobj;
PlaySoundLocActor(ANGELFIRESND,new);
break;
default:
PlaySoundLocActor(MISSILEFIRESND,new);
}
new->dir = nodir;
new->angle = iangle;
new->speed = 0x2000l;
new->flags = FL_NONMARK;
new->active = ac_yes;
}
void A_Slurpie(objtype *ob)
{
SD_PlaySound(SLURPIESND);
}
void A_Breathing(objtype *ob)
{
SD_PlaySound(ANGELTIREDSND);
}
/*
===============
=
= SpawnAngel
=
===============
*/
void SpawnAngel(myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (SoundBlasterPresent && DigiMode != sds_Off)
gamestates[s_angeldie11].tictime = 105;
#endif
SpawnNewObj (tilex,tiley,s_angelstand);
new->obclass = angelobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_angel];
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
=================
=
= A_Victory
=
=================
*/
void A_Victory(objtype *ob)
{
playstate = ex_victorious;
}
/*
=================
=
= A_StartAttack
=
=================
*/
void A_StartAttack(objtype *ob)
{
ob->temp1 = 0;
}
/*
=================
=
= A_Relaunch
=
=================
*/
void A_Relaunch(objtype *ob)
{
if (++ob->temp1 == 3)
{
NewState(ob, s_angeltired);
return;
}
if (US_RndT()&1)
{
NewState(ob, s_angelchase1);
return;
}
}
/*
===============
=
= SpawnSpectre
=
===============
*/
void SpawnSpectre(myint tilex, myint tiley)
{
SpawnNewObj (tilex,tiley,s_spectrewait1);
new->obclass = spectreobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_spectre];
new->flags |= FL_SHOOTABLE|FL_AMBUSH; // |FL_NEVERMARK|FL_NONMARK;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= A_Dormant
=
===============
*/
void A_Dormant(objtype *ob)
{
long deltax, deltay;
myint xl,xh,yl,yh;
myint x,y;
unsigned tile;
deltax = ob->x - player->x;
if (deltax < -MINACTORDIST || deltax > MINACTORDIST)
goto moveok;
deltay = ob->y - player->y;
if (deltay < -MINACTORDIST || deltay > MINACTORDIST)
goto moveok;
return;
moveok:
xl = (ob->x-MINDIST) >> TILESHIFT;
xh = (ob->x+MINDIST) >> TILESHIFT;
yl = (ob->y-MINDIST) >> TILESHIFT;
yh = (ob->y+MINDIST) >> TILESHIFT;
for (y = yl; y <= yh; y++)
for (x = xl; x <= xh; x++)
{
if (!obj_actor_at(x, y))
continue;
tile = get_actor_at(x, y);
if (objlist[tile].flags & FL_SHOOTABLE)
return;
}
ob->flags |= FL_AMBUSH | FL_SHOOTABLE;
ob->flags &= ~FL_ATTACKMODE;
ob->dir = nodir;
NewState(ob, s_spectrewait1);
}
#endif
/*
=============================================================================
SCHABBS / GIFT / FAT
=============================================================================
*/
#ifndef SPEAR
/*
===============
=
= SpawnBoss
=
===============
*/
void SpawnBoss (myint tilex, myint tiley)
{
SpawnNewObj (tilex,tiley,s_bossstand);
new->speed = SPDPATROL;
new->obclass = bossobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_boss];
new->dir = south;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= SpawnGretel
=
===============
*/
void SpawnGretel (myint tilex, myint tiley)
{
SpawnNewObj (tilex,tiley,s_gretelstand);
new->speed = SPDPATROL;
new->obclass = gretelobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_gretel];
new->dir = north;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= SpawnGhosts
=
===============
*/
void SpawnGhosts (myint which, myint tilex, myint tiley)
{
switch(which)
{
case en_blinky:
SpawnNewObj (tilex,tiley,s_blinkychase1);
break;
case en_clyde:
SpawnNewObj (tilex,tiley,s_clydechase1);
break;
case en_pinky:
SpawnNewObj (tilex,tiley,s_pinkychase1);
break;
case en_inky:
SpawnNewObj (tilex,tiley,s_inkychase1);
break;
}
new->obclass = ghostobj;
new->speed = SPDDOG;
new->dir = east;
new->flags |= FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= SpawnSchabbs
=
===============
*/
void SpawnSchabbs(myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (DigiMode != sds_Off)
gamestates[s_schabbdie2].tictime = 140;
else
gamestates[s_schabbdie2].tictime = 5;
#endif
SpawnNewObj(tilex, tiley, s_schabbstand);
new->speed = SPDPATROL;
new->obclass = schabbobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_schabbs];
new->dir = south;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= SpawnGift
=
===============
*/
void SpawnGift (myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (DigiMode != sds_Off)
gamestates[s_giftdie2].tictime = 140;
else
gamestates[s_giftdie2].tictime = 5;
#endif
SpawnNewObj (tilex,tiley,s_giftstand);
new->speed = SPDPATROL;
new->obclass = giftobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_gift];
new->dir = north;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= SpawnFat
=
===============
*/
void SpawnFat (myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (DigiMode != sds_Off)
gamestates[s_fatdie2].tictime = 140;
else
gamestates[s_fatdie2].tictime = 5;
#endif
SpawnNewObj (tilex,tiley,s_fatstand);
new->speed = SPDPATROL;
new->obclass = fatobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_fat];
new->dir = south;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
=================
=
= T_SchabbThrow
=
=================
*/
void T_SchabbThrow (objtype *ob)
{
long deltax,deltay;
myint iangle;
deltax = player->x - ob->x;
deltay = ob->y - player->y;
iangle = atan2fix (deltay,deltax);
GetNewActor ();
new->state = s_needle1;
new->ticcount = 1;
new->tilex = ob->tilex;
new->tiley = ob->tiley;
new->x = ob->x;
new->y = ob->y;
new->obclass = needleobj;
new->dir = nodir;
new->angle = iangle;
new->speed = 0x2000l;
new->flags = FL_NONMARK;
new->active = ac_yes;
PlaySoundLocActor(SCHABBSTHROWSND, new);
}
/*
=================
=
= T_GiftThrow
=
=================
*/
void T_GiftThrow(objtype *ob)
{
long deltax,deltay;
myint iangle;
deltax = player->x - ob->x;
deltay = ob->y - player->y;
iangle = atan2fix (deltay,deltax);
GetNewActor ();
new->state = s_rocket;
new->ticcount = 1;
new->tilex = ob->tilex;
new->tiley = ob->tiley;
new->x = ob->x;
new->y = ob->y;
new->obclass = rocketobj;
new->dir = nodir;
new->angle = iangle;
new->speed = 0x2000l;
new->flags = FL_NONMARK;
new->active = ac_yes;
PlaySoundLocActor(MISSILEFIRESND, new);
}
/*
=================
=
= T_Schabb
=
=================
*/
void T_Schabb (objtype *ob)
{
long move;
myint dx,dy,dist;
boolean dodge;
dodge = false;
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx : dy;
if (CheckLine(ob)) // got a shot at player?
{
if ( US_RndT() < (tics<<3) )
{
//
// go into attack frame
//
NewState (ob,s_schabbshoot1);
return;
}
dodge = true;
}
if (ob->dir == nodir)
{
if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (ob->distance < 0)
{
//
// waiting for a door to open
//
OpenDoor (-ob->distance-1);
if (doorobjlist[-ob->distance-1].action != dr_open)
return;
ob->distance = TILEGLOBAL; // go ahead, the door is now opoen
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
if (dist <4)
SelectRunDir (ob);
else if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
/*
=================
=
= T_Gift
=
=================
*/
void T_Gift (objtype *ob)
{
long move;
myint dx,dy,dist;
boolean dodge;
dodge = false;
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx : dy;
if (CheckLine(ob)) // got a shot at player?
{
if ( US_RndT() < (tics<<3) )
{
//
// go into attack frame
//
NewState (ob,s_giftshoot1);
return;
}
dodge = true;
}
if (ob->dir == nodir)
{
if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (ob->distance < 0)
{
//
// waiting for a door to open
//
OpenDoor (-ob->distance-1);
if (doorobjlist[-ob->distance-1].action != dr_open)
return;
ob->distance = TILEGLOBAL; // go ahead, the door is now opoen
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
if (dist <4)
SelectRunDir (ob);
else if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
/*
=================
=
= T_Fat
=
=================
*/
void T_Fat (objtype *ob)
{
long move;
myint dx,dy,dist;
boolean dodge;
dodge = false;
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx : dy;
if (CheckLine(ob)) // got a shot at player?
{
if ( US_RndT() < (tics<<3) )
{
//
// go into attack frame
//
NewState (ob,s_fatshoot1);
return;
}
dodge = true;
}
if (ob->dir == nodir)
{
if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (ob->distance < 0)
{
//
// waiting for a door to open
//
OpenDoor (-ob->distance-1);
if (doorobjlist[-ob->distance-1].action != dr_open)
return;
ob->distance = TILEGLOBAL; // go ahead, the door is now opoen
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
if (dist <4)
SelectRunDir (ob);
else if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
/*
=============================================================================
HITLERS
=============================================================================
*/
/*
===============
=
= SpawnFakeHitler
=
===============
*/
void SpawnFakeHitler(myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (DigiMode != sds_Off)
gamestates[s_hitlerdie2].tictime = 140;
else
gamestates[s_hitlerdie2].tictime = 5;
#endif
SpawnNewObj(tilex, tiley, s_fakestand);
new->speed = SPDPATROL;
new->obclass = fakeobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_fake];
new->dir = north;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= SpawnHitler
=
===============
*/
void SpawnHitler(myint tilex, myint tiley)
{
#ifdef WEIRD_TIMER_HACK
if (DigiMode != sds_Off)
gamestates[s_hitlerdie2].tictime = 140;
else
gamestates[s_hitlerdie2].tictime = 5;
#endif
SpawnNewObj (tilex,tiley,s_mechastand);
new->speed = SPDPATROL;
new->obclass = mechahitlerobj;
new->hitpoints = starthitpoints[gamestate_difficulty][en_hitler];
new->dir = south;
new->flags |= FL_SHOOTABLE|FL_AMBUSH;
#ifdef ENABLE_STATS
if (!loadedgame)
gamestate.killtotal++;
#endif
}
/*
===============
=
= A_HitlerMorph
=
===============
*/
void A_HitlerMorph (objtype *ob)
{
const word hitpoints[4]={500,700,800,900};
SpawnNewObj (ob->tilex,ob->tiley,s_hitlerchase1);
new->speed = SPDPATROL*5;
new->x = ob->x;
new->y = ob->y;
new->distance = ob->distance;
new->dir = ob->dir;
new->flags = ob->flags | FL_SHOOTABLE;
new->obclass = realhitlerobj;
new->hitpoints = hitpoints[gamestate_difficulty];
}
////////////////////////////////////////////////////////
//
// A_MechaSound
// A_Slurpie
//
////////////////////////////////////////////////////////
void A_MechaSound(objtype *ob)
{
if (getareabyplayer(ob->areanumber))
PlaySoundLocActor(MECHSTEPSND, ob);
}
void A_Slurpie(objtype *ob)
{
SD_PlaySound(SLURPIESND);
}
/*
=================
=
= T_FakeFire
=
=================
*/
void T_FakeFire (objtype *ob)
{
long deltax,deltay;
myint iangle;
deltax = player->x - ob->x;
deltay = ob->y - player->y;
iangle = atan2fix (deltay,deltax);
GetNewActor ();
new->state = s_fire1;
new->ticcount = 1;
new->tilex = ob->tilex;
new->tiley = ob->tiley;
new->x = ob->x;
new->y = ob->y;
new->dir = nodir;
new->angle = iangle;
new->obclass = fireobj;
new->speed = 0x1200l;
new->flags = FL_NEVERMARK;
new->active = ac_yes;
PlaySoundLocActor(FLAMETHROWERSND, new);
}
/*
=================
=
= T_Fake
=
=================
*/
void T_Fake (objtype *ob)
{
long move;
if (CheckLine(ob)) // got a shot at player?
{
if ( US_RndT() < (tics<<1) )
{
//
// go into attack frame
//
NewState (ob,s_fakeshoot1);
return;
}
}
if (ob->dir == nodir)
{
SelectDodgeDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
SelectDodgeDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
#endif
/*
============================================================================
STAND
============================================================================
*/
/*
===============
=
= T_Stand
=
===============
*/
void T_Stand(objtype *ob)
{
SightPlayer (ob);
}
/*
============================================================================
CHASE
============================================================================
*/
/*
=================
=
= T_Chase
=
=================
*/
void T_Chase (objtype *ob)
{
long move;
myint dx,dy,dist,chance;
boolean dodge;
if (gamestate.victoryflag)
return;
dodge = false;
if (CheckLine(ob)) // got a shot at player?
{
dx = abs(ob->tilex - player->tilex);
dy = abs(ob->tiley - player->tiley);
dist = dx>dy ? dx : dy;
if (!dist || (dist==1 && ob->distance<0x4000) )
chance = 300;
else
chance = (tics<<4)/dist;
if ( US_RndT()<chance)
{
//
// go into attack frame
//
switch (ob->obclass)
{
case guardobj:
NewState (ob,s_grdshoot1);
break;
case officerobj:
NewState (ob,s_ofcshoot1);
break;
case mutantobj:
NewState (ob,s_mutshoot1);
break;
case ssobj:
NewState (ob,s_ssshoot1);
break;
#ifndef SPEAR
case bossobj:
NewState (ob,s_bossshoot1);
break;
case gretelobj:
NewState (ob,s_gretelshoot1);
break;
case mechahitlerobj:
NewState (ob,s_mechashoot1);
break;
case realhitlerobj:
NewState (ob,s_hitlershoot1);
break;
#else
case angelobj:
NewState (ob,s_angelshoot1);
break;
case transobj:
NewState (ob,s_transshoot1);
break;
case uberobj:
NewState (ob,s_ubershoot1);
break;
case willobj:
NewState (ob,s_willshoot1);
break;
case deathobj:
NewState (ob,s_deathshoot1);
break;
#endif
default:
break;
}
return;
}
dodge = true;
}
if (ob->dir == nodir)
{
if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (ob->distance < 0)
{
//
// waiting for a door to open
//
OpenDoor (-ob->distance-1);
if (doorobjlist[-ob->distance-1].action != dr_open)
return;
ob->distance = TILEGLOBAL; // go ahead, the door is now opoen
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
if (dodge)
SelectDodgeDir (ob);
else
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
/*
=================
=
= T_Ghosts
=
=================
*/
void T_Ghosts (objtype *ob)
{
long move;
if (ob->dir == nodir)
{
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
SelectChaseDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
/*
=================
=
= T_DogChase
=
=================
*/
void T_DogChase (objtype *ob)
{
long move;
long dx,dy;
if (ob->dir == nodir)
{
SelectDodgeDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
move = ob->speed*tics;
while (move)
{
//
// check for byte range
//
dx = player->x - ob->x;
if (dx<0)
dx = -dx;
dx -= move;
if (dx <= MINACTORDIST)
{
dy = player->y - ob->y;
if (dy<0)
dy = -dy;
dy -= move;
if (dy <= MINACTORDIST)
{
NewState (ob,s_dogjump1);
return;
}
}
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
//
// reached goal tile, so select another one
//
//
// fix position to account for round off during moving
//
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
SelectDodgeDir (ob);
if (ob->dir == nodir)
return; // object is blocked in
}
}
#ifndef SPEAR
/*
============================================================================
BJ VICTORY
============================================================================
*/
/*
===============
=
= SpawnBJVictory
=
===============
*/
void SpawnBJVictory()
{
SpawnNewObj(player->tilex,player->tiley+1, s_bjrun1);
new->x = player->x;
new->y = player->y;
new->obclass = bjobj;
new->dir = north;
new->temp1 = 6; // tiles to run forward
}
/*
===============
=
= T_BJRun
=
===============
*/
void T_BJRun(objtype *ob)
{
long move;
move = BJRUNSPEED*tics;
while (move)
{
if (move < ob->distance)
{
MoveObj (ob,move);
break;
}
ob->x = ((long)ob->tilex<<TILESHIFT)+TILEGLOBAL/2;
ob->y = ((long)ob->tiley<<TILESHIFT)+TILEGLOBAL/2;
move -= ob->distance;
SelectPathDir (ob);
if (!(--ob->temp1))
{
NewState(ob,s_bjjump1);
return;
}
}
}
/*
===============
=
= T_BJJump
=
===============
*/
void T_BJJump(objtype *ob)
{
long move;
move = BJJUMPSPEED*tics;
MoveObj(ob,move);
}
/*
===============
=
= T_BJYell
=
===============
*/
void T_BJYell(objtype *ob)
{
PlaySoundLocActor(YEAHSND, ob);
}
/*
===============
=
= T_BJDone
=
===============
*/
void T_BJDone(objtype *ob)
{
playstate = ex_victorious; // exit castle tile
}
//===========================================================================
#ifndef EMBEDDED
/*
===============
=
= CheckPosition
=
===============
*/
boolean CheckPosition(objtype *ob)
{
myint x, y, xl, yl, xh, yh;
xl = (ob->x-PLAYERSIZE) >>TILESHIFT;
yl = (ob->y-PLAYERSIZE) >>TILESHIFT;
xh = (ob->x+PLAYERSIZE) >>TILESHIFT;
yh = (ob->y+PLAYERSIZE) >>TILESHIFT;
//
// check for solid walls
//
for (y=yl;y<=yh;y++)
for (x=xl;x<=xh;x++)
{
if (solid_actor_at(x, y))
return false;
}
return true;
}
#endif
/*
===============
=
= A_StartDeathCam
=
===============
*/
void A_StartDeathCam(objtype *ob)
{
#ifndef EMBEDDED
long dx,dy;
long xmove,ymove;
long dist;
#ifdef ENABLE_FLASHES
FinishPaletteShifts();
#endif
VW_WaitVBL(100);
if (gamestate.victoryflag)
{
playstate = ex_victorious; // exit castle tile
return;
}
gamestate.victoryflag = true;
FizzleFade(false, 70, 127);
CacheLump(LEVELEND_LUMP_START, LEVELEND_LUMP_END);
Write(0, 7, STR_SEEAGAIN);
VW_UpdateScreen();
IN_UserInput(300);
/* line angle up exactly */
NewState (player,s_deathcam);
player->x = gamestate.killx;
player->y = gamestate.killy;
dx = ob->x - player->x;
dy = player->y - ob->y;
player->angle = atan2fix(dy, dx);
/* try to position as close as possible without being in a wall */
dist = 0x14000l;
do
{
xmove = FixedByFrac(dist, cosfix(player->angle));
ymove = -FixedByFrac(dist, sinfix(player->angle));
player->x = ob->x - xmove;
player->y = ob->y - ymove;
dist += 0x1000;
} while (!CheckPosition(player));
plux = player->x >> UNSIGNEDSHIFT; // scale to fit in unsigned
pluy = player->y >> UNSIGNEDSHIFT;
player->tilex = player->x >> TILESHIFT; // scale to tile values
player->tiley = player->y >> TILESHIFT;
//
// go back to the game
//
DrawPlayBorder();
switch (ob->obclass)
{
case schabbobj:
NewState(ob, s_schabbdeathcam);
break;
case realhitlerobj:
NewState(ob, s_hitlerdeathcam);
break;
case giftobj:
NewState(ob, s_giftdeathcam);
break;
case fatobj:
NewState(ob, s_fatdeathcam);
break;
default:
break;
}
#endif
}
#endif