p_user.c 381 KB
Newer Older
Alam Ed Arias committed
1 2 3 4
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
James R. committed
5
// Copyright (C) 1999-2020 by Sonic Team Junior.
Alam Ed Arias committed
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file  p_user.c
/// \brief New stuff?
///        Player related stuff.
///        Bobbing POV/weapon, movement.
///        Pending weapon.

#include "doomdef.h"
#include "i_system.h"
#include "d_event.h"
#include "d_net.h"
#include "g_game.h"
#include "p_local.h"
#include "r_main.h"
#include "s_sound.h"
25
#include "r_skins.h"
Alam Ed Arias committed
26 27 28 29 30 31
#include "d_think.h"
#include "r_sky.h"
#include "p_setup.h"
#include "m_random.h"
#include "m_misc.h"
#include "i_video.h"
32
#include "p_slopes.h"
Alam Ed Arias committed
33 34 35 36 37 38 39 40
#include "p_spec.h"
#include "r_splats.h"
#include "z_zone.h"
#include "w_wad.h"
#include "hu_stuff.h"
// We need to affect the NiGHTS hud
#include "st_stuff.h"
#include "lua_script.h"
Alam Ed Arias committed
41
#include "lua_hook.h"
Alam Ed Arias committed
42 43 44
#include "b_bot.h"
// Objectplace
#include "m_cheat.h"
45 46
// Thok camera snap (ctrl-f "chalupa")
#include "g_input.h"
Alam Ed Arias committed
47 48 49 50 51 52 53 54 55 56 57 58 59 60

#ifdef HW3SOUND
#include "hardware/hw3sound.h"
#endif

#ifdef HWRENDER
#include "hardware/hw_light.h"
#include "hardware/hw_main.h"
#endif

#if 0
static void P_NukeAllPlayers(player_t *player);
#endif

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83
//
// Jingle stuff.
//

jingle_t jingleinfo[NUMJINGLES] = {
	// {musname, looping, reset, nest}
	{""        , false}, // JT_NONE
	{""        , false}, // JT_OTHER
	{""        , false}, // JT_MASTER
	{"_1up"    , false},
	{"_shoes"  ,  true},
	{"_inv"    , false},
	{"_minv"   , false},
	{"_drown"  , false},
	{"_super"  ,  true},
	{"_gover"  , false},
	{"_ntime"  , false},  // JT_NIGHTSTIMEOUT
	{"_drown"  , false}   // JT_SSTIMEOUT
	// {"_clear"  , false},
	// {"_inter"  ,  true},
	// {"_conti"  ,  true}
};

Alam Ed Arias committed
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
//
// Movement.
//

// 16 pixels of bob
#define MAXBOB (0x10 << FRACBITS)

static boolean onground;

//
// P_Thrust
// Moves the given origin along a given angle.
//
void P_Thrust(mobj_t *mo, angle_t angle, fixed_t move)
{
	angle >>= ANGLETOFINESHIFT;

	mo->momx += FixedMul(move, FINECOSINE(angle));

	if (!(twodlevel || (mo->flags2 & MF2_TWOD)))
		mo->momy += FixedMul(move, FINESINE(angle));
}

#if 0
static inline void P_ThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move)
{
	angle >>= ANGLETOFINESHIFT;

	mo->momx += FixedMul(move, FINECOSINE(angle));
	mo->momy += FixedMul(move, FINESINE(angle));
}

static inline void P_VectorInstaThrust(fixed_t xa, fixed_t xb, fixed_t xc, fixed_t ya, fixed_t yb, fixed_t yc,
	fixed_t za, fixed_t zb, fixed_t zc, fixed_t momentum, mobj_t *mo)
{
	fixed_t a1, b1, c1, a2, b2, c2, i, j, k;

	a1 = xb - xa;
	b1 = yb - ya;
	c1 = zb - za;
	a2 = xb - xc;
	b2 = yb - yc;
	c2 = zb - zc;
/*
	// Convert to unit vectors...
	a1 = FixedDiv(a1,FixedSqrt(FixedMul(a1,a1) + FixedMul(b1,b1) + FixedMul(c1,c1)));
	b1 = FixedDiv(b1,FixedSqrt(FixedMul(a1,a1) + FixedMul(b1,b1) + FixedMul(c1,c1)));
	c1 = FixedDiv(c1,FixedSqrt(FixedMul(c1,c1) + FixedMul(c1,c1) + FixedMul(c1,c1)));

	a2 = FixedDiv(a2,FixedSqrt(FixedMul(a2,a2) + FixedMul(c2,c2) + FixedMul(c2,c2)));
	b2 = FixedDiv(b2,FixedSqrt(FixedMul(a2,a2) + FixedMul(c2,c2) + FixedMul(c2,c2)));
	c2 = FixedDiv(c2,FixedSqrt(FixedMul(a2,a2) + FixedMul(c2,c2) + FixedMul(c2,c2)));
*/
	// Calculate the momx, momy, and momz
	i = FixedMul(momentum, FixedMul(b1, c2) - FixedMul(c1, b2));
	j = FixedMul(momentum, FixedMul(c1, a2) - FixedMul(a1, c2));
	k = FixedMul(momentum, FixedMul(a1, b2) - FixedMul(a1, c2));

	mo->momx = i;
	mo->momy = j;
	mo->momz = k;
}
#endif

//
// P_InstaThrust
// Moves the given origin along a given angle instantly.
//
// FIXTHIS: belongs in another file, not here
//
void P_InstaThrust(mobj_t *mo, angle_t angle, fixed_t move)
{
	angle >>= ANGLETOFINESHIFT;

	mo->momx = FixedMul(move, FINECOSINE(angle));

	if (!(twodlevel || (mo->flags2 & MF2_TWOD)))
		mo->momy = FixedMul(move,FINESINE(angle));
}

void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move)
{
	angle >>= ANGLETOFINESHIFT;

	mo->momx = FixedMul(move, FINECOSINE(angle));
	mo->momy = FixedMul(move, FINESINE(angle));
}

// Returns a location (hard to explain - go see how it is used)
fixed_t P_ReturnThrustX(mobj_t *mo, angle_t angle, fixed_t move)
{
	(void)mo;
	angle >>= ANGLETOFINESHIFT;
	return FixedMul(move, FINECOSINE(angle));
}
fixed_t P_ReturnThrustY(mobj_t *mo, angle_t angle, fixed_t move)
{
	(void)mo;
	angle >>= ANGLETOFINESHIFT;
	return FixedMul(move, FINESINE(angle));
}

Alam Ed Arias committed
186 187 188 189 190
//
// P_AutoPause
// Returns true when gameplay should be halted even if the game isn't necessarily paused.
//
boolean P_AutoPause(void)
Alam Ed Arias committed
191
{
Alam Ed Arias committed
192
	// Don't pause even on menu-up or focus-lost in netgames or record attack
szv committed
193
	if (netgame || modeattacking || gamestate == GS_TITLESCREEN)
Alam Ed Arias committed
194 195
		return false;

196
	return (menuactive || ( window_notinfocus && cv_pauseifunfocused.value ));
Alam Ed Arias committed
197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215
}

