X-Git-Url: http://4ch.mooo.com/gitweb/?a=blobdiff_plain;f=src%2Flib%2Fhb%2Fc3_state.c;fp=src%2Flib%2Fhb%2Fc3_state.c;h=8c31eb0681719d8a160811aeddf612a818b9886a;hb=52fab2ff9ef6a39ed9303b0df1ce0ad9c9180ef1;hp=0000000000000000000000000000000000000000;hpb=44abd2a32d08194960117b1d09fe453d6157544f;p=16.git diff --git a/src/lib/hb/c3_state.c b/src/lib/hb/c3_state.c new file mode 100755 index 00000000..8c31eb06 --- /dev/null +++ b/src/lib/hb/c3_state.c @@ -0,0 +1,546 @@ +/* Catacomb 3-D Source Code + * Copyright (C) 1993-2014 Flat Rock Software + * + * 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., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +// C3_STATE.C + +#include "C3_DEF.H" +#pragma hdrstop + +/* +============================================================================= + + LOCAL CONSTANTS + +============================================================================= +*/ + + +/* +============================================================================= + + GLOBAL VARIABLES + +============================================================================= +*/ + + + +/* +============================================================================= + + LOCAL VARIABLES + +============================================================================= +*/ + + +dirtype opposite[9] = + {south,west,north,east,southwest,northwest,northeast,southeast,nodir}; + + + +//=========================================================================== + + +/* +=================== += += SpawnNewObj += +=================== +*/ + +void SpawnNewObj (unsigned x, unsigned y, statetype *state, unsigned size) +{ + GetNewObj (false); + new->size = size; + new->state = state; + new->ticcount = random (state->tictime)+1; + + new->tilex = x; + new->tiley = y; + new->x = ((long)x<y = ((long)y<dir = nodir; + + actorat[new->tilex][new->tiley] = new; +} + +void SpawnNewObjFrac (long x, long y, statetype *state, unsigned size) +{ + GetNewObj (false); + new->size = size; + new->state = state; + new->ticcount = random (state->tictime)+1; + new->active = true; + + new->x = x; + new->y = y; + new->tilex = x>>TILESHIFT; + new->tiley = y>>TILESHIFT; + CalcBounds(new); + new->distance = 100; + new->dir = nodir; +} + + + +/* +=================== += += CheckHandAttack += += If the object can move next to the player, it will return true += +=================== +*/ + +boolean CheckHandAttack (objtype *ob) +{ + long deltax,deltay,size; + + size = (long)ob->size + player->size + ob->speed*tics; + deltax = ob->x - player->x; + deltay = ob->y - player->y; + + if (deltax > size || deltax < -size || deltay > size || deltay < -size) + return false; + + return true; +} + + +/* +=================== += += T_DoDamage += += Attacks the player if still nearby, then immediately changes to next state += +=================== +*/ + +void T_DoDamage (objtype *ob) +{ + int points; + + + if (!CheckHandAttack (ob)) + { + SD_PlaySound (MONSTERMISSSND); + } + else + { + points = 0; + + switch (ob->obclass) + { + case orcobj: + points = 4; + break; + case trollobj: + points = 8; + break; + case demonobj: + points = 15; + break; + } + TakeDamage (points); + } + + ob->state = ob->state->next; +} + + +//========================================================================== + +/* +================================== += += Walk += +================================== +*/ + +boolean Walk (objtype *ob) +{ + switch (ob->dir) + { + case north: + if (actorat[ob->tilex][ob->tiley-1]) + return false; + ob->tiley--; + ob->distance = TILEGLOBAL; + return true; + + case northeast: + if (actorat[ob->tilex+1][ob->tiley-1]) + return false; + ob->tilex++; + ob->tiley--; + ob->distance = TILEGLOBAL; + return true; + + case east: + if (actorat[ob->tilex+1][ob->tiley]) + return false; + ob->tilex++; + ob->distance = TILEGLOBAL; + return true; + + case southeast: + if (actorat[ob->tilex+1][ob->tiley+1]) + return false; + ob->tilex++; + ob->tiley++; + ob->distance = TILEGLOBAL; + return true; + + case south: + if (actorat[ob->tilex][ob->tiley+1]) + return false; + ob->tiley++; + ob->distance = TILEGLOBAL; + return true; + + case southwest: + if (actorat[ob->tilex-1][ob->tiley+1]) + return false; + ob->tilex--; + ob->tiley++; + ob->distance = TILEGLOBAL; + return true; + + case west: + if (actorat[ob->tilex-1][ob->tiley]) + return false; + ob->tilex--; + ob->distance = TILEGLOBAL; + return true; + + case northwest: + if (actorat[ob->tilex-1][ob->tiley-1]) + return false; + ob->tilex--; + ob->tiley--; + ob->distance = TILEGLOBAL; + return true; + + case nodir: + return false; + } + + Quit ("Walk: Bad dir"); + return false; +} + + + +/* +================================== += += ChaseThink += have the current monster go after the player, += either diagonally or straight on += +================================== +*/ + +void ChaseThink (objtype *obj, boolean diagonal) +{ + int deltax,deltay,i; + dirtype d[3]; + dirtype tdir, olddir, turnaround; + + + olddir=obj->dir; + turnaround=opposite[olddir]; + + deltax=player->tilex - obj->tilex; + deltay=player->tiley - obj->tiley; + + d[1]=nodir; + d[2]=nodir; + + if (deltax>0) + d[1]= east; + if (deltax<0) + d[1]= west; + if (deltay>0) + d[2]=south; + if (deltay<0) + d[2]=north; + + if (abs(deltay)>abs(deltax)) + { + tdir=d[1]; + d[1]=d[2]; + d[2]=tdir; + } + + if (d[1]==turnaround) + d[1]=nodir; + if (d[2]==turnaround) + d[2]=nodir; + + + if (diagonal) + { /*ramdiagonals try the best dir first*/ + if (d[1]!=nodir) + { + obj->dir=d[1]; + if (Walk(obj)) + return; /*either moved forward or attacked*/ + } + + if (d[2]!=nodir) + { + obj->dir=d[2]; + if (Walk(obj)) + return; + } + } + else + { /*ramstraights try the second best dir first*/ + + if (d[2]!=nodir) + { + obj->dir=d[2]; + if (Walk(obj)) + return; + } + + if (d[1]!=nodir) + { + obj->dir=d[1]; + if (Walk(obj)) + return; + } + } + +/* there is no direct path to the player, so pick another direction */ + + obj->dir=olddir; + if (Walk(obj)) + return; + + if (US_RndT()>128) /*randomly determine direction of search*/ + { + for (tdir=north;tdir<=west;tdir++) + { + if (tdir!=turnaround) + { + obj->dir=tdir; + if (Walk(obj)) + return; + } + } + } + else + { + for (tdir=west;tdir>=north;tdir--) + { + if (tdir!=turnaround) + { + obj->dir=tdir; + if (Walk(obj)) + return; + } + } + } + + obj->dir=turnaround; + Walk(obj); /*last chance, don't worry about returned value*/ +} + + +/* +================= += += MoveObj += +================= +*/ + +void MoveObj (objtype *ob, long move) +{ + ob->distance -=move; + + switch (ob->dir) + { + case north: + ob->y -= move; + return; + case northeast: + ob->x += move; + ob->y -= move; + return; + case east: + ob->x += move; + return; + case southeast: + ob->x += move; + ob->y += move; + return; + case south: + ob->y += move; + return; + case southwest: + ob->x -= move; + ob->y += move; + return; + case west: + ob->x -= move; + return; + case northwest: + ob->x -= move; + ob->y -= move; + return; + + case nodir: + return; + } +} + + +/* +================= += += Chase += += returns true if hand attack range += +================= +*/ + +boolean Chase (objtype *ob, boolean diagonal) +{ + long move; + long deltax,deltay,size; + + move = ob->speed*tics; + size = (long)ob->size + player->size + move; + + while (move) + { + deltax = ob->x - player->x; + deltay = ob->y - player->y; + + if (deltax <= size && deltax >= -size + && deltay <= size && deltay >= -size) + { + CalcBounds (ob); + return true; + } + + if (move < ob->distance) + { + MoveObj (ob,move); + break; + } + actorat[ob->tilex][ob->tiley] = 0; // pick up marker from goal + if (ob->dir == nodir) + ob->dir = north; + + ob->x = ((long)ob->tilex<y = ((long)ob->tiley<distance; + + ChaseThink (ob,diagonal); + if (!ob->distance) + break; // no possible move + actorat[ob->tilex][ob->tiley] = ob; // set down a new goal marker + } + CalcBounds (ob); + return false; +} + +//=========================================================================== + + +/* +=================== += += ShootActor += +=================== +*/ + +void ShootActor (objtype *ob, unsigned damage) +{ + ob->hitpoints -= damage; + if (ob->hitpoints<=0) + { + switch (ob->obclass) + { + case orcobj: + ob->state = &s_orcdie1; + GivePoints (100); + break; + case trollobj: + ob->state = &s_trolldie1; + GivePoints (400); + break; + case demonobj: + ob->state = &s_demondie1; + GivePoints (1000); + break; + case mageobj: + ob->state = &s_magedie1; + GivePoints (600); + break; + case batobj: + ob->state = &s_batdie1; + GivePoints (100); + break; + case grelmobj: + ob->state = &s_greldie1; + GivePoints (10000); + break; + + } + ob->obclass = inertobj; + ob->shootable = false; + actorat[ob->tilex][ob->tiley] = NULL; + } + else + { + switch (ob->obclass) + { + case orcobj: + ob->state = &s_orcouch; + break; + case trollobj: + ob->state = &s_trollouch; + break; + case demonobj: + ob->state = &s_demonouch; + break; + case mageobj: + ob->state = &s_mageouch; + break; + case grelmobj: + ob->state = &s_grelouch; + break; + + } + } + ob->ticcount = ob->state->tictime; +} +