DOOM64-RE

DOOM 64 Reverse Engineering
Log | Files | Refs | README | LICENSE

p_mobj.c (11614B)


      1 /* P_mobj.c */
      2 
      3 #include "doomdef.h"
      4 #include "p_local.h"
      5 #include "sounds.h"
      6 
      7 void G_PlayerReborn (int player);
      8 
      9 extern mobj_t *cameratarget;    // 800A5D70
     10 extern mapthing_t *spawnlist;   // 800A5D74
     11 extern int spawncount;          // 800A5D78
     12 
     13 /*
     14 ===============
     15 =
     16 = P_SpawnMobj
     17 =
     18 ===============
     19 */
     20 
     21 mobj_t *P_SpawnMobj (fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) // 80018a20
     22 {
     23 	mobj_t		*mobj;
     24 	state_t		*st;
     25 	mobjinfo_t	*info;
     26 
     27 	mobj = Z_Malloc (sizeof(*mobj), PU_LEVEL, NULL);
     28 
     29 	D_memset (mobj, 0, sizeof (*mobj));
     30 	info = &mobjinfo[type];
     31 
     32 	mobj->type = type;
     33 	mobj->info = info;
     34 	mobj->x = x;
     35 	mobj->y = y;
     36 	mobj->radius = info->radius;
     37 	mobj->height = info->height;
     38 	mobj->flags = info->flags;
     39 	mobj->health = info->spawnhealth;
     40 	mobj->reactiontime = info->reactiontime;
     41 	mobj->alpha = info->alpha;
     42 
     43 	/* do not set the state with P_SetMobjState, because action routines can't */
     44 	/* be called yet */
     45 	st = &states[info->spawnstate];
     46 
     47 	mobj->state = st;
     48 	mobj->tics = st->tics;
     49 	mobj->sprite = st->sprite;
     50 	mobj->frame = st->frame;
     51 
     52 	/* set subsector and/or block links */
     53 	P_SetThingPosition (mobj);
     54 
     55 	mobj->floorz = mobj->subsector->sector->floorheight;
     56 	mobj->ceilingz = mobj->subsector->sector->ceilingheight;
     57 	if (z == ONFLOORZ)
     58 		mobj->z = mobj->floorz;
     59 	else if (z == ONCEILINGZ)
     60 		mobj->z = mobj->ceilingz - mobj->info->height;
     61 	else
     62 		mobj->z = z;
     63 
     64 	/* */
     65 	/* link into the mobj list */
     66 	/* */
     67 	mobjhead.prev->next = mobj;
     68 	mobj->next = &mobjhead;
     69 	mobj->prev = mobjhead.prev;
     70 	mobjhead.prev = mobj;
     71 
     72 	if((mobj->flags & MF_COUNTKILL) != 0)
     73         totalkills++;
     74 
     75     if((mobj->flags & MF_COUNTITEM) != 0)
     76         totalitems++;
     77 
     78 	return mobj;
     79 }
     80 
     81 /*
     82 =================
     83 =
     84 = P_SpawnMapThing
     85 =
     86 = The fields of the mapthing should already be in host byte order
     87 ==================
     88 */
     89 
     90 extern mobj_t*  checkthing;
     91 extern int      testflags;
     92 extern fixed_t  testradius;
     93 extern fixed_t  testx;
     94 extern fixed_t  testy;
     95 
     96 extern boolean PB_CheckPosition(void);
     97 
     98 mobj_t *P_SpawnMapThing (mapthing_t *mthing) // 80018C24
     99 {
    100 	int			i, bit;
    101 	mobj_t		*mobj;
    102 	fixed_t		x,y,z;
    103 	mobj_t		tmp_mobj;
    104 
    105 	if (mthing->type == MAXPLAYERS)
    106 	{
    107 		playerstarts[0] = *mthing;
    108 		return NULL;
    109 	}
    110 
    111 	#if ENABLE_NIGHTMARE == 1
    112 	if (gameskill == sk_baby)
    113 		bit = 1;
    114 	else if (gameskill == sk_nightmare)
    115 		bit = 4;
    116 	else
    117 		bit = 1<<(gameskill-1);
    118 	#else
    119 	if (gameskill == sk_baby || gameskill == sk_easy)
    120 		bit = 1;
    121 	else if (gameskill == sk_medium)
    122 		bit = 2;
    123 	else if (gameskill == sk_hard)
    124 		bit = 4;
    125 
    126 	#endif // ENABLE_NIGHTMARE
    127 
    128 	if (!(mthing->options & bit) )
    129 		return NULL;
    130 
    131 	/* find which type to spawn */
    132 	for (i = 0; i < NUMMOBJTYPES; i++)
    133 	{
    134 		if (mthing->type == mobjinfo[i].doomednum)
    135 			break;
    136 	}
    137 
    138 	if (i==NUMMOBJTYPES)
    139     {
    140 		I_Error ("P_SpawnMapThing: Unknown type %d at (%d, %d)",mthing->type , mthing->x, mthing->y);
    141     }
    142 
    143     //
    144     // [d64] check if spawn is valid
    145     //
    146     if((mobjinfo[i].flags & MF_SOLID) != 0)
    147     {
    148         checkthing = &tmp_mobj;
    149         testflags = mobjinfo[i].flags;
    150         testradius = mobjinfo[i].radius;
    151         testx = mthing->x << FRACBITS;
    152         testy = mthing->y << FRACBITS;
    153 
    154         if(!PB_CheckPosition())
    155             return NULL;
    156     }
    157 
    158     // [d64]: queue mobj for spawning later
    159     if(mthing->options & MTF_SPAWN)
    160     {
    161         mthing->options &= ~MTF_SPAWN;
    162         D_memcpy(&spawnlist[spawncount], mthing, sizeof(mapthing_t));
    163         spawncount += 1;
    164 
    165         return NULL;
    166     }
    167 
    168 	/* spawn it */
    169 	x = mthing->x << FRACBITS;
    170 	y = mthing->y << FRACBITS;
    171 	if (mobjinfo[i].flags & MF_SPAWNCEILING)
    172 		z = ONCEILINGZ;
    173 	else
    174 		z = ONFLOORZ;
    175 
    176 	mobj = P_SpawnMobj (x,y,z, i);
    177 	mobj->z += (mthing->z << FRACBITS);
    178 	mobj->angle = ANG45 * (mthing->angle/45);
    179 	mobj->tid = mthing->tid;
    180 
    181 	if (mobj->tics > 0)
    182 		mobj->tics = 1 + (P_Random () % mobj->tics);
    183 
    184 	if (mthing->options & MTF_AMBUSH)
    185 		mobj->flags |= MF_AMBUSH;
    186 
    187     if (mthing->options & MTF_ONTOUCH)
    188 		mobj->flags |= MF_TRIGTOUCH;
    189 
    190     if (mthing->options & MTF_ONDEATH)
    191 		mobj->flags |= MF_TRIGDEATH;
    192 
    193     if (mthing->options & MTF_SECRET)
    194     {
    195 		mobj->flags |= MF_COUNTSECRET;
    196 		totalsecret++;
    197     }
    198 
    199     if (mthing->options & MTF_NOINFIGHTING)
    200 		mobj->flags |= MF_NOINFIGHTING;
    201 
    202     return mobj;
    203 }
    204 
    205 /*
    206 ============
    207 =
    208 = P_SpawnPlayer
    209 =
    210 = Called when a player is spawned on the level
    211 = Most of the player structure stays unchanged between levels
    212 ============
    213 */
    214 
    215 void P_SpawnPlayer(/*mapthing_t *mthing*/) // 80018F94
    216 {
    217 	player_t	*p;
    218 	fixed_t		x,y,z;
    219 	mobj_t		*mobj;
    220 	int	i;
    221 	int levelnum;
    222 	int skill;
    223 
    224 	//if (!playeringame[mthing->type-1])
    225 		//return;						/* not playing */
    226 
    227 	p = &players[0];
    228 
    229 	if (p->playerstate == PST_REBORN)
    230 		G_PlayerReborn(0);
    231     else
    232     {
    233         p->killcount = 0;
    234         p->secretcount = 0;
    235         p->itemcount = 0;
    236     }
    237 
    238 	x = playerstarts[0].x << FRACBITS;
    239 	y = playerstarts[0].y << FRACBITS;
    240 
    241 	z = ONFLOORZ;
    242 	mobj = P_SpawnMobj (x,y,z, MT_PLAYER);
    243 
    244 	mobj->angle  = ANG45 * (playerstarts[0].angle/45);
    245 	mobj->player = p;
    246 	mobj->health = p->health;
    247 	mobj->tid    = playerstarts[0].tid;
    248     mobj->z      = mobj->z + (playerstarts[0].z << FRACBITS);
    249 	p->mo = mobj;
    250 	p->playerstate = PST_LIVE;
    251 	p->refire = 0;
    252 	p->message = NULL;
    253 	p->messagetic = 0;
    254 	p->damagecount = 0;
    255 	p->bonuscount = 0;
    256 	p->extralight = 0;
    257 	p->bfgcount = 0;
    258 	p->viewheight = VIEWHEIGHT;
    259 	p->automapscale = 850;
    260 	p->viewz = mobj->z + VIEWHEIGHT;
    261 	cameratarget = p->mo;
    262 
    263 	P_SetupPsprites (0);		/* setup gun psprite	 */
    264 
    265     if (doPassword != 0)
    266     {
    267         M_DecodePassword(Passwordbuff, &levelnum, &skill, p);
    268         doPassword = false;
    269     }
    270 
    271     ST_InitEveryLevel();
    272     ST_UpdateFlash(); // ST_doPaletteStuff();
    273 }
    274 
    275 /*
    276 ===============
    277 =
    278 = P_RemoveMobj
    279 =
    280 ===============
    281 */
    282 
    283 void P_RemoveMobj (mobj_t *mobj) // 80019130
    284 {
    285 	/* unlink from sector and block lists */
    286 	P_UnsetThingPosition (mobj);
    287 
    288 	/* unlink from mobj list */
    289 	mobj->next->prev = mobj->prev;
    290 	mobj->prev->next = mobj->next;
    291 	Z_Free (mobj);
    292 }
    293 
    294 /*
    295 ================
    296 =
    297 = P_SetMobjState
    298 =
    299 = Returns true if the mobj is still present
    300 ================
    301 */
    302 
    303 boolean P_SetMobjState (mobj_t *mobj, statenum_t state) // 80019184
    304 {
    305 	state_t	*st;
    306 
    307 	if (state == S_000)
    308 	{
    309 		mobj->state = NULL;
    310 		P_RemoveMobj (mobj);
    311 		return false;
    312 	}
    313 
    314 	st = &states[state];
    315 
    316 	mobj->state = st;
    317 	mobj->tics = st->tics;
    318 	mobj->sprite = st->sprite;
    319 	mobj->frame = st->frame;
    320 
    321 	if (st->action)		/* call action functions when the state is set */
    322 		st->action (mobj);
    323 
    324 	mobj->latecall = NULL;	/* make sure it doesn't come back to life... */
    325 
    326 	return true;
    327 }
    328 
    329 /*============================================================================= */
    330 
    331 /*
    332 ===============================================================================
    333 
    334 						GAME SPAWN FUNCTIONS
    335 
    336 ===============================================================================
    337 */
    338 
    339 /*
    340 ================
    341 =
    342 = P_SpawnPuff
    343 =
    344 ================
    345 */
    346 
    347 extern fixed_t attackrange; // 800A5704
    348 
    349 void P_SpawnPuff (fixed_t x, fixed_t y, fixed_t z) // 80019218
    350 {
    351 	mobj_t	*th;
    352 	int rnd1, rnd2;
    353 
    354 	rnd1 = P_Random();
    355 	rnd2 = P_Random();
    356 
    357 	z += ((rnd2-rnd1)<<10);
    358 	th = P_SpawnMobj (x,y,z, MT_SMOKE_SMALL);
    359 	th->momz = FRACUNIT;
    360 	th->tics -= P_Random()&1;
    361 	if (th->tics < 1)
    362 		th->tics = 1;
    363 
    364 /* don't make punches spark on the wall */
    365 	if (attackrange == MELEERANGE)
    366 		P_SetMobjState (th, S_490);
    367 }
    368 
    369 
    370 /*
    371 ================
    372 =
    373 = P_SpawnBlood
    374 =
    375 ================
    376 */
    377 
    378 void P_SpawnBlood (fixed_t x, fixed_t y, fixed_t z, int damage) // 800192B8
    379 {
    380 	mobj_t	*th;
    381 	int i;
    382 
    383 	for(i = 0; i < 3; i++)
    384     {
    385         x += ((P_Random()-P_Random())<<12);
    386         y += ((P_Random()-P_Random())<<12);
    387         z += ((P_Random()-P_Random())<<11);
    388         th = P_SpawnMobj (x,y,z, MT_BLOOD);
    389         th->momz = FRACUNIT*2;
    390         th->tics -= P_Random()&1;
    391         if (th->tics<1)
    392             th->tics = 1;
    393         if (damage <= 12 && damage >= 9)
    394             P_SetMobjState (th, S_495);
    395         else if (damage < 9)
    396             P_SetMobjState (th, S_496);
    397     }
    398 }
    399 
    400 /*
    401 ================
    402 =
    403 = P_SpawnMissile
    404 =
    405 ================
    406 */
    407 
    408 mobj_t *P_SpawnMissile (mobj_t *source, mobj_t *dest, fixed_t xoffs, fixed_t yoffs, fixed_t heightoffs, mobjtype_t type) // 80019410
    409 {
    410 	mobj_t		*th;
    411 	angle_t		an;
    412 	int			dist;
    413 	int			speed;
    414 	fixed_t     x, y, z;
    415 	int         rnd1, rnd2;
    416 
    417 	x = source->x + xoffs;
    418     y = source->y + yoffs;
    419     z = source->z + heightoffs;
    420 
    421 	th = P_SpawnMobj (x, y, z, type);
    422 	if (th->info->seesound)
    423 		S_StartSound (source, th->info->seesound);
    424 	th->target = source;		/* where it came from */
    425 
    426     if ((type == MT_PROJ_BABY) || (type == MT_PROJ_DART)) /* no aim projectile */
    427         an = source->angle;
    428     else if (dest)
    429         an = R_PointToAngle2(x, y, dest->x, dest->y);
    430 
    431 	if (dest && (dest->flags & MF_SHADOW))
    432     {
    433         rnd1 = P_Random();
    434         rnd2 = P_Random();
    435 		an += ((rnd2 - rnd1) << 20);
    436     }
    437 
    438     th->angle = an;
    439     an >>= ANGLETOFINESHIFT;
    440     speed = th->info->speed;
    441     th->momx = speed * finecosine[an];
    442     th->momy = speed * finesine[an];
    443 
    444     if (dest)
    445     {
    446         dist = P_AproxDistance (dest->x - x, dest->y - y);
    447         dist = dist / (th->info->speed << FRACBITS);
    448         if (dist < 1)
    449             dist = 1;
    450         th->momz = ((dest->z + (dest->height >> 1)) - z) / dist;
    451     }
    452 
    453 	if (!P_CheckPosition (th, th->x, th->y))
    454 		P_ExplodeMissile (th);
    455 
    456 	return th;
    457 }
    458 
    459 
    460 /*
    461 ================
    462 =
    463 = P_SpawnPlayerMissile
    464 =
    465 = Tries to aim at a nearby monster
    466 ================
    467 */
    468 extern line_t*         shotline;       // 800A56FC
    469 extern fixed_t         aimfrac;        // 800A5720
    470 
    471 void P_SpawnPlayerMissile (mobj_t *source, mobjtype_t type) // 80019668
    472 {
    473 	mobj_t      *th;
    474 	angle_t     an;
    475 	fixed_t     x,y,z, slope;
    476 	int         speed;
    477 	fixed_t     missileheight;
    478     int         offset;
    479 
    480     // [d64] adjust offset and height based on missile
    481     if(type == MT_PROJ_ROCKET)
    482     {
    483         missileheight = (42*FRACUNIT);
    484         offset = 30;
    485     }
    486     else if(type == MT_PROJ_PLASMA)
    487     {
    488         missileheight = (32*FRACUNIT);
    489         offset = 40;
    490     }
    491     else if(type == MT_PROJ_BFG)
    492     {
    493         missileheight = (32*FRACUNIT);
    494         offset = 30;
    495     }
    496     else
    497     {
    498         missileheight = (32*FRACUNIT);
    499         offset = 0;
    500     }
    501 
    502 	/* */
    503 	/* see which target is to be aimed at */
    504 	/* */
    505 	an = source->angle;
    506 	slope = P_AimLineAttack (source, an, missileheight, 16*64*FRACUNIT);
    507 	if (!linetarget)
    508 	{
    509 		an += 1<<26;
    510 		slope = P_AimLineAttack (source, an, missileheight, 16*64*FRACUNIT);
    511 		if (!linetarget)
    512 		{
    513 			an -= 2<<26;
    514 			slope = P_AimLineAttack (source, an, missileheight, 16*64*FRACUNIT);
    515 		}
    516 		if (!linetarget)
    517 		{
    518 			an = source->angle;
    519 			slope = 0;
    520 		}
    521 	}
    522 
    523 	x = source->x;
    524 	y = source->y;
    525 	z = source->z;
    526 
    527 	th = P_SpawnMobj (x,y,z+missileheight, type);
    528 	if (th->info->seesound)
    529 		S_StartSound (source, th->info->seesound);
    530 	th->target = source;
    531 	th->angle = an;
    532 
    533 	speed = th->info->speed;
    534 
    535 	th->momx = speed * finecosine[an>>ANGLETOFINESHIFT];
    536 	th->momy = speed * finesine[an>>ANGLETOFINESHIFT];
    537 	th->momz = speed * slope;
    538 
    539 	x = source->x + (offset * finecosine[an>>ANGLETOFINESHIFT]);
    540     y = source->y + (offset * finesine[an>>ANGLETOFINESHIFT]);
    541 
    542 	// [d64]: checking against very close lines?
    543     if((shotline && aimfrac <= 0xC80) || !P_TryMove(th, x, y))
    544         P_ExplodeMissile(th);
    545 }
    546 
    547 
    548 /*
    549 ===================
    550 =
    551 = P_ExplodeMissile
    552 =
    553 ===================
    554 */
    555 
    556 void P_ExplodeMissile (mobj_t *mo) // 800198B8
    557 {
    558     if(!P_SetMobjState(mo, mobjinfo[mo->type].deathstate))
    559         return;
    560 
    561 	mo->momx = mo->momy = mo->momz = 0;
    562 
    563 	mo->tics -= P_Random()&1;
    564 	if (mo->tics < 1)
    565 		mo->tics = 1;
    566 
    567 	mo->flags &= ~MF_MISSILE;
    568 	if (mo->info->deathsound)
    569 	{
    570 		S_StopSound(mo, 0);
    571 		S_StartSound(mo, mo->info->deathsound);
    572 	}
    573 }