//
// P_CalcHeight
// Calculate the walking / running height adjustment
//
void P_CalcHeight(player_t *player)
{
	INT32 angle;
	fixed_t bob;
	fixed_t pviewheight;
	mobj_t *mo = player->mo;

	// Regular movement bobbing.
	// Should not be calculated when not on ground (FIXTHIS?)
	// OPTIMIZE: tablify angle
	// Note: a LUT allows for effects
	//  like a ramp with low health.

Sal committed
216 217 218
	player->bob = FixedMul(cv_movebob.value,
		(FixedMul(player->rmomx,player->rmomx)
		+ FixedMul(player->rmomy,player->rmomy))>>2);
Alam Ed Arias committed
219

Sal committed
220 221
	if (player->bob > FixedMul(cv_movebob.value, FixedMul(MAXBOB, mo->scale)))
		player->bob = FixedMul(cv_movebob.value, FixedMul(MAXBOB, mo->scale));
Alam Ed Arias committed
222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243

	if (!P_IsObjectOnGround(mo))
	{
		if (mo->eflags & MFE_VERTICALFLIP)
		{
			player->viewz = mo->z + mo->height - player->viewheight;
			if (player->viewz < mo->floorz + FixedMul(FRACUNIT, mo->scale))
				player->viewz = mo->floorz + FixedMul(FRACUNIT, mo->scale);
		}
		else
		{
			player->viewz = mo->z + player->viewheight;
			if (player->viewz > mo->ceilingz - FixedMul(FRACUNIT, mo->scale))
				player->viewz = mo->ceilingz - FixedMul(FRACUNIT, mo->scale);
		}
		return;
	}

	angle = (FINEANGLES/20*localgametic)&FINEMASK;
	bob = FixedMul(player->bob/2, FINESINE(angle));

	// move viewheight
Sal committed
244
	pviewheight = FixedMul(41*player->height/48, mo->scale); // default eye view height
Alam Ed Arias committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290

	if (player->playerstate == PST_LIVE)
	{
		player->viewheight += player->deltaviewheight;

		if (player->viewheight > pviewheight)
		{
			player->viewheight = pviewheight;
			player->deltaviewheight = 0;
		}

		if (player->viewheight < pviewheight/2)
		{
			player->viewheight = pviewheight/2;
			if (player->deltaviewheight <= 0)
				player->deltaviewheight = 1;
		}

		if (player->deltaviewheight)
		{
			player->deltaviewheight += FixedMul(FRACUNIT/4, mo->scale);
			if (!player->deltaviewheight)
				player->deltaviewheight = 1;
		}
	}

	if (player->mo->eflags & MFE_VERTICALFLIP)
		player->viewz = mo->z + mo->height - player->viewheight - bob;
	else
		player->viewz = mo->z + player->viewheight + bob;

	if (player->viewz > mo->ceilingz-FixedMul(4*FRACUNIT, mo->scale))
		player->viewz = mo->ceilingz-FixedMul(4*FRACUNIT, mo->scale);
	if (player->viewz < mo->floorz+FixedMul(4*FRACUNIT, mo->scale))
		player->viewz = mo->floorz+FixedMul(4*FRACUNIT, mo->scale);
}

/** Decides if a player is moving.
  * \param pnum The player number to test.
  * \return True if the player is considered to be moving.
  * \author Graue <graue@oceanbase.org>
  */
boolean P_PlayerMoving(INT32 pnum)
{
	player_t *p = &players[pnum];

Alam Ed Arias committed
291 292 293
	if (!Playing())
		return false;

Alam Ed Arias committed
294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
	if (p->jointime < 5*TICRATE || p->playerstate == PST_DEAD || p->playerstate == PST_REBORN || p->spectator)
		return false;

	return gamestate == GS_LEVEL && p->mo && p->mo->health > 0
		&& (abs(p->rmomx) >= FixedMul(FRACUNIT/2, p->mo->scale)
			|| abs(p->rmomy) >= FixedMul(FRACUNIT/2, p->mo->scale)
			|| abs(p->mo->momz) >= FixedMul(FRACUNIT/2, p->mo->scale)
			|| p->climbing || p->powers[pw_tailsfly]
			|| (p->pflags & PF_JUMPED) || (p->pflags & PF_SPINNING));
}

// P_GetNextEmerald
//
// Gets the number (0 based) of the next emerald to obtain
//
UINT8 P_GetNextEmerald(void)
{
311
	if (gamemap >= sstage_start && gamemap <= sstage_end)
Alam Ed Arias committed
312
		return (UINT8)(gamemap - sstage_start);
313 314 315
	if (gamemap >= smpstage_start || gamemap <= smpstage_end)
		return (UINT8)(gamemap - smpstage_start);
	return 0;
Alam Ed Arias committed
316 317 318 319 320 321 322 323 324 325
}

//
// P_GiveEmerald
//
// Award an emerald upon completion
// of a special stage.
//
void P_GiveEmerald(boolean spawnObj)
{
toaster committed
326
	UINT8 em = P_GetNextEmerald();
Alam Ed Arias committed
327 328 329

	S_StartSound(NULL, sfx_cgot); // Got the emerald!
	emeralds |= (1 << em);
330
	stagefailed = false;
Alam Ed Arias committed
331

332
	if (spawnObj)
Alam Ed Arias committed
333
	{
toaster committed
334
		// The Chaos Emerald begins to orbit us!
335 336 337 338 339 340 341 342 343 344 345 346 347
		// Only visibly give it to ONE person!
		UINT8 i, pnum = ((playeringame[consoleplayer]) && (!players[consoleplayer].spectator) && (players[consoleplayer].mo)) ? consoleplayer : 255;
		for (i = 0; i < MAXPLAYERS; i++)
		{
			mobj_t *emmo;
			if (!playeringame[i])
				continue;
			if (players[i].spectator)
				continue;
			if (!players[i].mo)
				continue;

			emmo = P_SpawnMobjFromMobj(players[i].mo, 0, 0, players[i].mo->height, MT_GOTEMERALD);
348 349
			if (!emmo)
				continue;
350 351
			P_SetTarget(&emmo->target, players[i].mo);
			P_SetMobjState(emmo, mobjinfo[MT_GOTEMERALD].meleestate + em);
Alam Ed Arias committed
352

353
			// Make sure we're not being carried before our tracer is changed
Tatsuru committed
354
			if (players[i].powers[pw_carry] != CR_NIGHTSMODE)
355
				players[i].powers[pw_carry] = CR_NONE;
Alam Ed Arias committed
356

357 358 359 360
			P_SetTarget(&players[i].mo->tracer, emmo);

			if (pnum == 255)
			{
361
				pnum = i;
362 363 364 365 366 367 368 369
				continue;
			}

			if (i == pnum)
				continue;

			emmo->flags2 |= MF2_DONTDRAW;
		}
Alam Ed Arias committed
370 371 372
	}
}

Tatsuru committed
373 374 375 376 377 378 379 380
//
// P_GiveFinishFlags
//
// Give the player visual indicators
// that they've finished the map.
//
void P_GiveFinishFlags(player_t *player)
{
Tatsuru committed
381
	angle_t angle = FixedAngle(player->mo->angle << FRACBITS);
Tatsuru committed
382
	UINT8 i;
Tatsuru committed
383

Tatsuru committed
384 385
	if (!player->mo)
		return;
Tatsuru committed
386

Tatsuru committed
387
	if (!(netgame||multiplayer))
Tatsuru committed
388 389
		return;

Tatsuru committed
390
	for (i = 0; i < 3; i++)
Tatsuru committed
391 392 393 394 395 396 397
	{
		angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK;
		fixed_t xoffs = FINECOSINE(fa);
		fixed_t yoffs = FINESINE(fa);
		mobj_t* flag = P_SpawnMobjFromMobj(player->mo, xoffs, yoffs, 0, MT_FINISHFLAG);
		flag->angle = angle;
		angle += FixedAngle(120*FRACUNIT);
398

Tatsuru committed
399 400 401 402
		P_SetTarget(&flag->target, player->mo);
	}
}

toaster committed
403
#if 0
Alam Ed Arias committed
404 405 406
//
// P_ResetScore
//
Alam Ed Arias committed
407
// This is called when your chain is reset.
Alam Ed Arias committed
408 409
void P_ResetScore(player_t *player)
{
Alam Ed Arias committed
410
	// Formally a host for Chaos mode behavior
Alam Ed Arias committed
411 412 413

	player->scoreadd = 0;
}
toaster committed
414
#endif
Alam Ed Arias committed
415 416 417 418 419 420 421 422 423 424 425 426

//
// P_FindLowestMare
//
// Returns the lowest open mare available
//
UINT8 P_FindLowestMare(void)
{
	thinker_t *th;
	mobj_t *mo2;
	UINT8 mare = UINT8_MAX;

427
	if (gametyperules & GTR_RACE)
Alam Ed Arias committed
428 429 430 431
		return 0;

	// scan the thinkers
	// to find the egg capsule with the lowest mare
432
	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
Alam Ed Arias committed
433
	{
434
		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
Alam Ed Arias committed
435 436 437 438
			continue;

		mo2 = (mobj_t *)th;

439 440 441 442 443
		if (mo2->type != MT_EGGCAPSULE)
			continue;
		if (mo2->health <= 0)
			continue;

Alam Ed Arias committed
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479
		{
			const UINT8 threshold = (UINT8)mo2->threshold;
			if (mare == 255)
				mare = threshold;
			else if (threshold < mare)
				mare = threshold;
		}
	}

	CONS_Debug(DBG_NIGHTS, "Lowest mare found: %d\n", mare);

	return mare;
}

//
// P_TransferToNextMare
//
// Transfers the player to the next Mare.
// (Finds the lowest mare # for capsules that have not been destroyed).
// Returns true if successful, false if there is no other mare.
//
boolean P_TransferToNextMare(player_t *player)
{
	thinker_t *th;
	mobj_t *mo2;
	mobj_t *closestaxis = NULL;
	INT32 lowestaxisnum = -1;
	UINT8 mare = P_FindLowestMare();
	fixed_t dist1, dist2 = 0;

	if (mare == 255)
		return false;

	CONS_Debug(DBG_NIGHTS, "Mare is %d\n", mare);

	player->mare = mare;
480 481
	player->marelap = 0;
	player->marebonuslap = 0;
Alam Ed Arias committed
482 483 484

	// scan the thinkers
	// to find the closest axis point
485
	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
Alam Ed Arias committed
486
	{
487
		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
Alam Ed Arias committed
488 489 490 491
			continue;

		mo2 = (mobj_t *)th;

492 493 494 495 496 497 498
		if (mo2->type != MT_AXIS)
			continue;

		if (mo2->threshold != mare)
			continue;

		if (closestaxis == NULL)
Alam Ed Arias committed
499
		{
500 501 502 503 504 505 506
			closestaxis = mo2;
			lowestaxisnum = mo2->health;
			dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
		}
		else if (mo2->health < lowestaxisnum)
		{
			dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
Alam Ed Arias committed
507

508 509 510 511 512
			if (dist1 < dist2)
			{
				closestaxis = mo2;
				lowestaxisnum = mo2->health;
				dist2 = dist1;
Alam Ed Arias committed
513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535
			}
		}
	}

	if (closestaxis == NULL)
		return false;

	P_SetTarget(&player->mo->target, closestaxis);
	return true;
}

//
// P_FindAxis
//
// Given a mare and axis number, returns
// the mobj for that axis point.
static mobj_t *P_FindAxis(INT32 mare, INT32 axisnum)
{
	thinker_t *th;
	mobj_t *mo2;

	// scan the thinkers
	// to find the closest axis point
536
	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
Alam Ed Arias committed
537
	{
538
		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
Alam Ed Arias committed
539 540 541 542 543 544 545 546
			continue;

		mo2 = (mobj_t *)th;

		// Axis things are only at beginning of list.
		if (!(mo2->flags2 & MF2_AXIS))
			return NULL;

547 548 549 550 551 552 553
		if (mo2->type != MT_AXIS)
			continue;
		if (mo2->health != axisnum)
			continue;
		if (mo2->threshold != mare)
			continue;
		return mo2;
Alam Ed Arias committed
554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570
	}

	return NULL;
}

//
// P_FindAxisTransfer
//
// Given a mare and axis number, returns
// the mobj for that axis transfer point.
static mobj_t *P_FindAxisTransfer(INT32 mare, INT32 axisnum, mobjtype_t type)
{
	thinker_t *th;
	mobj_t *mo2;

	// scan the thinkers
	// to find the closest axis point
571
	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
Alam Ed Arias committed
572
	{
573
		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
Alam Ed Arias committed
574 575 576 577 578 579 580 581
			continue;

		mo2 = (mobj_t *)th;

		// Axis things are only at beginning of list.
		if (!(mo2->flags2 & MF2_AXIS))
			return NULL;

582 583 584 585 586 587 588
		if (mo2->type != type)
			continue;
		if (mo2->health != axisnum)
			continue;
		if (mo2->threshold != mare)
			continue;
		return mo2;
Alam Ed Arias committed
589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
	}

	return NULL;
}

//
// P_TransferToAxis
//
// Finds the CLOSEST axis with the number specified.
void P_TransferToAxis(player_t *player, INT32 axisnum)
{
	thinker_t *th;
	mobj_t *mo2;
	mobj_t *closestaxis;
	INT32 mare = player->mare;
	fixed_t dist1, dist2 = 0;

	CONS_Debug(DBG_NIGHTS, "Transferring to axis %d\nLeveltime: %u...\n", axisnum, leveltime);

	closestaxis = NULL;

	// scan the thinkers
	// to find the closest axis point
612
	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
Alam Ed Arias committed
613
	{
614
		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
Alam Ed Arias committed
615 616 617 618
			continue;

		mo2 = (mobj_t *)th;

619 620 621 622 623 624 625 626
		if (mo2->type != MT_AXIS)
			continue;
		if (mo2->health != axisnum)
			continue;
		if (mo2->threshold != mare)
			continue;

		if (closestaxis == NULL)
Alam Ed Arias committed
627
		{
628 629 630 631 632 633
			closestaxis = mo2;
			dist2 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
		}
		else
		{
			dist1 = R_PointToDist2(player->mo->x, player->mo->y, mo2->x, mo2->y) - mo2->radius;
Alam Ed Arias committed
634

635 636 637 638
			if (dist1 < dist2)
			{
				closestaxis = mo2;
				dist2 = dist1;
Alam Ed Arias committed
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664
			}
		}
	}

	if (!closestaxis)
	{
		CONS_Debug(DBG_NIGHTS, "ERROR: Specified axis point to transfer to not found!\n%d\n", axisnum);
	}
	else
	{
		CONS_Debug(DBG_NIGHTS, "Transferred to axis %d, mare %d\n", closestaxis->health, closestaxis->threshold);
	}

	P_SetTarget(&player->mo->target, closestaxis);
}

//
// P_DeNightserizePlayer
//
// Whoops! Ran out of NiGHTS time!
//
static void P_DeNightserizePlayer(player_t *player)
{
	thinker_t *th;
	mobj_t *mo2;

665
	player->powers[pw_carry] = CR_NIGHTSFALL;
Alam Ed Arias committed
666 667

	player->powers[pw_underwater] = 0;
668
	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SPINNING|PF_DRILLING|PF_TRANSFERTOCLOSEST);
Alam Ed Arias committed
669 670 671 672 673
	player->secondjump = 0;
	player->homing = 0;
	player->climbing = 0;
	player->mo->fuse = 0;
	player->speed = 0;
674 675
	player->marelap = 0;
	player->marebonuslap = 0;
676 677
	player->flyangle = 0;
	player->anotherflyangle = 0;
Jaime Ita Passos committed
678 679
	player->mo->rollangle = 0;

Alam Ed Arias committed
680 681 682 683 684
	P_SetTarget(&player->mo->target, NULL);
	P_SetTarget(&player->axis1, P_SetTarget(&player->axis2, NULL));

	player->mo->flags &= ~MF_NOGRAVITY;

685
	player->mo->skin = &skins[player->skin];
686
	player->followitem = skins[player->skin].followitem;
687
	player->mo->color = player->skincolor;
688
	G_GhostAddColor(GHC_RETURNSKIN);
Alam Ed Arias committed
689 690 691 692 693 694 695

	// Restore aiming angle
	if (player == &players[consoleplayer])
		localaiming = 0;
	else if (player == &players[secondarydisplayplayer])
		localaiming2 = 0;

696
	P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
Alam Ed Arias committed
697 698 699 700 701 702

	// If in a special stage, add some preliminary exit time.
	if (G_IsSpecialStage(gamemap))
	{
		INT32 i;
		for (i = 0; i < MAXPLAYERS; i++)
703
			if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
Alam Ed Arias committed
704 705
				players[i].nightstime = 1; // force everyone else to fall too.
		player->exiting = 3*TICRATE;
706 707

		// If you screwed up, kiss your score and ring bonus goodbye.
708 709 710
		// But only do this in special stage (and instakill!) In regular stages, wait til we hit the ground.
		player->marescore = player->spheres =\
		 player->rings = 0;
Alam Ed Arias committed
711 712 713
	}

	// Check to see if the player should be killed.
714
	for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
Alam Ed Arias committed
715
	{
716
		if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
Alam Ed Arias committed
717 718 719 720 721 722
			continue;

		mo2 = (mobj_t *)th;
		if (!(mo2->type == MT_NIGHTSDRONE))
			continue;

723
		if (mo2->flags2 & MF2_AMBUSH)
724 725 726
		{
			player->marescore = player->spheres =\
			 player->rings = 0;
727
			P_DamageMobj(player->mo, NULL, NULL, 1, DMG_INSTAKILL);
Marco Z committed
728 729 730 731 732 733 734 735

			// Reset music to beginning if MIXNIGHTSCOUNTDOWN
			if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
				&& S_MusicType() != MU_MID
#endif
			)
				S_SetMusicPosition(0);
736
		}
Alam Ed Arias committed
737 738 739 740

		break;
	}

741 742 743 744
	if (player->mo->scale != player->oldscale)
		player->mo->destscale = player->oldscale;
	player->oldscale = 0;

Alam Ed Arias committed
745
	// Restore from drowning music
Marco Z committed
746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762
	if ((mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
#ifdef _WIN32
		&& S_MusicType() != MU_MID
#endif
	)
	{
		S_StopSoundByNum(sfx_timeup);
		S_StopFadingMusic();
		S_SetInternalMusicVolume(100);

		// Reset the music if you did not destroy all the capsules, because you failed.
		// Why make the all-capsules exception: because it's your reward for nearly finishing the level!
		// (unless the player auto-loses upon denightserizing; for death case, see above.)
		if (P_FindLowestMare() != UINT8_MAX || G_IsSpecialStage(gamemap))
			S_SetMusicPosition(0);
	}
	else
763 764
	{
		music_stack_fadein = 0; // HACK: Change fade-in for restore music
Marco Z committed
765
		P_RestoreMusic(player);
766
	}
Marco Z committed
767

768
	P_RunDeNightserizeExecutors(player->mo);
Alam Ed Arias committed
769
}
770

Alam Ed Arias committed
771 772 773 774 775 776
//
// P_NightserizePlayer
//
// NiGHTS Time!
void P_NightserizePlayer(player_t *player, INT32 nighttime)
{
777
	UINT8 oldmare, oldmarelap, oldmarebonuslap;
Alam Ed Arias committed
778

779
	// Bots can't be NiGHTSerized, silly!1 :P
Alam Ed Arias committed
780 781 782
	if (player->bot)
		return;

783
	if (player->powers[pw_carry] != CR_NIGHTSMODE)
784
	{
785
		player->mo->height = P_GetPlayerHeight(player); // Just to make sure jumping into the drone doesn't result in a squashed hitbox.
786
		player->oldscale = player->mo->scale;
787

788
		if (skins[player->skin].sprites[SPR2_NFLY].numframes == 0) // If you don't have a sprite for flying horizontally, use the default NiGHTS skin.
789 790 791 792 793 794 795
		{
			player->mo->skin = &skins[DEFAULTNIGHTSSKIN];
			if (!(cv_debug || devparm) && !(netgame || multiplayer || demoplayback))
				player->mo->color = skins[DEFAULTNIGHTSSKIN].prefcolor;
			player->followitem = skins[DEFAULTNIGHTSSKIN].followitem;
			G_GhostAddColor(GHC_NIGHTSSKIN);
		}
796
	}
Alam Ed Arias committed
797

798
	player->pflags &= ~(PF_SPINDOWN|PF_JUMPDOWN|PF_ATTACKDOWN|PF_STARTDASH|PF_GLIDING|PF_JUMPED|PF_NOJUMPDAMAGE|PF_THOKKED|PF_SHIELDABILITY|PF_SPINNING|PF_DRILLING);
Alam Ed Arias committed
799 800 801 802 803
	player->homing = 0;
	player->mo->fuse = 0;
	player->speed = 0;
	player->climbing = 0;
	player->secondjump = 0;
804 805
	player->flyangle = 0;
	player->anotherflyangle = 0;
Jaime Ita Passos committed
806
	player->mo->rollangle = 0;
Alam Ed Arias committed
807 808

	player->powers[pw_shield] = SH_NONE;
809
	player->powers[pw_super] = 0;
Alam Ed Arias committed
810 811 812

	player->mo->flags |= MF_NOGRAVITY;

813
	player->nightstime = player->startedtime = player->lapstartedtime = nighttime*TICRATE;
Alam Ed Arias committed
814 815
	player->bonustime = false;

Marco Z committed
816 817 818 819 820 821 822 823
	// Restore from drowning music
	if (mapheaderinfo[gamemap-1]->levelflags & LF_MIXNIGHTSCOUNTDOWN)
	{
		S_StopSoundByNum(sfx_timeup);
		S_StopFadingMusic();
		S_SetInternalMusicVolume(100);
	}
	else
824 825
	{
		music_stack_fadein = 0; // HACK: Change fade-in for restore music
Marco Z committed
826
		P_RestoreMusic(player);
827
	}
Marco Z committed
828

829
	if (gametyperules & GTR_RACE)
Alam Ed Arias committed
830 831 832 833 834 835 836 837 838 839 840
	{
		if (player->drillmeter < 48*20)
			player->drillmeter = 48*20;
	}
	else
	{
		if (player->drillmeter < 40*20)
			player->drillmeter = 40*20;
	}

	oldmare = player->mare;
841 842
	oldmarelap = player->marelap;
	oldmarebonuslap = player->marebonuslap;
Alam Ed Arias committed
843

toaster committed
844
	if (!P_TransferToNextMare(player))
Alam Ed Arias committed
845 846
	{
		INT32 i;
toaster committed
847
		INT32 total_spheres = 0;
Alam Ed Arias committed
848 849 850 851 852 853 854
		INT32 total_rings = 0;

		P_SetTarget(&player->mo->target, NULL);

		if (G_IsSpecialStage(gamemap))
		{
			for (i = 0; i < MAXPLAYERS; i++)
855
				if (playeringame[i]/* && players[i].powers[pw_carry] == CR_NIGHTSMODE*/)
856
				{
toaster committed
857
					total_spheres += players[i].spheres;
858
					total_rings += players[i].rings;
859
				}
Alam Ed Arias committed
860 861 862 863 864 865 866 867 868 869
		}

		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i] || !players[i].mo || players[i].spectator)
				continue;

			players[i].texttimer = (3 * TICRATE) - 10;
			players[i].textvar = 4; // Score and grades
			players[i].lastmare = players[i].mare;
870 871
			players[i].lastmarelap = players[i].marelap;
			players[i].lastmarebonuslap = players[i].marebonuslap;
Alam Ed Arias committed
872 873
			if (G_IsSpecialStage(gamemap))
			{
toaster committed
874
				players[i].finishedspheres = (INT16)total_spheres;
Alam Ed Arias committed
875
				players[i].finishedrings = (INT16)total_rings;
toaster committed
876
				P_AddPlayerScore(player, total_spheres * 50);
Alam Ed Arias committed
877 878 879
			}
			else
			{
toaster committed
880
				players[i].finishedspheres = (INT16)(players[i].spheres);
881
				players[i].finishedrings = (INT16)(players[i].rings);
toaster committed
882
				P_AddPlayerScore(&players[i], (players[i].spheres) * 50);
Alam Ed Arias committed
883 884 885 886 887 888 889
			}

			// Add score to leaderboards now
			if (!(netgame||multiplayer) && P_IsLocalPlayer(&players[i]))
				G_AddTempNightsRecords(players[i].marescore, leveltime - player->marebegunat, players[i].mare + 1);

			// transfer scores anyway
890
			players[i].totalmarescore += players[i].marescore;
Alam Ed Arias committed
891 892 893
			players[i].lastmarescore = players[i].marescore;
			players[i].marescore = 0;

894
			players[i].spheres = players[i].rings = 0;
Alam Ed Arias committed
895 896 897 898 899 900
			P_DoPlayerExit(&players[i]);
		}
	}
	else if (oldmare != player->mare)
	{
		/// \todo Handle multi-mare special stages.
toaster committed
901 902
		// Spheres bonus
		P_AddPlayerScore(player, (player->spheres) * 50);
Alam Ed Arias committed
903

904 905 906
		player->lastmare = oldmare;
		player->lastmarelap = oldmarelap;
		player->lastmarebonuslap = oldmarebonuslap;
Alam Ed Arias committed
907 908
		player->texttimer = 4*TICRATE;
		player->textvar = 4; // Score and grades
toaster committed
909
		player->finishedspheres = (INT16)(player->spheres);
910
		player->finishedrings = (INT16)(player->rings);
Alam Ed Arias committed
911 912 913 914 915 916

		// Add score to temp leaderboards
		if (!(netgame||multiplayer) && P_IsLocalPlayer(player))
			G_AddTempNightsRecords(player->marescore, leveltime - player->marebegunat, (UINT8)(oldmare + 1));

		// Starting a new mare, transfer scores
Marco Z committed
917
		player->totalmarescore += player->marescore;
Alam Ed Arias committed
918 919 920
		player->lastmarescore = player->marescore;
		player->marescore = 0;
		player->marebegunat = leveltime;
921
		player->lapbegunat = leveltime;
Alam Ed Arias committed
922

923
		player->spheres = player->rings = 0;
Alam Ed Arias committed
924 925 926 927 928 929 930 931
	}
	else
	{
		player->textvar = 5; // Nothing, just tells it to go to the GET n RINGS/SPHERES text in a bit
		player->texttimer = 40;

		// Don't show before title card
		// Not consistency safe, but this only affects drawing
932 933
		if (timeinmap + 40 < (110 - 70))
			player->texttimer = (UINT8)((110 - 70) - timeinmap);
Alam Ed Arias committed
934 935
	}

936 937 938
	if (player->drone && player->drone->scale != player->mo->scale)
		player->mo->destscale = player->drone->scale;

939
	// force NiGHTS to face forward or backward
940
	if (player->mo->target)
941 942
	{
		player->angle_pos = R_PointToAngle2(player->mo->target->x, player->mo->target->y, player->mo->x, player->mo->y);
943
		player->drawangle = player->angle_pos
mazmazz committed
944
			+ ((player->mo->target->flags2 & MF2_AMBUSH) ? // if axis is invert, take the opposite right angle
945 946 947 948
				-ANGLE_90 : ANGLE_90); // flyangle is always 0 here, below is kept for posterity
				/*(player->flyangle > 90 && player->flyangle < 270 ? ANGLE_90 : -ANGLE_90)
				: (player->flyangle > 90 && player->flyangle < 270 ? -ANGLE_90 : ANGLE_90));*/
	}
949

950
	// Do this before setting CR_NIGHTSMODE so we can tell if player was non-NiGHTS
Marco Z committed
951
	P_RunNightserizeExecutors(player->mo);
952

953
	player->powers[pw_carry] = CR_NIGHTSMODE;
954
	P_SetPlayerMobjState(player->mo, S_PLAY_NIGHTS_TRANS1);
Alam Ed Arias committed
955 956
}

toaster committed
957 958 959 960 961
pflags_t P_GetJumpFlags(player_t *player)
{
	if (player->charflags & SF_NOJUMPDAMAGE)
		return (PF_JUMPED|PF_NOJUMPDAMAGE);
	return PF_JUMPED;
Alam Ed Arias committed
962 963 964 965 966 967 968 969 970 971 972 973 974 975
}

//
// P_PlayerInPain
//
// Is player in pain??
// Checks for painstate and pw_flashing, if both found return true
//
boolean P_PlayerInPain(player_t *player)
{
	// no silly, sliding isn't pain
	if (!(player->pflags & PF_SLIDING) && player->mo->state == &states[player->mo->info->painstate] && player->powers[pw_flashing])
		return true;

976 977 978
	if (player->mo->state == &states[S_PLAY_STUN])
		return true;

Alam Ed Arias committed
979 980 981 982 983 984 985 986 987 988 989
	return false;
}

//
// P_DoPlayerPain
//
// Player was hit,
// put them in pain.
//
void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor)
{
toaster committed
990 991
	if (player->powers[pw_carry] == CR_ROPEHANG)
		P_SetTarget(&player->mo->tracer, NULL);
Alam Ed Arias committed
992

toaster committed
993 994 995
	{
		angle_t ang;
		fixed_t fallbackspeed;
Alam Ed Arias committed
996

toaster committed
997 998
		P_ResetPlayer(player);
		P_SetPlayerMobjState(player->mo, player->mo->info->painstate);
Alam Ed Arias committed
999

toaster committed
1000 1001 1002 1003 1004 1005 1006 1007 1008
		if (player->mo->eflags & MFE_VERTICALFLIP)
			player->mo->z--;
		else
			player->mo->z++;

		if (player->mo->eflags & MFE_UNDERWATER)
			P_SetObjectMomZ(player->mo, FixedDiv(10511*FRACUNIT,2600*FRACUNIT), false);
		else
			P_SetObjectMomZ(player->mo, FixedDiv(69*FRACUNIT,10*FRACUNIT), false);
Alam Ed Arias committed
1009

toaster committed
1010
		if (inflictor)
Alam Ed Arias committed
1011
		{
1012 1013 1014 1015
			if (inflictor->type == MT_WALLSPIKE)
				ang = inflictor->angle;
			else
				ang = R_PointToAngle2(inflictor->x-inflictor->momx, inflictor->y - inflictor->momy, player->mo->x - player->mo->momx, player->mo->y - player->mo->momy);
Alam Ed Arias committed
1016

toaster committed
1017 1018 1019 1020
			// explosion and rail rings send you farther back, making it more difficult
			// to recover
			if ((inflictor->flags2 & MF2_SCATTER) && source)
			{
1021
				fixed_t dist = P_AproxDistance(P_AproxDistance(source->x-player->mo->x, source->y-player->mo->y), source->z-player->mo->z);
Alam Ed Arias committed
1022

toaster committed
1023
				dist = FixedMul(128*FRACUNIT, inflictor->scale) - dist/4;
Alam Ed Arias committed
1024

toaster committed
1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038
				if (dist < FixedMul(4*FRACUNIT, inflictor->scale))
					dist = FixedMul(4*FRACUNIT, inflictor->scale);

				fallbackspeed = dist;
			}
			else if (inflictor->flags2 & MF2_EXPLOSION)
			{
				if (inflictor->flags2 & MF2_RAILRING)
					fallbackspeed = FixedMul(38*FRACUNIT, inflictor->scale); // 7x
				else
					fallbackspeed = FixedMul(30*FRACUNIT, inflictor->scale); // 5x
			}
			else if (inflictor->flags2 & MF2_RAILRING)
				fallbackspeed = FixedMul(45*FRACUNIT, inflictor->scale); // 4x
Alam Ed Arias committed
1039
			else
toaster committed
1040
				fallbackspeed = FixedMul(4*FRACUNIT, inflictor->scale); // the usual amount of force
Alam Ed Arias committed
1041 1042
		}
		else
toaster committed
1043
		{
toaster committed
1044
			ang = ((player->mo->momx || player->mo->momy) ? R_PointToAngle2(player->mo->momx, player->mo->momy, 0, 0) : player->drawangle);
toaster committed
1045 1046
			fallbackspeed = FixedMul(4*FRACUNIT, player->mo->scale);
		}
Alam Ed Arias committed
1047

1048
		player->drawangle = ang + ANGLE_180;
toaster committed
1049 1050
		P_InstaThrust(player->mo, ang, fallbackspeed);
	}
Alam Ed Arias committed
1051 1052 1053

	// Point penalty for hitting a hazard during tag.
	// Discourages players from intentionally hurting themselves to avoid being tagged.
1054 1055
	if (((gametyperules & (GTR_TAG|GTR_HIDEFROZEN)) == GTR_TAG)
	&& (!(player->pflags & PF_GAMETYPEOVER) && !(player->pflags & PF_TAGIT)))
Alam Ed Arias committed
1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074
	{
		if (player->score >= 50)
			player->score -= 50;
		else
			player->score = 0;
	}

	player->powers[pw_flashing] = flashingtics;

	if (player->timeshit != UINT8_MAX)
		++player->timeshit;
}

//
// P_ResetPlayer
//
// Useful when you want to kill everything the player is doing.
void P_ResetPlayer(player_t *player)
{
1075
	player->pflags &= ~(PF_SPINNING|PF_STARTDASH|PF_STARTJUMP|PF_JUMPED|PF_NOJUMPDAMAGE|PF_GLIDING|PF_THOKKED|PF_CANCARRY|PF_SHIELDABILITY|PF_BOUNCING);
1076

1077 1078 1079 1080 1081
	if (player->powers[pw_carry] == CR_ROLLOUT)
	{
		if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer))
		{
			player->mo->tracer->flags |= MF_PUSHABLE;
lachwright committed
1082
			P_SetTarget(&player->mo->tracer->tracer, NULL);
1083 1084 1085 1086 1087
		}
		P_SetTarget(&player->mo->tracer, NULL);
		player->powers[pw_carry] = CR_NONE;
	}

1088
	if (!(player->powers[pw_carry] == CR_NIGHTSMODE || player->powers[pw_carry] == CR_NIGHTSFALL || player->powers[pw_carry] == CR_BRAKGOOP || player->powers[pw_carry] == CR_MINECART))
1089 1090
		player->powers[pw_carry] = CR_NONE;

Alam Ed Arias committed
1091 1092 1093 1094 1095 1096 1097 1098
	player->secondjump = 0;
	player->glidetime = 0;
	player->homing = 0;
	player->climbing = 0;
	player->powers[pw_tailsfly] = 0;
	player->onconveyor = 0;
	player->skidtime = 0;
	if (player-players == consoleplayer && botingame)
1099
		CV_SetValue(&cv_analog[1], true);
Alam Ed Arias committed
1100 1101
}

1102 1103 1104 1105 1106 1107
// P_PlayerCanDamage
//
// Can player do damage?
//
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing)
{
1108 1109
	fixed_t bottomheight, topheight;

1110 1111 1112
	if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing))
		return false;

toaster committed
1113 1114 1115 1116 1117 1118 1119 1120 1121 1122
	{
		UINT8 shouldCollide = LUAh_PlayerCanDamage(player, thing);
		if (P_MobjWasRemoved(thing))
			return false; // removed???
		if (shouldCollide == 1)
			return true; // force yes
		else if (shouldCollide == 2)
			return false; // force no
	}

1123 1124 1125 1126 1127
	// Invinc/super. Not for Monitors.
	if (!(thing->flags & MF_MONITOR) && (player->powers[pw_invulnerability] || player->powers[pw_super]))
		return true;

	// NiGHTS drill. Wasn't originally for monitors, but that's more an oversight being corrected than anything else.
1128 1129 1130
	if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
		return true;

1131
	// Jumping.
1132 1133 1134 1135 1136
	if ((player->pflags & PF_JUMPED)
	&& (!(player->pflags & PF_NOJUMPDAMAGE)
		|| (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
		return true;

1137 1138
	// Spinning.
	if (player->pflags & PF_SPINNING)
1139
		return true;
Jaime Ita Passos committed
1140

lachwright committed
1141
	if (player->dashmode >= DASHMODE_THRESHOLD && (player->charflags & (SF_DASHMODE|SF_MACHINE)) == (SF_DASHMODE|SF_MACHINE))
1142
		return true;
1143

1144 1145 1146
	// From the front.
	if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
	&& (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) +  + ANGLE_90) < ANGLE_180)
1147 1148
		return true;

1149
	// From the top/bottom.
1150 1151 1152 1153
	bottomheight = player->mo->z;
	topheight = player->mo->z + player->mo->height;

	if (player->mo->eflags & MFE_VERTICALFLIP)
1154
	{
1155 1156 1157 1158 1159 1160
		fixed_t swap = bottomheight;
		bottomheight = topheight;
		topheight = swap;
	}

	if (P_MobjFlip(player->mo)*(bottomheight - (thing->z + thing->height/2)) > 0)
1161
	{
1162 1163 1164 1165 1166
		if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) < 0))
			return true;
	}
	else if (P_MobjFlip(player->mo)*(topheight - (thing->z + thing->height/2)) < 0)
	{
toaster committed
1167
		if (player->charability == CA_FLY && player->panim == PA_ABILITY && !(player->mo->eflags & MFE_UNDERWATER) && (P_MobjFlip(player->mo)*(player->mo->momz - thing->momz) > 0))
1168 1169
			return true;
	}
1170

1171
	// Shield stomp.
1172 1173 1174 1175 1176 1177 1178 1179
	if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY))
		return true;

	return false;
}



Alam Ed Arias committed
1180 1181 1182 1183 1184 1185
//
// P_GivePlayerRings
//
// Gives rings to the player, and does any special things required.
// Call this function when you want to increment the player's health.
//
1186

Alam Ed Arias committed
1187 1188
void P_GivePlayerRings(player_t *player, INT32 num_rings)
{
1189 1190 1191
	if (!player)
		return;

Alam Ed Arias committed
1192 1193 1194 1195 1196 1197
	if (player->bot)
		player = &players[consoleplayer];

	if (!player->mo)
		return;

1198
	player->rings += num_rings;
Alam Ed Arias committed
1199

toaster committed
1200
	player->totalring += num_rings;
Alam Ed Arias committed
1201 1202

	// Can only get up to 9999 rings, sorry!
1203 1204 1205 1206
	if (player->rings > 9999)
		player->rings = 9999;
	else if (player->rings < 0)
		player->rings = 0;
Alam Ed Arias committed
1207 1208

	// Now extra life bonuses are handled here instead of in P_MovePlayer, since why not?
1209
	if (!ultimatemode && !modeattacking && !G_IsSpecialStage(gamemap) && G_GametypeUsesLives() && player->lives != INFLIVES)
Alam Ed Arias committed
1210 1211 1212
	{
		INT32 gainlives = 0;

1213
		while (player->xtralife < maxXtraLife && player->rings >= 100 * (player->xtralife+1))
Alam Ed Arias committed
1214 1215 1216 1217 1218 1219 1220
		{
			++gainlives;
			++player->xtralife;
		}

		if (gainlives)
		{
1221 1222 1223 1224 1225 1226
			player->lives += gainlives;
			if (player->lives > 99)
				player->lives = 99;
			else if (player->lives < 1)
				player->lives = 1;

Alam Ed Arias committed
1227 1228 1229 1230 1231
			P_PlayLivesJingle(player);
		}
	}
}

toaster committed
1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251
void P_GivePlayerSpheres(player_t *player, INT32 num_spheres)
{
	if (!player)
		return;

	if (player->bot)
		player = &players[consoleplayer];

	if (!player->mo)
		return;

	player->spheres += num_spheres;

	// Can only get up to 9999 spheres, sorry!
	if (player->spheres > 9999)
		player->spheres = 9999;
	else if (player->spheres < 0)
		player->spheres = 0;
}

Alam Ed Arias committed
1252 1253 1254 1255 1256 1257 1258 1259
//
// P_GivePlayerLives
//
// Gives the player an extra life.
// Call this function when you want to add lives to the player.
//
void P_GivePlayerLives(player_t *player, INT32 numlives)
{
1260
	UINT8 prevlives = player->lives;
1261 1262 1263 1264 1265 1266 1267 1268
	if (!player)
		return;

	if (player->bot)
		player = &players[consoleplayer];

	if (gamestate == GS_LEVEL)
	{
1269
		if (player->lives == INFLIVES || !(gametyperules & GTR_LIVES))
1270 1271 1272 1273 1274
		{
			P_GivePlayerRings(player, 100*numlives);
			return;
		}

1275
		if ((netgame || multiplayer) && G_GametypeUsesCoopLives() && cv_cooplives.value == 0)
1276 1277 1278
		{
			P_GivePlayerRings(player, 100*numlives);
			if (player->lives - prevlives >= numlives)
1279
				goto docooprespawn;
1280 1281 1282 1283

			numlives = (numlives + prevlives - player->lives);
		}
	}
1284 1285
	else if (player->lives == INFLIVES)
		return;
1286

Alam Ed Arias committed
1287 1288 1289 1290 1291 1292
	player->lives += numlives;

	if (player->lives > 99)
		player->lives = 99;
	else if (player->lives < 1)
		player->lives = 1;
1293 1294 1295 1296 1297 1298 1299 1300 1301

docooprespawn:
	if (cv_coopstarposts.value)
		return;
	if (prevlives > 0)
		return;
	if (!player->spectator)
		return;
	P_SpectatorJoinGame(player);
Alam Ed Arias committed
1302 1303
}

1304
void P_GiveCoopLives(player_t *player, INT32 numlives, boolean sound)
1305
{
1306
	if (!((netgame || multiplayer) && G_GametypeUsesCoopLives()))
1307
	{
1308
		P_GivePlayerLives(player, numlives);
1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319
		if (sound)
			P_PlayLivesJingle(player);
	}
	else
	{
		INT32 i;
		for (i = 0; i < MAXPLAYERS; i++)
		{
			if (!playeringame[i])
				continue;

1320
			P_GivePlayerLives(&players[i], numlives);
1321 1322 1323 1324 1325 1326
			if (sound)
				P_PlayLivesJingle(&players[i]);
		}
	}
}

Alam Ed Arias committed
1327 1328 1329 1330 1331 1332 1333 1334
//
// P_DoSuperTransformation
//
// Transform into Super Sonic!
void P_DoSuperTransformation(player_t *player, boolean giverings)
{
	player->powers[pw_super] = 1;
	if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC) && P_IsLocalPlayer(player))
1335
		P_PlayJingle(player, JT_SUPER);
Alam Ed Arias committed
1336 1337 1338

	S_StartSound(NULL, sfx_supert); //let all players hear it -mattw_cfi

toaster committed
1339 1340
	player->mo->momx = player->mo->momy = player->mo->momz = player->cmomx = player->cmomy = player->rmomx = player->rmomy = 0;

Alam Ed Arias committed
1341
	// Transformation animation
1342
	P_SetPlayerMobjState(player->mo, S_PLAY_SUPER_TRANS1);
Alam Ed Arias committed
1343

Zolton Auburn committed
1344
	if (giverings && player->rings < 50)
1345
		player->rings = 50;
Alam Ed Arias committed
1346 1347 1348 1349 1350 1351

	// Just in case.
	if (!(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC))
	{
		player->powers[pw_extralife] = 0;
		player->powers[pw_invulnerability] = 0;
Alam Ed Arias committed
1352
		player->powers[pw_sneakers] = 0;
Alam Ed Arias committed
1353 1354
	}

1355
	if (!G_CoopGametype())
Alam Ed Arias committed
1356 1357 1358 1359 1360 1361 1362 1363
	{
		HU_SetCEchoFlags(0);
		HU_SetCEchoDuration(5);
		HU_DoCEcho(va("%s\\is now super.\\\\\\\\", player_names[player-players]));
	}

	P_PlayerFlagBurst(player, false);
}
1364

Alam Ed Arias committed
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
// Adds to the player's score
void P_AddPlayerScore(player_t *player, UINT32 amount)
{
	UINT32 oldscore;

	if (player->bot)
		player = &players[consoleplayer];

	// NiGHTS does it different!
	if (gamestate == GS_LEVEL && mapheaderinfo[gamemap-1]->typeoflevel & TOL_NIGHTS)
	{
		if ((netgame || multiplayer) && G_IsSpecialStage(gamemap))
		{ // Pseudo-shared score for multiplayer special stages.
			INT32 i;
			for (i = 0; i < MAXPLAYERS; i++)
1380
				if (playeringame[i] && players[i].powers[pw_carry] == CR_NIGHTSMODE)
Alam Ed Arias committed
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
				{
					oldscore = players[i].marescore;

					// Don't go above MAXSCORE.
					if (players[i].marescore + amount < MAXSCORE)
						players[i].marescore += amount;
					else
						players[i].marescore = MAXSCORE;

					// Continues are worthless in netgames.
					// If that stops being the case uncomment this.
1392
/*					if (!ultimatemode && continuesInSession && players[i].marescore > 50000
Alam Ed Arias committed
1393 1394 1395 1396 1397
					&& oldscore < 50000)
					{
						players[i].continues += 1;
						players[i].gotcontinue = true;
						if (P_IsLocalPlayer(player))
toaster committed
1398
							S_StartSound(NULL, sfx_s3kac);
Alam Ed Arias committed
1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411
					} */
				}
		}
		else
		{
			oldscore = player->marescore;

			// Don't go above MAXSCORE.
			if (player->marescore + amount < MAXSCORE)
				player->marescore += amount;
			else
				player->marescore = MAXSCORE;

1412
			if (!ultimatemode && continuesInSession && G_IsSpecialStage(gamemap)
Alam Ed Arias committed
1413 1414 1415 1416 1417
			&& player->marescore >= 50000 && oldscore < 50000)
			{
				player->continues += 1;
				player->gotcontinue = true;
				if (P_IsLocalPlayer(player))
toaster committed
1418
					S_StartSound(NULL, sfx_s3kac);
Alam Ed Arias committed
1419 1420 1421
			}
		}

1422
		if (G_CoopGametype())
Alam Ed Arias committed
1423 1424 1425 1426 1427 1428
			return;
	}

	oldscore = player->score;

	// Don't go above MAXSCORE.
1429 1430
	player->score += amount;
	if (player->score > MAXSCORE)
Alam Ed Arias committed
1431 1432 1433
		player->score = MAXSCORE;

	// check for extra lives every 50000 pts
1434
	if (!ultimatemode && !modeattacking && player->score > oldscore && player->score % 50000 < amount && (gametyperules & GTR_LIVES))
Alam Ed Arias committed
1435 1436 1437 1438 1439 1440
	{
		P_GivePlayerLives(player, (player->score/50000) - (oldscore/50000));
		P_PlayLivesJingle(player);
	}

	// In team match, all awarded points are incremented to the team's running score.
1441
	if ((gametyperules & (GTR_TEAMS|GTR_TEAMFLAGS)) == GTR_TEAMS)
Alam Ed Arias committed
1442 1443 1444 1445 1446 1447 1448 1449
	{
		if (player->ctfteam == 1)
			redscore += amount;
		else if (player->ctfteam == 2)
			bluescore += amount;
	}
}

1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474
// Steals from every enemy's score.
void P_StealPlayerScore(player_t *player, UINT32 amount)
{
	boolean teams = G_GametypeHasTeams();
	UINT32 stolen = 0;
	int i;
	for (i = 0; i < MAXPLAYERS; i++)
	{
		if (&players[i] == player
		|| (teams && players[i].ctfteam == player->ctfteam))
			continue;
		if (players[i].score >= amount)
		{
			stolen += amount;
			players[i].score -= amount;
		}
		else
		{
			stolen += players[i].score;
			players[i].score = 0;
		}
	}
	if (stolen > 0)
	{
		// In team match, all stolen points are removed from the enemy team's running score.
1475
		if ((gametyperules & (GTR_TEAMS|GTR_TEAMFLAGS)) == GTR_TEAMS)
1476 1477 1478 1479 1480 1481 1482 1483 1484 1485
		{
			if (player->ctfteam == 1)
				bluescore -= amount;
			else if (player->ctfteam == 2)
				redscore -= amount;
		}
		P_AddPlayerScore(player, stolen);
	}
}

Alam Ed Arias committed
1486 1487 1488 1489 1490 1491 1492 1493
//
// P_PlayLivesJingle
//
void P_PlayLivesJingle(player_t *player)
{
	if (player && !P_IsLocalPlayer(player))
		return;

1494
	if (mariomode)
Alam Ed Arias committed
1495
		S_StartSound(NULL, sfx_marioa);
1496 1497
	else if (use1upSound || cv_1upsound.value)
		S_StartSound(NULL, sfx_oneup);
Alam Ed Arias committed
1498 1499
	else
	{
1500
		P_PlayJingle(player, JT_1UP);
Alam Ed Arias committed
1501
		if (player)
1502
			player->powers[pw_extralife] = extralifetics + 1;
1503 1504
		strlcpy(S_sfx[sfx_None].caption, "One-up", 7);
		S_StartCaption(sfx_None, -1, extralifetics+1);
Alam Ed Arias committed
1505 1506 1507
	}
}

1508 1509 1510 1511 1512 1513 1514 1515
void P_PlayJingle(player_t *player, jingletype_t jingletype)
{
	const char *musname = jingleinfo[jingletype].musname;
	UINT16 musflags = 0;
	boolean looping = jingleinfo[jingletype].looping;

	char newmusic[7];
	strncpy(newmusic, musname, 7);
1516
#ifdef HAVE_LUA_MUSICPLUS
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530
 	if(LUAh_MusicJingle(jingletype, newmusic, &musflags, &looping))
 		return;
#endif
	newmusic[6] = 0;

	P_PlayJingleMusic(player, newmusic, musflags, looping, jingletype);
}

//
// P_PlayJingleMusic
//
void P_PlayJingleMusic(player_t *player, const char *musname, UINT16 musflags, boolean looping, UINT16 status)
{
	// If gamestate != GS_LEVEL, always play the jingle (1-up intermission)
1531
	if (gamestate == GS_LEVEL && player && !P_IsLocalPlayer(player))
1532 1533 1534 1535 1536 1537 1538
		return;

	S_RetainMusic(musname, musflags, looping, 0, status);
	S_StopMusic();
	S_ChangeMusicInternal(musname, looping);
}

1539
boolean P_EvaluateMusicStatus(UINT16 status, const char *musname)
1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596
{
	// \todo lua hook
	int i;
	boolean result = false;

	for (i = 0; i < MAXPLAYERS; i++)
	{
		if (!P_IsLocalPlayer(&players[i]))
			continue;

		switch(status)
		{
			case JT_1UP: // Extra life
				result = (players[i].powers[pw_extralife] > 1);
				break;

			case JT_SHOES:  // Speed shoes
				if (players[i].powers[pw_sneakers] > 1 && !players[i].powers[pw_super])
				{
					//strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
					//S_StartCaption(sfx_None, -1, players[i].powers[pw_sneakers]);
					result = true;
				}
				else
					result = false;
				break;

			case JT_INV: // Invincibility
			case JT_MINV: // Mario Invincibility
				if (players[i].powers[pw_invulnerability] > 1)
				{
					//strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
					//S_StartCaption(sfx_None, -1, players[i].powers[pw_invulnerability]);
					result = true;
				}
				else
					result = false;
				break;

			case JT_DROWN:  // Drowning
				result = (players[i].powers[pw_underwater] && players[i].powers[pw_underwater] <= 11*TICRATE + 1);
				break;

			case JT_SUPER:  // Super Sonic
				result = (players[i].powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC));
				break;

			case JT_GOVER: // Game Over
				result = (players[i].lives <= 0);
				break;

			case JT_NIGHTSTIMEOUT: // NiGHTS Time Out (10 seconds)
			case JT_SSTIMEOUT:
				result = (players[i].nightstime && players[i].nightstime <= 10*TICRATE);
				break;

			case JT_OTHER:  // Other state
1597
				result = LUAh_ShouldJingleContinue(&players[i], musname);
1598 1599 1600
				break;

			case JT_NONE:   // Null state
1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612
			case JT_MASTER: // Main level music
			default:
				result = true;
		}

		if (result)
			break;
 	}

	return result;
 }

Alam Ed Arias committed
1613 1614 1615 1616 1617 1618 1619 1620 1621 1622
//
// P_RestoreMusic
//
// Restores music after some special music change
//
void P_RestoreMusic(player_t *player)
{
	if (!P_IsLocalPlayer(player)) // Only applies to a local player
		return;

1623 1624 1625 1626 1627 1628
	S_SpeedMusic(1.0f);

	// Jingles have a priority in this order, so follow it
	// and as a default case, go down the music stack.

	// Extra life
Alam Ed Arias committed
1629 1630
	if (player->powers[pw_extralife] > 1)
		return;
1631 1632 1633 1634 1635 1636 1637

	// Super
	else if (player->powers[pw_super] && !(mapheaderinfo[gamemap-1]->levelflags & LF_NOSSMUSIC)
		&& !S_RecallMusic(JT_SUPER, false))
		P_PlayJingle(player, JT_SUPER);

	// Invulnerability
1638
	else if (player->powers[pw_invulnerability] > 1 && !player->powers[pw_super])
1639 1640 1641
	{
		strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
		S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
1642 1643
		if (!S_RecallMusic(JT_INV, false) && !S_RecallMusic(JT_MINV, false))
			P_PlayJingle(player, (mariomode) ? JT_MINV : JT_INV);
1644
	}
1645 1646

	// Shoes
Alam Ed Arias committed
1647 1648
	else if (player->powers[pw_sneakers] > 1 && !player->powers[pw_super])
	{
1649 1650
		strlcpy(S_sfx[sfx_None].caption, "Speed shoes", 12);
		S_StartCaption(sfx_None, -1, player->powers[pw_sneakers]);
Alam Ed Arias committed
1651 1652 1653
		if (mapheaderinfo[gamemap-1]->levelflags & LF_SPEEDMUSIC)
		{
			S_SpeedMusic(1.4f);
1654 1655
			if (!S_RecallMusic(JT_MASTER, true))
				S_ChangeMusicEx(mapmusname, mapmusflags, true, mapmusposition, 0, 0);
Alam Ed Arias committed
1656
		}
1657 1658
		else if (!S_RecallMusic(JT_SHOES, false))
			P_PlayJingle(player, JT_SHOES);
Alam Ed Arias committed
1659
	}
1660 1661 1662 1663 1664