mirror of
				https://github.com/KartKrewDev/RingRacers.git
				synced 2025-10-30 08:01:28 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			8270 lines
		
	
	
	
		
			257 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			8270 lines
		
	
	
	
		
			257 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SONIC ROBO BLAST 2 KART ~ ZarroTsu
 | 
						|
//-----------------------------------------------------------------------------
 | 
						|
/// \file  k_kart.c
 | 
						|
/// \brief SRB2kart general.
 | 
						|
///        All of the SRB2kart-unique stuff.
 | 
						|
 | 
						|
#include "doomdef.h"
 | 
						|
#include "hu_stuff.h"
 | 
						|
#include "g_game.h"
 | 
						|
#include "m_random.h"
 | 
						|
#include "p_local.h"
 | 
						|
#include "p_slopes.h"
 | 
						|
#include "r_draw.h"
 | 
						|
#include "r_local.h"
 | 
						|
#include "s_sound.h"
 | 
						|
#include "st_stuff.h"
 | 
						|
#include "v_video.h"
 | 
						|
#include "z_zone.h"
 | 
						|
#include "m_misc.h"
 | 
						|
#include "m_cond.h"
 | 
						|
#include "k_kart.h"
 | 
						|
#include "f_finale.h"
 | 
						|
#include "lua_hud.h"	// For Lua hud checks
 | 
						|
#include "lua_hook.h"	// For MobjDamage and ShouldDamage
 | 
						|
 | 
						|
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
 | 
						|
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
 | 
						|
// franticitems is Frantic Mode items, bool
 | 
						|
// encoremode is Encore Mode (duh), bool
 | 
						|
// comeback is Battle Mode's karma comeback, also bool
 | 
						|
// battlewanted is an array of the WANTED player nums, -1 for no player in that slot
 | 
						|
// indirectitemcooldown is timer before anyone's allowed another Shrink/SPB
 | 
						|
// mapreset is set when enough players fill an empty server
 | 
						|
// nospectategrief is the players in-game needed to eliminate the person in last
 | 
						|
 | 
						|
 | 
						|
//{ SRB2kart Color Code
 | 
						|
 | 
						|
#define SKIN_RAMP_LENGTH 16
 | 
						|
#define DEFAULT_STARTTRANSCOLOR 160
 | 
						|
#define NUM_PALETTE_ENTRIES 256
 | 
						|
 | 
						|
// These should be within 14 characters to fit on the character select screen
 | 
						|
const char *KartColor_Names[MAXSKINCOLORS] =
 | 
						|
{
 | 
						|
	"None",           // 00 // SKINCOLOR_NONE
 | 
						|
	"White",          // 01 // SKINCOLOR_WHITE
 | 
						|
	"Silver",         // 02 // SKINCOLOR_SILVER
 | 
						|
	"Grey",           // 03 // SKINCOLOR_GREY
 | 
						|
	"Nickel",         // 04 // SKINCOLOR_NICKEL
 | 
						|
	"Black",          // 05 // SKINCOLOR_BLACK
 | 
						|
	"Sepia",          // 06 // SKINCOLOR_SEPIA
 | 
						|
	"Beige",          // 07 // SKINCOLOR_BEIGE
 | 
						|
	"Brown",          // 08 // SKINCOLOR_BROWN
 | 
						|
	"Leather",        // 09 // SKINCOLOR_LEATHER
 | 
						|
	"Salmon",         // 10 // SKINCOLOR_SALMON
 | 
						|
	"Pink",           // 11 // SKINCOLOR_PINK
 | 
						|
	"Rose",           // 12 // SKINCOLOR_ROSE
 | 
						|
	"Ruby",           // 13 // SKINCOLOR_RUBY
 | 
						|
	"Raspberry",      // 14 // SKINCOLOR_RASPBERRY
 | 
						|
	"Red",            // 15 // SKINCOLOR_RED
 | 
						|
	"Crimson",        // 16 // SKINCOLOR_CRIMSON
 | 
						|
	"Ketchup",        // 17 // SKINCOLOR_KETCHUP
 | 
						|
	"Dawn",           // 18 // SKINCOLOR_DAWN
 | 
						|
	"Creamsicle",     // 19 // SKINCOLOR_CREAMSICLE
 | 
						|
	"Orange",         // 20 // SKINCOLOR_ORANGE
 | 
						|
	"Pumpkin",        // 21 // SKINCOLOR_PUMPKIN
 | 
						|
	"Rosewood",       // 22 // SKINCOLOR_ROSEWOOD
 | 
						|
	"Burgundy",       // 23 // SKINCOLOR_BURGUNDY
 | 
						|
	"Tangerine",      // 24 // SKINCOLOR_TANGERINE
 | 
						|
	"Peach",          // 25 // SKINCOLOR_PEACH
 | 
						|
	"Caramel",        // 26 // SKINCOLOR_CARAMEL
 | 
						|
	"Gold",           // 27 // SKINCOLOR_GOLD
 | 
						|
	"Bronze",         // 28 // SKINCOLOR_BRONZE
 | 
						|
	"Yellow",         // 29 // SKINCOLOR_YELLOW
 | 
						|
	"Mustard",        // 30 // SKINCOLOR_MUSTARD
 | 
						|
	"Olive",          // 31 // SKINCOLOR_OLIVE
 | 
						|
	"Vomit",          // 32 // SKINCOLOR_VOMIT
 | 
						|
	"Garden",         // 33 // SKINCOLOR_GARDEN
 | 
						|
	"Lime",           // 34 // SKINCOLOR_LIME
 | 
						|
	"Tea",            // 35 // SKINCOLOR_TEA
 | 
						|
	"Pistachio",      // 36 // SKINCOLOR_PISTACHIO
 | 
						|
	"Robo-Hood",      // 37 // SKINCOLOR_ROBOHOOD
 | 
						|
	"Moss",           // 38 // SKINCOLOR_MOSS
 | 
						|
	"Mint",           // 39 // SKINCOLOR_MINT
 | 
						|
	"Green",          // 40 // SKINCOLOR_GREEN
 | 
						|
	"Pinetree",       // 41 // SKINCOLOR_PINETREE
 | 
						|
	"Emerald",        // 42 // SKINCOLOR_EMERALD
 | 
						|
	"Swamp",          // 43 // SKINCOLOR_SWAMP
 | 
						|
	"Dream",          // 44 // SKINCOLOR_DREAM
 | 
						|
	"Aqua",           // 45 // SKINCOLOR_AQUA
 | 
						|
	"Teal",           // 46 // SKINCOLOR_TEAL
 | 
						|
	"Cyan",           // 47 // SKINCOLOR_CYAN
 | 
						|
	"Jawz",           // 48 // SKINCOLOR_JAWZ
 | 
						|
	"Cerulean",       // 49 // SKINCOLOR_CERULEAN
 | 
						|
	"Navy",           // 50 // SKINCOLOR_NAVY
 | 
						|
	"Slate",          // 51 // SKINCOLOR_SLATE
 | 
						|
	"Steel",          // 52 // SKINCOLOR_STEEL
 | 
						|
	"Jet",            // 53 // SKINCOLOR_JET
 | 
						|
	"Sapphire",       // 54 // SKINCOLOR_SAPPHIRE
 | 
						|
	"Periwinkle",     // 55 // SKINCOLOR_PERIWINKLE
 | 
						|
	"Blue",           // 56 // SKINCOLOR_BLUE
 | 
						|
	"Blueberry",      // 57 // SKINCOLOR_BLUEBERRY
 | 
						|
	"Dusk",           // 58 // SKINCOLOR_DUSK
 | 
						|
	"Purple",         // 59 // SKINCOLOR_PURPLE
 | 
						|
	"Lavender",       // 60 // SKINCOLOR_LAVENDER
 | 
						|
	"Byzantium",      // 61 // SKINCOLOR_BYZANTIUM
 | 
						|
	"Pomegranate",    // 62 // SKINCOLOR_POMEGRANATE
 | 
						|
	"Lilac"           // 63 // SKINCOLOR_LILAC
 | 
						|
};
 | 
						|
 | 
						|
// Color_Opposite replacement; frame setting has not been changed from 8 for most, should be done later
 | 
						|
const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] =
 | 
						|
{
 | 
						|
	SKINCOLOR_NONE,8,         // 00 // SKINCOLOR_NONE
 | 
						|
	SKINCOLOR_BLACK,8,        // 01 // SKINCOLOR_WHITE
 | 
						|
	SKINCOLOR_NICKEL,8,       // 02 // SKINCOLOR_SILVER
 | 
						|
	SKINCOLOR_GREY,8,         // 03 // SKINCOLOR_GREY
 | 
						|
	SKINCOLOR_SILVER,8,       // 04 // SKINCOLOR_NICKEL
 | 
						|
	SKINCOLOR_WHITE,8,        // 05 // SKINCOLOR_BLACK
 | 
						|
	SKINCOLOR_LEATHER,6,      // 06 // SKINCOLOR_SEPIA
 | 
						|
	SKINCOLOR_BROWN,2,        // 07 // SKINCOLOR_BEIGE
 | 
						|
	SKINCOLOR_BEIGE,8,        // 08 // SKINCOLOR_BROWN
 | 
						|
	SKINCOLOR_SEPIA,8,        // 09 // SKINCOLOR_LEATHER
 | 
						|
	SKINCOLOR_TEA,8,          // 10 // SKINCOLOR_SALMON
 | 
						|
	SKINCOLOR_PISTACHIO,8,    // 11 // SKINCOLOR_PINK
 | 
						|
	SKINCOLOR_MOSS,8,         // 12 // SKINCOLOR_ROSE
 | 
						|
	SKINCOLOR_SAPPHIRE,8,     // 13 // SKINCOLOR_RUBY
 | 
						|
	SKINCOLOR_MINT,8,         // 14 // SKINCOLOR_RASPBERRY
 | 
						|
	SKINCOLOR_GREEN,6,        // 15 // SKINCOLOR_RED
 | 
						|
	SKINCOLOR_PINETREE,6,     // 16 // SKINCOLOR_CRIMSON
 | 
						|
	SKINCOLOR_MUSTARD,10,     // 17 // SKINCOLOR_KETCHUP
 | 
						|
	SKINCOLOR_DUSK,8,         // 18 // SKINCOLOR_DAWN
 | 
						|
	SKINCOLOR_PERIWINKLE,8,   // 19 // SKINCOLOR_CREAMSICLE
 | 
						|
	SKINCOLOR_BLUE,8,         // 20 // SKINCOLOR_ORANGE
 | 
						|
	SKINCOLOR_BLUEBERRY,8,    // 21 // SKINCOLOR_PUMPKIN
 | 
						|
	SKINCOLOR_NAVY,6,         // 22 // SKINCOLOR_ROSEWOOD
 | 
						|
	SKINCOLOR_JET,8,          // 23 // SKINCOLOR_BURGUNDY
 | 
						|
	SKINCOLOR_LIME,8,         // 24 // SKINCOLOR_TANGERINE
 | 
						|
	SKINCOLOR_CYAN,8,         // 25 // SKINCOLOR_PEACH
 | 
						|
	SKINCOLOR_CERULEAN,8,     // 26 // SKINCOLOR_CARAMEL
 | 
						|
	SKINCOLOR_SLATE,8,        // 27 // SKINCOLOR_GOLD
 | 
						|
	SKINCOLOR_STEEL,8,        // 28 // SKINCOLOR_BRONZE
 | 
						|
	SKINCOLOR_AQUA,8,         // 29 // SKINCOLOR_YELLOW
 | 
						|
	SKINCOLOR_KETCHUP,8,      // 30 // SKINCOLOR_MUSTARD
 | 
						|
	SKINCOLOR_TEAL,8,         // 31 // SKINCOLOR_OLIVE
 | 
						|
	SKINCOLOR_ROBOHOOD,8,     // 32 // SKINCOLOR_VOMIT
 | 
						|
	SKINCOLOR_LAVENDER,6,     // 33 // SKINCOLOR_GARDEN
 | 
						|
	SKINCOLOR_TANGERINE,8,    // 34 // SKINCOLOR_LIME
 | 
						|
	SKINCOLOR_SALMON,8,       // 35 // SKINCOLOR_TEA
 | 
						|
	SKINCOLOR_PINK,6,         // 36 // SKINCOLOR_PISTACHIO
 | 
						|
	SKINCOLOR_VOMIT,8,        // 37 // SKINCOLOR_ROBOHOOD
 | 
						|
	SKINCOLOR_ROSE,8,         // 38 // SKINCOLOR_MOSS
 | 
						|
	SKINCOLOR_RASPBERRY,8,    // 39 // SKINCOLOR_MINT
 | 
						|
	SKINCOLOR_RED,8,          // 40 // SKINCOLOR_GREEN
 | 
						|
	SKINCOLOR_CRIMSON,8,      // 41 // SKINCOLOR_PINETREE
 | 
						|
	SKINCOLOR_PURPLE,8,       // 42 // SKINCOLOR_EMERALD
 | 
						|
	SKINCOLOR_BYZANTIUM,8,    // 43 // SKINCOLOR_SWAMP
 | 
						|
	SKINCOLOR_POMEGRANATE,8,  // 44 // SKINCOLOR_DREAM
 | 
						|
	SKINCOLOR_YELLOW,8,       // 45 // SKINCOLOR_AQUA
 | 
						|
	SKINCOLOR_OLIVE,8,        // 46 // SKINCOLOR_TEAL
 | 
						|
	SKINCOLOR_PEACH,8,        // 47 // SKINCOLOR_CYAN
 | 
						|
	SKINCOLOR_LILAC,10,       // 48 // SKINCOLOR_JAWZ
 | 
						|
	SKINCOLOR_CARAMEL,8,      // 49 // SKINCOLOR_CERULEAN
 | 
						|
	SKINCOLOR_ROSEWOOD,8,     // 50 // SKINCOLOR_NAVY
 | 
						|
	SKINCOLOR_GOLD,10,        // 51 // SKINCOLOR_SLATE
 | 
						|
	SKINCOLOR_BRONZE,10,      // 52 // SKINCOLOR_STEEL
 | 
						|
	SKINCOLOR_BURGUNDY,8,     // 53 // SKINCOLOR_JET
 | 
						|
	SKINCOLOR_RUBY,6,         // 54 // SKINCOLOR_SAPPHIRE
 | 
						|
	SKINCOLOR_CREAMSICLE,8,   // 55 // SKINCOLOR_PERIWINKLE
 | 
						|
	SKINCOLOR_ORANGE,8,       // 56 // SKINCOLOR_BLUE
 | 
						|
	SKINCOLOR_PUMPKIN,8,      // 57 // SKINCOLOR_BLUEBERRY
 | 
						|
	SKINCOLOR_DAWN,6,         // 58 // SKINCOLOR_DUSK
 | 
						|
	SKINCOLOR_EMERALD,8,      // 59 // SKINCOLOR_PURPLE
 | 
						|
	SKINCOLOR_GARDEN,6,       // 60 // SKINCOLOR_LAVENDER
 | 
						|
	SKINCOLOR_SWAMP,8,        // 61 // SKINCOLOR_BYZANTIUM
 | 
						|
	SKINCOLOR_DREAM,8,        // 62 // SKINCOLOR_POMEGRANATE
 | 
						|
	SKINCOLOR_JAWZ,6          // 63 // SKINCOLOR_LILAC
 | 
						|
};
 | 
						|
 | 
						|
UINT8 colortranslations[MAXSKINCOLORS][16] = {
 | 
						|
	{  0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0}, // SKINCOLOR_NONE
 | 
						|
	{120, 120, 120, 120,   0,   1,   3,   4,   6,   7,  10,  14,  18,  22,  25,  28}, // SKINCOLOR_WHITE
 | 
						|
	{  0,   1,   2,   4,   5,   7,   8,  10,  13,  15,  18,  20,  23,  25,  28,  30}, // SKINCOLOR_SILVER
 | 
						|
	{  1,   3,   5,   7,   9,  11,  13,  15,  17,  19,  21,  23,  25,  27,  29,  31}, // SKINCOLOR_GREY
 | 
						|
	{ 12,  14,  16,  19,  20,  21,  22,  23,  24,  25,  26,  27,  28,  29,  30,  31}, // SKINCOLOR_NICKEL
 | 
						|
	{ 16,  17,  19,  21,  22,  24,  26,  27,  27,  28,  28,  29,  29,  30,  30,  31}, // SKINCOLOR_BLACK
 | 
						|
	{  0,   1,   3,   5,   7,   9,  34,  36,  38,  40,  42,  44,  60,  61,  62,  63}, // SKINCOLOR_SEPIA
 | 
						|
	{ 32,  33,  34,  35,  36,  37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47}, // SKINCOLOR_BEIGE
 | 
						|
	{ 48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63}, // SKINCOLOR_BROWN
 | 
						|
	{ 51,  52,  53,  55,  56,  57,  58,  60,  61,  63,  28,  28,  29,  29,  30,  31}, // SKINCOLOR_LEATHER
 | 
						|
	{120, 120, 120, 121, 121, 122, 122, 123, 124, 125, 126, 128, 129, 131, 133, 135}, // SKINCOLOR_SALMON
 | 
						|
	{120, 121, 121, 122, 144, 145, 146, 147, 148, 149, 150, 151, 134, 136, 138, 140}, // SKINCOLOR_PINK
 | 
						|
	{144, 145, 146, 147, 148, 149, 150, 151, 134, 135, 136, 137, 138, 139, 140, 141}, // SKINCOLOR_ROSE
 | 
						|
	{121, 122, 145, 146, 147, 149, 131, 132, 133, 134, 135, 197, 197, 198, 199, 255}, // SKINCOLOR_RUBY
 | 
						|
	{120, 121, 122, 123, 124, 125, 126, 127, 128, 130, 131, 133, 134, 136, 137, 139}, // SKINCOLOR_RASPBERRY
 | 
						|
	{125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140}, // SKINCOLOR_RED
 | 
						|
	{130, 131, 132, 133, 134, 136, 137, 138, 139, 139, 140, 140, 141, 141, 142, 143}, // SKINCOLOR_CRIMSON
 | 
						|
	{104, 113, 113,  85,  86,  88, 128, 129, 131, 133, 134, 136, 138, 139, 141, 143}, // SKINCOLOR_KETCHUP
 | 
						|
	{120, 121, 122, 123, 124, 147, 147, 148,  90,  91,  92,  93,  94,  95, 152, 154}, // SKINCOLOR_DAWN
 | 
						|
	{120, 120,  80,  80,  81,  82,  83,  83,  84,  85,  86,  88,  89,  91,  93,  95}, // SKINCOLOR_CREAMSICLE
 | 
						|
	{ 80,  81,  82,  83,  84,  85,  86,  88,  89,  91,  94,  95, 154, 156, 158, 159}, // SKINCOLOR_ORANGE
 | 
						|
	{ 84,  85,  86,  87,  88,  90,  92,  93,  94,  95, 152, 153, 154, 156, 157, 159}, // SKINCOLOR_PUMPKIN
 | 
						|
	{ 90,  91,  92,  93,  94, 152, 153, 154, 155, 156, 157, 158, 159, 139, 141, 143}, // SKINCOLOR_ROSEWOOD
 | 
						|
	{ 94,  95, 152, 153, 154, 156, 157, 159, 141, 141, 141, 142, 142, 143, 143,  31}, // SKINCOLOR_BURGUNDY
 | 
						|
	{ 98,  98, 112, 112, 113, 113,  84,  85,  87,  89,  91,  93,  95, 153, 156, 159}, // SKINCOLOR_TANGERINE
 | 
						|
	{ 64,  65,  67,  68,  70,  71,  73,  74,  76,  77,  79,  48,  50,  53,  56,  59}, // SKINCOLOR_PEACH
 | 
						|
	{ 64,  66,  68,  70,  72,  74,  76,  78,  48,  50,  52,  54,  56,  58,  60,  62}, // SKINCOLOR_CARAMEL
 | 
						|
	{112, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119}, // SKINCOLOR_GOLD
 | 
						|
	{112, 113, 114, 115, 116, 117, 118, 119, 156, 157, 158, 159, 141, 141, 142, 143}, // SKINCOLOR_BRONZE
 | 
						|
	{ 96,  97,  98, 100, 101, 102, 104, 113, 114, 115, 116, 117, 118, 119, 156, 159}, // SKINCOLOR_YELLOW
 | 
						|
	{ 96,  98,  99, 112, 113, 114, 114, 106, 106, 107, 107, 108, 108, 109, 110, 111}, // SKINCOLOR_MUSTARD
 | 
						|
	{105, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111,  31}, // SKINCOLOR_OLIVE
 | 
						|
	{121, 144, 145,  72,  73,  84, 114, 115, 107, 108, 109, 183, 223, 207,  30, 246}, // SKINCOLOR_VOMIT
 | 
						|
	{ 98,  99, 112, 101, 113, 114, 106, 179, 180, 180, 181, 182, 183, 173, 174, 175}, // SKINCOLOR_GARDEN
 | 
						|
	{ 96,  97,  99, 100, 102, 104, 160, 162, 164, 166, 168, 171, 223, 223, 207,  31}, // SKINCOLOR_LIME
 | 
						|
	{120, 120, 176, 176, 176, 177, 177, 178, 178, 179, 179, 180, 180, 181, 182, 183}, // SKINCOLOR_TEA
 | 
						|
	{120, 120, 176, 176, 177, 177, 178, 179, 165, 166, 167, 168, 169, 170, 171, 172}, // SKINCOLOR_PISTACHIO
 | 
						|
	{176, 176, 177, 178, 165, 166, 167, 167, 168, 169, 182, 182, 182, 183, 183, 183}, // SKINCOLOR_ROBOHOOD
 | 
						|
	{178, 178, 178, 179, 179, 180, 181, 182, 183, 172, 172, 173, 173, 174, 174, 175}, // SKINCOLOR_MOSS
 | 
						|
	{120, 176, 176, 176, 177, 163, 164, 165, 167, 221, 221, 222, 223, 207, 207,  31}, // SKINCOLOR_MINT
 | 
						|
	{160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175}, // SKINCOLOR_GREEN
 | 
						|
	{160, 161, 162, 164, 165, 167, 169, 170, 171, 171, 172, 173, 174, 175,  30,  31}, // SKINCOLOR_PINETREE
 | 
						|
	{160, 184, 184, 185, 185, 186, 186, 187, 187, 188, 188, 189, 189, 190, 191, 175}, // SKINCOLOR_EMERALD
 | 
						|
	{186, 187, 188, 188, 188, 189, 189, 190, 190, 191, 175, 175,  30,  30,  31,  31}, // SKINCOLOR_SWAMP
 | 
						|
	{120, 120,  80,  80,  81, 177, 162, 164, 228, 228, 204, 204, 205, 205, 206, 207}, // SKINCOLOR_DREAM
 | 
						|
	{120, 208, 208, 210, 212, 214, 220, 220, 220, 221, 221, 222, 222, 223, 223, 191}, // SKINCOLOR_AQUA
 | 
						|
	{210, 213, 220, 220, 220, 216, 216, 221, 221, 221, 222, 222, 223, 223, 191,  31}, // SKINCOLOR_TEAL
 | 
						|
	{120, 120, 208, 208, 209, 210, 211, 212, 213, 215, 216, 217, 218, 219, 222, 223}, // SKINCOLOR_CYAN
 | 
						|
	{120, 120, 208, 209, 210, 226, 215, 216, 217, 229, 229, 205, 205, 206, 207,  31}, // SKINCOLOR_JAWZ
 | 
						|
	{208, 209, 211, 213, 215, 216, 216, 217, 217, 218, 218, 219, 205, 206, 207, 207}, // SKINCOLOR_CERULEAN
 | 
						|
	{211, 212, 213, 215, 216, 218, 219, 205, 206, 206, 207, 207,  28,  29,  30,  31}, // SKINCOLOR_NAVY
 | 
						|
	{120, 120, 200, 200, 200, 201, 201, 201, 202, 202, 202, 203, 204, 205, 206, 207}, // SKINCOLOR_SLATE
 | 
						|
	{120, 200, 200, 201, 201, 202, 202, 203, 203, 204, 204, 205, 205, 206, 207,  31}, // SKINCOLOR_STEEL
 | 
						|
	{225, 226, 227, 228, 229, 205, 205, 206, 207, 207,  28,  28,  29,  29,  30,  31}, // SKINCOLOR_JET
 | 
						|
	{208, 209, 211, 213, 215, 217, 229, 230, 232, 234, 236, 238, 240, 242, 244, 246}, // SKINCOLOR_SAPPHIRE
 | 
						|
	{120, 224, 225, 226, 226, 227, 228, 228, 229, 230, 231, 234, 235, 237, 239, 241}, // SKINCOLOR_PERIWINKLE
 | 
						|
	{224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239}, // SKINCOLOR_BLUE
 | 
						|
	{228, 229, 230, 231, 232, 233, 234, 235, 237, 238, 239, 240, 242, 243, 244, 245}, // SKINCOLOR_BLUEBERRY
 | 
						|
	{192, 192, 248, 249, 250, 251, 204, 204, 205, 205, 206, 206, 207,  29,  30,  31}, // SKINCOLOR_DUSK
 | 
						|
	{192, 192, 192, 193, 193, 194, 194, 195, 195, 196, 196, 197, 197, 198, 198, 199}, // SKINCOLOR_PURPLE
 | 
						|
	{248, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255}, // SKINCOLOR_LAVENDER
 | 
						|
	{192, 248, 249, 250, 251, 252, 253, 254, 255, 255,  29,  29,  30,  30,  31,  31}, // SKINCOLOR_BYZANTIUM
 | 
						|
	{144, 145, 146, 147, 148, 149, 150, 251, 251, 252, 252, 253, 254, 255,  29,  30}, // SKINCOLOR_POMEGRANATE
 | 
						|
	{120, 120, 120, 121, 121, 122, 122, 123, 192, 248, 249, 250, 251, 252, 253, 254}, // SKINCOLOR_LILAC
 | 
						|
	/* Removed Colours
 | 
						|
		{120, 121, 123, 124, 126, 127, 129, 130, 132, 133, 135, 136, 138, 139, 141, 143}, // old SKINCOLOR_RUBY, removed for other colors
 | 
						|
		{224, 225, 226, 228, 229, 231, 232, 234, 235, 237, 238, 240, 241, 243, 244, 246}, // old SKINCOLOR_SAPPHIRE, removed for other colors
 | 
						|
		{ 72,  73,  74,  75,  76,  77,  78,  79,  48,  49,  50,  51,  52,  53,  54,  55}, // old SKINCOLOR_CARAMEL, new Caramel was previously Shiny Caramel
 | 
						|
		{215, 216, 217, 218, 204, 205, 206, 237, 238, 239, 240, 241, 242, 243, 244, 245}, // old SKINCOLOR_NAVY, too similar to Jet
 | 
						|
		{ 80,  81,  83,  85,  86,  88,  90,  91,  93,  95, 152, 153, 154, 156, 157, 159}, // SKINCOLOR_AMBER, removed for other colors
 | 
						|
		{160, 160, 160, 184, 184, 184, 185, 185, 185, 186, 187, 187, 188, 188, 189, 190}, // SKINCOLOR_JADE, removed for other colors
 | 
						|
		{224, 225, 226, 212, 213, 213, 214, 215, 220, 221, 172, 222, 173, 223, 174, 175}, // SKINCOLOR_FROST, merged into Aqua
 | 
						|
		{ 96,  97,  99, 100, 102, 104, 105, 105, 106, 107, 107, 108, 109, 109, 110, 111}, // SKINCOLOR_CANARY, replaced with Mustard
 | 
						|
		{192, 193, 194, 195, 196, 197, 198, 199, 255, 255,  29,  29,  30,  30,  31,  31}, // SKINCOLOR_INDIGO, too similar to Byzantium
 | 
						|
		{  1, 145, 125,  73,  83, 114, 106, 180, 187, 168, 219, 205, 236, 206, 199, 255}, // SKINCOLOR_RAINBOW, is Vomit 2.0
 | 
						|
	*/
 | 
						|
};
 | 
						|
 | 
						|
// Define for getting accurate color brightness readings according to how the human eye sees them.
 | 
						|
// https://en.wikipedia.org/wiki/Relative_luminance
 | 
						|
// 0.2126 to red
 | 
						|
// 0.7152 to green
 | 
						|
// 0.0722 to blue
 | 
						|
// (See this same define in hw_md2.c!)
 | 
						|
#define SETBRIGHTNESS(brightness,r,g,b) \
 | 
						|
	brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
 | 
						|
 | 
						|
/** \brief	Generates the rainbow colourmaps that are used when a player has the invincibility power
 | 
						|
 | 
						|
	\param	dest_colormap	colormap to populate
 | 
						|
	\param	skincolor		translation color
 | 
						|
*/
 | 
						|
void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor)
 | 
						|
{
 | 
						|
	INT32 i;
 | 
						|
	RGBA_t color;
 | 
						|
	UINT8 brightness;
 | 
						|
	INT32 j;
 | 
						|
	UINT8 colorbrightnesses[16];
 | 
						|
	UINT16 brightdif;
 | 
						|
	INT32 temp;
 | 
						|
 | 
						|
	// first generate the brightness of all the colours of that skincolour
 | 
						|
	for (i = 0; i < 16; i++)
 | 
						|
	{
 | 
						|
		color = V_GetColor(colortranslations[skincolor][i]);
 | 
						|
		SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue);
 | 
						|
	}
 | 
						|
 | 
						|
	// next, for every colour in the palette, choose the transcolor that has the closest brightness
 | 
						|
	for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
 | 
						|
	{
 | 
						|
		if (i == 0 || i == 31 || i == 120) // pure black and pure white don't change
 | 
						|
		{
 | 
						|
			dest_colormap[i] = (UINT8)i;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		color = V_GetColor(i);
 | 
						|
		SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue);
 | 
						|
		brightdif = 256;
 | 
						|
		for (j = 0; j < 16; j++)
 | 
						|
		{
 | 
						|
			temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]);
 | 
						|
			if (temp < brightdif)
 | 
						|
			{
 | 
						|
				brightdif = (UINT16)temp;
 | 
						|
				dest_colormap[i] = colortranslations[skincolor][j];
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#undef SETBRIGHTNESS
 | 
						|
 | 
						|
/**	\brief	Generates a translation colormap for Kart, to replace R_GenerateTranslationColormap in r_draw.c
 | 
						|
 | 
						|
	\param	dest_colormap	colormap to populate
 | 
						|
	\param	skinnum			number of skin, TC_DEFAULT or TC_BOSS
 | 
						|
	\param	color			translation color
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color)
 | 
						|
{
 | 
						|
	INT32 i;
 | 
						|
	INT32 starttranscolor;
 | 
						|
 | 
						|
	// Handle a couple of simple special cases
 | 
						|
	if (skinnum == TC_BOSS
 | 
						|
		|| skinnum == TC_ALLWHITE
 | 
						|
		|| skinnum == TC_METALSONIC
 | 
						|
		|| skinnum == TC_BLINK
 | 
						|
		|| color == SKINCOLOR_NONE)
 | 
						|
	{
 | 
						|
		for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
 | 
						|
		{
 | 
						|
			if (skinnum == TC_ALLWHITE)
 | 
						|
				dest_colormap[i] = 0;
 | 
						|
			else if (skinnum == TC_BLINK)
 | 
						|
				dest_colormap[i] = colortranslations[color][3];
 | 
						|
			else
 | 
						|
				dest_colormap[i] = (UINT8)i;
 | 
						|
		}
 | 
						|
 | 
						|
		// White!
 | 
						|
		if (skinnum == TC_BOSS)
 | 
						|
			dest_colormap[31] = 0;
 | 
						|
		else if (skinnum == TC_METALSONIC)
 | 
						|
			dest_colormap[239] = 0;
 | 
						|
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else if (skinnum == TC_RAINBOW)
 | 
						|
	{
 | 
						|
		K_RainbowColormap(dest_colormap, color);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR;
 | 
						|
 | 
						|
	// Fill in the entries of the palette that are fixed
 | 
						|
	for (i = 0; i < starttranscolor; i++)
 | 
						|
		dest_colormap[i] = (UINT8)i;
 | 
						|
 | 
						|
	for (i = (UINT8)(starttranscolor + 16); i < NUM_PALETTE_ENTRIES; i++)
 | 
						|
		dest_colormap[i] = (UINT8)i;
 | 
						|
 | 
						|
	// Build the translated ramp
 | 
						|
	for (i = 0; i < SKIN_RAMP_LENGTH; i++)
 | 
						|
	{
 | 
						|
		// Sryder 2017-10-26: What was here before was most definitely not particularly readable, check above for new color translation table
 | 
						|
		dest_colormap[starttranscolor + i] = colortranslations[color][i];
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief	Pulls kart color by name, to replace R_GetColorByName in r_draw.c
 | 
						|
 | 
						|
	\param	name	color name
 | 
						|
 | 
						|
	\return	0
 | 
						|
*/
 | 
						|
UINT8 K_GetKartColorByName(const char *name)
 | 
						|
{
 | 
						|
	UINT8 color = (UINT8)atoi(name);
 | 
						|
	if (color > 0 && color < MAXSKINCOLORS)
 | 
						|
		return color;
 | 
						|
	for (color = 1; color < MAXSKINCOLORS; color++)
 | 
						|
		if (!stricmp(KartColor_Names[color], name))
 | 
						|
			return color;
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
//}
 | 
						|
 | 
						|
//{ SRB2kart Net Variables
 | 
						|
 | 
						|
void K_RegisterKartStuff(void)
 | 
						|
{
 | 
						|
	CV_RegisterVar(&cv_sneaker);
 | 
						|
	CV_RegisterVar(&cv_rocketsneaker);
 | 
						|
	CV_RegisterVar(&cv_invincibility);
 | 
						|
	CV_RegisterVar(&cv_banana);
 | 
						|
	CV_RegisterVar(&cv_eggmanmonitor);
 | 
						|
	CV_RegisterVar(&cv_orbinaut);
 | 
						|
	CV_RegisterVar(&cv_jawz);
 | 
						|
	CV_RegisterVar(&cv_mine);
 | 
						|
	CV_RegisterVar(&cv_ballhog);
 | 
						|
	CV_RegisterVar(&cv_selfpropelledbomb);
 | 
						|
	CV_RegisterVar(&cv_grow);
 | 
						|
	CV_RegisterVar(&cv_shrink);
 | 
						|
	CV_RegisterVar(&cv_thundershield);
 | 
						|
	CV_RegisterVar(&cv_hyudoro);
 | 
						|
	CV_RegisterVar(&cv_pogospring);
 | 
						|
	CV_RegisterVar(&cv_kitchensink);
 | 
						|
 | 
						|
	CV_RegisterVar(&cv_triplesneaker);
 | 
						|
	CV_RegisterVar(&cv_triplebanana);
 | 
						|
	CV_RegisterVar(&cv_decabanana);
 | 
						|
	CV_RegisterVar(&cv_tripleorbinaut);
 | 
						|
	CV_RegisterVar(&cv_quadorbinaut);
 | 
						|
	CV_RegisterVar(&cv_dualjawz);
 | 
						|
 | 
						|
	CV_RegisterVar(&cv_kartminimap);
 | 
						|
	CV_RegisterVar(&cv_kartcheck);
 | 
						|
	CV_RegisterVar(&cv_kartinvinsfx);
 | 
						|
	CV_RegisterVar(&cv_kartspeed);
 | 
						|
	CV_RegisterVar(&cv_kartbumpers);
 | 
						|
	CV_RegisterVar(&cv_kartfrantic);
 | 
						|
	CV_RegisterVar(&cv_kartcomeback);
 | 
						|
	CV_RegisterVar(&cv_kartencore);
 | 
						|
	CV_RegisterVar(&cv_kartvoterulechanges);
 | 
						|
	CV_RegisterVar(&cv_kartspeedometer);
 | 
						|
	CV_RegisterVar(&cv_kartvoices);
 | 
						|
	CV_RegisterVar(&cv_karteliminatelast);
 | 
						|
	CV_RegisterVar(&cv_votetime);
 | 
						|
 | 
						|
	CV_RegisterVar(&cv_kartdebugitem);
 | 
						|
	CV_RegisterVar(&cv_kartdebugamount);
 | 
						|
	CV_RegisterVar(&cv_kartdebugshrink);
 | 
						|
	CV_RegisterVar(&cv_kartdebugdistribution);
 | 
						|
	CV_RegisterVar(&cv_kartdebughuddrop);
 | 
						|
 | 
						|
	CV_RegisterVar(&cv_kartdebugcheckpoint);
 | 
						|
	CV_RegisterVar(&cv_kartdebugnodes);
 | 
						|
}
 | 
						|
 | 
						|
//}
 | 
						|
 | 
						|
boolean K_IsPlayerLosing(player_t *player)
 | 
						|
{
 | 
						|
	INT32 winningpos = 1;
 | 
						|
	UINT8 i, pcount = 0;
 | 
						|
 | 
						|
	if (player->kartstuff[k_position] == 1)
 | 
						|
		return false;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator)
 | 
						|
			continue;
 | 
						|
		if (players[i].kartstuff[k_position] > pcount)
 | 
						|
			pcount = players[i].kartstuff[k_position];
 | 
						|
	}
 | 
						|
 | 
						|
	if (pcount <= 1)
 | 
						|
		return false;
 | 
						|
 | 
						|
	winningpos = pcount/2;
 | 
						|
	if (pcount % 2) // any remainder?
 | 
						|
		winningpos++;
 | 
						|
 | 
						|
	return (player->kartstuff[k_position] > winningpos);
 | 
						|
}
 | 
						|
 | 
						|
boolean K_IsPlayerWanted(player_t *player)
 | 
						|
{
 | 
						|
	UINT8 i;
 | 
						|
	if (!(G_BattleGametype()))
 | 
						|
		return false;
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		if (battlewanted[i] == -1)
 | 
						|
			break;
 | 
						|
		if (player == &players[battlewanted[i]])
 | 
						|
			return true;
 | 
						|
	}
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
//{ SRB2kart Roulette Code - Position Based
 | 
						|
 | 
						|
#define NUMKARTODDS 	80
 | 
						|
 | 
						|
// Less ugly 2D arrays
 | 
						|
static INT32 K_KartItemOddsRace[NUMKARTRESULTS][10] =
 | 
						|
{
 | 
						|
				//P-Odds	 0  1  2  3  4  5  6  7  8  9
 | 
						|
			   /*Sneaker*/ {20, 0, 0, 4, 6, 6, 0, 0, 0, 0 }, // Sneaker
 | 
						|
		/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 1, 3, 5, 3, 0 }, // Rocket Sneaker
 | 
						|
		 /*Invincibility*/ { 0, 0, 0, 0, 0, 1, 4, 6,14, 0 }, // Invincibility
 | 
						|
				/*Banana*/ { 0, 9, 4, 2, 1, 0, 0, 0, 0, 0 }, // Banana
 | 
						|
		/*Eggman Monitor*/ { 0, 4, 3, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
 | 
						|
			  /*Orbinaut*/ { 0, 6, 5, 3, 2, 0, 0, 0, 0, 0 }, // Orbinaut
 | 
						|
				  /*Jawz*/ { 0, 0, 3, 2, 1, 1, 0, 0, 0, 0 }, // Jawz
 | 
						|
				  /*Mine*/ { 0, 0, 2, 2, 1, 0, 0, 0, 0, 0 }, // Mine
 | 
						|
			   /*Ballhog*/ { 0, 0, 0, 2, 1, 0, 0, 0, 0, 0 }, // Ballhog
 | 
						|
   /*Self-Propelled Bomb*/ { 0, 0, 1, 2, 3, 4, 2, 2, 0,20 }, // Self-Propelled Bomb
 | 
						|
				  /*Grow*/ { 0, 0, 0, 0, 0, 1, 3, 5, 3, 0 }, // Grow
 | 
						|
				/*Shrink*/ { 0, 0, 0, 0, 0, 0, 0, 2, 0, 0 }, // Shrink
 | 
						|
		/*Thunder Shield*/ { 0, 1, 2, 0, 0, 0, 0, 0, 0, 0 }, // Thunder Shield
 | 
						|
			   /*Hyudoro*/ { 0, 0, 0, 0, 1, 2, 1, 0, 0, 0 }, // Hyudoro
 | 
						|
		   /*Pogo Spring*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring
 | 
						|
		  /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
 | 
						|
			/*Sneaker x3*/ { 0, 0, 0, 0, 3, 7, 9, 2, 0, 0 }, // Sneaker x3
 | 
						|
			 /*Banana x3*/ { 0, 0, 1, 1, 0, 0, 0, 0, 0, 0 }, // Banana x3
 | 
						|
			/*Banana x10*/ { 0, 0, 0, 0, 1, 0, 0, 0, 0, 0 }, // Banana x10
 | 
						|
		   /*Orbinaut x3*/ { 0, 0, 0, 1, 0, 0, 0, 0, 0, 0 }, // Orbinaut x3
 | 
						|
		   /*Orbinaut x4*/ { 0, 0, 0, 0, 1, 1, 0, 0, 0, 0 }, // Orbinaut x4
 | 
						|
			   /*Jawz x2*/ { 0, 0, 0, 1, 2, 0, 0, 0, 0, 0 }  // Jawz x2
 | 
						|
};
 | 
						|
 | 
						|
static INT32 K_KartItemOddsBattle[NUMKARTRESULTS][6] =
 | 
						|
{
 | 
						|
				//P-Odds	 0  1  2  3  4  5
 | 
						|
			   /*Sneaker*/ { 3, 2, 2, 2, 0, 2 }, // Sneaker
 | 
						|
		/*Rocket Sneaker*/ { 0, 0, 0, 0, 0, 0 }, // Rocket Sneaker
 | 
						|
		 /*Invincibility*/ { 0, 1, 2, 3, 4, 2 }, // Invincibility
 | 
						|
				/*Banana*/ { 2, 1, 0, 0, 0, 0 }, // Banana
 | 
						|
		/*Eggman Monitor*/ { 1, 1, 0, 0, 0, 0 }, // Eggman Monitor
 | 
						|
			  /*Orbinaut*/ { 6, 2, 1, 0, 0, 0 }, // Orbinaut
 | 
						|
				  /*Jawz*/ { 3, 3, 3, 2, 0, 2 }, // Jawz
 | 
						|
				  /*Mine*/ { 2, 3, 3, 1, 0, 2 }, // Mine
 | 
						|
			   /*Ballhog*/ { 0, 1, 2, 1, 0, 2 }, // Ballhog
 | 
						|
   /*Self-Propelled Bomb*/ { 0, 0, 0, 0, 0, 0 }, // Self-Propelled Bomb
 | 
						|
				  /*Grow*/ { 0, 0, 1, 2, 4, 2 }, // Grow
 | 
						|
				/*Shrink*/ { 0, 0, 0, 0, 0, 0 }, // Shrink
 | 
						|
		/*Thunder Shield*/ { 0, 0, 0, 0, 0, 0 }, // Thunder Shield
 | 
						|
			   /*Hyudoro*/ { 1, 1, 0, 0, 0, 0 }, // Hyudoro
 | 
						|
		   /*Pogo Spring*/ { 1, 1, 0, 0, 0, 0 }, // Pogo Spring
 | 
						|
		  /*Kitchen Sink*/ { 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
 | 
						|
			/*Sneaker x3*/ { 0, 0, 0, 2, 4, 2 }, // Sneaker x3
 | 
						|
			 /*Banana x3*/ { 1, 2, 1, 0, 0, 0 }, // Banana x3
 | 
						|
			/*Banana x10*/ { 0, 0, 1, 1, 0, 2 }, // Banana x10
 | 
						|
		   /*Orbinaut x3*/ { 0, 1, 2, 1, 0, 0 }, // Orbinaut x3
 | 
						|
		   /*Orbinaut x4*/ { 0, 0, 1, 3, 4, 2 }, // Orbinaut x4
 | 
						|
			   /*Jawz x2*/ { 0, 0, 1, 2, 4, 2 }  // Jawz x2
 | 
						|
};
 | 
						|
 | 
						|
/**	\brief	Item Roulette for Kart
 | 
						|
 | 
						|
	\param	player		player
 | 
						|
	\param	getitem		what item we're looking for
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
static void K_KartGetItemResult(player_t *player, SINT8 getitem)
 | 
						|
{
 | 
						|
	switch (getitem)
 | 
						|
	{
 | 
						|
		// Special roulettes first, then the generic ones are handled by default
 | 
						|
		case KRITEM_TRIPLESNEAKER: // Sneaker x3
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_SNEAKER;
 | 
						|
			player->kartstuff[k_itemamount] = 3;
 | 
						|
			break;
 | 
						|
		case KRITEM_TRIPLEBANANA: // Banana x3
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_BANANA;
 | 
						|
			player->kartstuff[k_itemamount] = 3;
 | 
						|
			break;
 | 
						|
		case KRITEM_TENFOLDBANANA: // Banana x10
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_BANANA;
 | 
						|
			player->kartstuff[k_itemamount] = 10;
 | 
						|
			break;
 | 
						|
		case KRITEM_TRIPLEORBINAUT: // Orbinaut x3
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_ORBINAUT;
 | 
						|
			player->kartstuff[k_itemamount] = 3;
 | 
						|
			break;
 | 
						|
		case KRITEM_QUADORBINAUT: // Orbinaut x4
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_ORBINAUT;
 | 
						|
			player->kartstuff[k_itemamount] = 4;
 | 
						|
			break;
 | 
						|
		case KRITEM_DUALJAWZ: // Jawz x2
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_JAWZ;
 | 
						|
			player->kartstuff[k_itemamount] = 2;
 | 
						|
			break;
 | 
						|
		case KITEM_SPB:
 | 
						|
		case KITEM_SHRINK: // Indirect items
 | 
						|
			indirectitemcooldown = 20*TICRATE;
 | 
						|
			/* FALLTHRU */
 | 
						|
		default:
 | 
						|
			if (getitem <= 0 || getitem >= NUMKARTRESULTS) // Sad (Fallback)
 | 
						|
			{
 | 
						|
				if (getitem != 0)
 | 
						|
					CONS_Printf("ERROR: P_KartGetItemResult - Item roulette gave bad item (%d) :(\n", getitem);
 | 
						|
				player->kartstuff[k_itemtype] = KITEM_SAD;
 | 
						|
			}
 | 
						|
			else
 | 
						|
				player->kartstuff[k_itemtype] = getitem;
 | 
						|
			player->kartstuff[k_itemamount] = 1;
 | 
						|
			break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief	Item Roulette for Kart
 | 
						|
 | 
						|
	\param	player	player object passed from P_KartPlayerThink
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
 | 
						|
static INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, fixed_t mashed)
 | 
						|
{
 | 
						|
	const INT32 distvar = (64*14);
 | 
						|
	INT32 newodds;
 | 
						|
	INT32 i;
 | 
						|
	UINT8 pingame = 0, pexiting = 0, pinvin = 0;
 | 
						|
	SINT8 first = -1, second = -1;
 | 
						|
	INT32 secondist = 0;
 | 
						|
 | 
						|
	if (G_BattleGametype())
 | 
						|
		newodds = K_KartItemOddsBattle[item-1][pos];
 | 
						|
	else
 | 
						|
		newodds = K_KartItemOddsRace[item-1][pos];
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator)
 | 
						|
			continue;
 | 
						|
 | 
						|
		pingame++;
 | 
						|
		if (players[i].exiting)
 | 
						|
			pexiting++;
 | 
						|
		if (players[i].mo)
 | 
						|
		{
 | 
						|
			if (players[i].kartstuff[k_position] == 1 && first == -1)
 | 
						|
				first = i;
 | 
						|
			if (players[i].kartstuff[k_position] == 2 && second == -1)
 | 
						|
				second = i;
 | 
						|
			if (players[i].kartstuff[k_itemtype] == KITEM_INVINCIBILITY
 | 
						|
				|| players[i].kartstuff[k_itemtype] == KITEM_GROW
 | 
						|
				|| players[i].kartstuff[k_invincibilitytimer]
 | 
						|
				|| players[i].kartstuff[k_growshrinktimer] > 0)
 | 
						|
				pinvin++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (first != -1 && second != -1) // calculate 2nd's distance from 1st, for SPB
 | 
						|
	{
 | 
						|
		secondist = P_AproxDistance(P_AproxDistance(players[first].mo->x - players[second].mo->x,
 | 
						|
													players[first].mo->y - players[second].mo->y),
 | 
						|
													players[first].mo->z - players[second].mo->z) / mapobjectscale;
 | 
						|
		if (franticitems)
 | 
						|
			secondist = (15*secondist/14);
 | 
						|
		if (pingame < 8 && !G_BattleGametype())
 | 
						|
			secondist = ((28+(8-pingame))*secondist/28);
 | 
						|
	}
 | 
						|
 | 
						|
	// POWERITEMODDS handles all of the "frantic item" related functionality, for all of our powerful items.
 | 
						|
	// First, it multiplies it by 2 if franticitems is true; easy-peasy.
 | 
						|
	// Next, it multiplies it again if it's in SPB mode and 2nd needs to apply pressure to 1st.
 | 
						|
	// Then, it multiplies it further if there's less than 8 players in game.
 | 
						|
	// This is done to make low player count races more fair & interesting. (1v1s are basically the same as franticitems false in a normal race)
 | 
						|
	// Lastly, it *divides* it by your mashed value, which was determined in K_KartItemRoulette, to punish those who are impatient.
 | 
						|
	// The last two are very fractional and complicated, very sorry!
 | 
						|
#define POWERITEMODDS(odds) \
 | 
						|
	if (franticitems) \
 | 
						|
		odds *= 2; \
 | 
						|
	if (pingame < 8 && !G_BattleGametype()) \
 | 
						|
		odds = FixedMul(odds*FRACUNIT, FRACUNIT+min((8-pingame)*(FRACUNIT/25), FRACUNIT))/FRACUNIT; \
 | 
						|
	if (mashed > 0) \
 | 
						|
		odds = FixedDiv(odds*FRACUNIT, mashed+FRACUNIT)/FRACUNIT \
 | 
						|
 | 
						|
	switch (item)
 | 
						|
	{
 | 
						|
		case KITEM_SNEAKER:
 | 
						|
			if ((!cv_sneaker.value) && (!modeattacking)) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_ROCKETSNEAKER:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_rocketsneaker.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_INVINCIBILITY:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if ((!cv_invincibility.value) || (pinvin >= 2)) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_BANANA:
 | 
						|
			if (!cv_banana.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_EGGMAN:
 | 
						|
			if (!cv_eggmanmonitor.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_ORBINAUT:
 | 
						|
			if (!cv_orbinaut.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_JAWZ:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_jawz.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_MINE:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_mine.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_BALLHOG:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_ballhog.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_SPB:
 | 
						|
			//POWERITEMODDS(newodds);
 | 
						|
			if (((!cv_selfpropelledbomb.value)
 | 
						|
				|| (indirectitemcooldown > 0)
 | 
						|
				|| (pexiting > 0)
 | 
						|
				|| (secondist/distvar < 3))
 | 
						|
				&& (pos != 9)) // Force SPB
 | 
						|
				newodds = 0;
 | 
						|
			newodds *= min((secondist/distvar)-4, 3);
 | 
						|
			break;
 | 
						|
		case KITEM_GROW:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if ((!cv_grow.value) || (pinvin >= 2)) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_SHRINK:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if ((!cv_shrink.value)
 | 
						|
				|| (indirectitemcooldown > 0)
 | 
						|
				|| (pingame-1 <= pexiting)) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_THUNDERSHIELD:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_thundershield.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_HYUDORO:
 | 
						|
			if (!cv_hyudoro.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_POGOSPRING:
 | 
						|
			if (!cv_pogospring.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KITEM_KITCHENSINK:
 | 
						|
			newodds = 0; // Not obtained via normal means.
 | 
						|
			break;
 | 
						|
		case KRITEM_TRIPLESNEAKER:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_triplesneaker.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KRITEM_TRIPLEBANANA:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_triplebanana.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KRITEM_TENFOLDBANANA:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_decabanana.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KRITEM_TRIPLEORBINAUT:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_tripleorbinaut.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KRITEM_QUADORBINAUT:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_quadorbinaut.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		case KRITEM_DUALJAWZ:
 | 
						|
			POWERITEMODDS(newodds);
 | 
						|
			if (!cv_dualjawz.value) newodds = 0;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
#undef POWERITEMODDS
 | 
						|
 | 
						|
	return newodds;
 | 
						|
}
 | 
						|
 | 
						|
//{ SRB2kart Roulette Code - Distance Based, no waypoints
 | 
						|
 | 
						|
static INT32 K_FindUseodds(player_t *player, fixed_t mashed, INT32 pingame, INT32 bestbumper, boolean spbrush, boolean dontforcespb)
 | 
						|
{
 | 
						|
	const INT32 distvar = (64*14);
 | 
						|
	INT32 i;
 | 
						|
	INT32 pdis = 0, useodds = 0;
 | 
						|
	UINT8 disttable[14];
 | 
						|
	UINT8 distlen = 0;
 | 
						|
	boolean oddsvalid[10];
 | 
						|
 | 
						|
	for (i = 0; i < 10; i++)
 | 
						|
	{
 | 
						|
		INT32 j;
 | 
						|
		boolean available = false;
 | 
						|
 | 
						|
		if (G_BattleGametype() && i > 5)
 | 
						|
		{
 | 
						|
			oddsvalid[i] = false;
 | 
						|
			break;
 | 
						|
		}
 | 
						|
 | 
						|
		for (j = 0; j < NUMKARTRESULTS; j++)
 | 
						|
		{
 | 
						|
			if (K_KartGetItemOdds(i, j, mashed) > 0)
 | 
						|
			{
 | 
						|
				available = true;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		oddsvalid[i] = available;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (playeringame[i] && !players[i].spectator && players[i].mo
 | 
						|
			&& players[i].kartstuff[k_position] < player->kartstuff[k_position])
 | 
						|
			pdis += P_AproxDistance(P_AproxDistance(players[i].mo->x - player->mo->x,
 | 
						|
													players[i].mo->y - player->mo->y),
 | 
						|
													players[i].mo->z - player->mo->z) / mapobjectscale
 | 
						|
													* (pingame - players[i].kartstuff[k_position])
 | 
						|
													/ max(1, ((pingame - 1) * (pingame + 1) / 3));
 | 
						|
	}
 | 
						|
 | 
						|
#define SETUPDISTTABLE(odds, num) \
 | 
						|
	for (i = num; i; --i) disttable[distlen++] = odds
 | 
						|
 | 
						|
	if (G_BattleGametype()) // Battle Mode
 | 
						|
	{
 | 
						|
		if (oddsvalid[0]) SETUPDISTTABLE(0,1);
 | 
						|
		if (oddsvalid[1]) SETUPDISTTABLE(1,1);
 | 
						|
		if (oddsvalid[2]) SETUPDISTTABLE(2,1);
 | 
						|
		if (oddsvalid[3]) SETUPDISTTABLE(3,1);
 | 
						|
		if (oddsvalid[4]) SETUPDISTTABLE(4,1);
 | 
						|
 | 
						|
		if (player->kartstuff[k_roulettetype] == 1 && oddsvalid[5]) // 5 is the extreme odds of player-controlled "Karma" items
 | 
						|
			useodds = 5;
 | 
						|
		else
 | 
						|
		{
 | 
						|
			SINT8 wantedpos = (bestbumper-player->kartstuff[k_bumper]); // 0 is the best player's bumper count, 1 is a bumper below best, 2 is two bumpers below, etc
 | 
						|
			if (K_IsPlayerWanted(player))
 | 
						|
				wantedpos++;
 | 
						|
			if (wantedpos > 4) // Don't run off into karma items
 | 
						|
				wantedpos = 4;
 | 
						|
			if (wantedpos < 0) // Don't go below somehow
 | 
						|
				wantedpos = 0;
 | 
						|
			useodds = disttable[(wantedpos * distlen) / 5];
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (oddsvalid[1]) SETUPDISTTABLE(1,1);
 | 
						|
		if (oddsvalid[2]) SETUPDISTTABLE(2,1);
 | 
						|
		if (oddsvalid[3]) SETUPDISTTABLE(3,1);
 | 
						|
		if (oddsvalid[4]) SETUPDISTTABLE(4,2);
 | 
						|
		if (oddsvalid[5]) SETUPDISTTABLE(5,2);
 | 
						|
		if (oddsvalid[6]) SETUPDISTTABLE(6,3);
 | 
						|
		if (oddsvalid[7]) SETUPDISTTABLE(7,3);
 | 
						|
		if (oddsvalid[8]) SETUPDISTTABLE(8,1);
 | 
						|
 | 
						|
		if (franticitems) // Frantic items make the distances between everyone artifically higher, for crazier items
 | 
						|
			pdis = (15*pdis)/14;
 | 
						|
		if (spbrush) // SPB Rush Mode: It's 2nd place's job to catch-up items and make 1st place's job hell
 | 
						|
			pdis = (3*pdis)/2;
 | 
						|
		if (pingame < 8)
 | 
						|
			pdis = ((28+(8-pingame))*pdis)/28;
 | 
						|
 | 
						|
		if (pingame == 1 && oddsvalid[0])					// Record Attack, or just alone
 | 
						|
			useodds = 0;
 | 
						|
		else if (pdis <= 0)									// (64*14) *  0 =     0
 | 
						|
			useodds = disttable[0];
 | 
						|
		else if (player->kartstuff[k_position] == 2 && pdis > (distvar*6)
 | 
						|
			&& spbplace == -1 && !indirectitemcooldown && !dontforcespb
 | 
						|
			&& oddsvalid[9])								// Force SPB in 2nd
 | 
						|
			useodds = 9;
 | 
						|
		else if (pdis > distvar * ((12 * distlen) / 14))	// (64*14) * 12 = 10752
 | 
						|
			useodds = disttable[distlen-1];
 | 
						|
		else
 | 
						|
		{
 | 
						|
			for (i = 1; i < 13; i++)
 | 
						|
			{
 | 
						|
				if (pdis <= distvar * ((i * distlen) / 14))
 | 
						|
				{
 | 
						|
					useodds = disttable[((i * distlen) / 14)];
 | 
						|
					break;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
#undef SETUPDISTTABLE
 | 
						|
 | 
						|
	//CONS_Printf("Got useodds %d. (position: %d, distance: %d)\n", useodds, player->kartstuff[k_position], pdis);
 | 
						|
 | 
						|
	return useodds;
 | 
						|
}
 | 
						|
 | 
						|
static void K_KartItemRoulette(player_t *player, ticcmd_t *cmd)
 | 
						|
{
 | 
						|
	INT32 i;
 | 
						|
	UINT8 pingame = 0;
 | 
						|
	UINT8 roulettestop;
 | 
						|
	INT32 useodds = 0;
 | 
						|
	INT32 spawnchance[NUMKARTRESULTS * NUMKARTODDS];
 | 
						|
	INT32 chance = 0, numchoices = 0;
 | 
						|
	INT32 bestbumper = 0;
 | 
						|
	fixed_t mashed = 0;
 | 
						|
	boolean dontforcespb = false;
 | 
						|
 | 
						|
	// This makes the roulette cycle through items - if this is 0, you shouldn't be here.
 | 
						|
	if (player->kartstuff[k_itemroulette])
 | 
						|
		player->kartstuff[k_itemroulette]++;
 | 
						|
	else
 | 
						|
		return;
 | 
						|
 | 
						|
	// Gotta check how many players are active at this moment.
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator)
 | 
						|
			continue;
 | 
						|
		pingame++;
 | 
						|
		if (players[i].exiting)
 | 
						|
			dontforcespb = true;
 | 
						|
		if (players[i].kartstuff[k_bumper] > bestbumper)
 | 
						|
			bestbumper = players[i].kartstuff[k_bumper];
 | 
						|
	}
 | 
						|
 | 
						|
	// This makes the roulette produce the random noises.
 | 
						|
	if ((player->kartstuff[k_itemroulette] % 3) == 1 && P_IsLocalPlayer(player))
 | 
						|
	{
 | 
						|
#define PLAYROULETTESND S_StartSound(NULL, sfx_itrol1 + ((player->kartstuff[k_itemroulette] / 3) % 8));
 | 
						|
		if (splitscreen)
 | 
						|
		{
 | 
						|
			if (players[displayplayer].kartstuff[k_itemroulette])
 | 
						|
			{
 | 
						|
				if (player == &players[displayplayer])
 | 
						|
					PLAYROULETTESND;
 | 
						|
			}
 | 
						|
			else if (players[secondarydisplayplayer].kartstuff[k_itemroulette])
 | 
						|
			{
 | 
						|
				if (player == &players[secondarydisplayplayer])
 | 
						|
					PLAYROULETTESND;
 | 
						|
			}
 | 
						|
			else if (players[thirddisplayplayer].kartstuff[k_itemroulette] && splitscreen > 1)
 | 
						|
			{
 | 
						|
				if (player == &players[thirddisplayplayer])
 | 
						|
					PLAYROULETTESND;
 | 
						|
			}
 | 
						|
			else if (players[fourthdisplayplayer].kartstuff[k_itemroulette] && splitscreen > 2)
 | 
						|
			{
 | 
						|
				if (player == &players[fourthdisplayplayer])
 | 
						|
					PLAYROULETTESND;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
			PLAYROULETTESND;
 | 
						|
#undef PLAYROULETTESND
 | 
						|
	}
 | 
						|
 | 
						|
	roulettestop = TICRATE + (3*(pingame - player->kartstuff[k_position]));
 | 
						|
 | 
						|
	// If the roulette finishes or the player presses BT_ATTACK, stop the roulette and calculate the item.
 | 
						|
	// I'm returning via the exact opposite, however, to forgo having another bracket embed. Same result either way, I think.
 | 
						|
	// Finally, if you get past this check, now you can actually start calculating what item you get.
 | 
						|
	if ((cmd->buttons & BT_ATTACK) && !(player->kartstuff[k_eggmanheld] || player->kartstuff[k_itemheld]) && player->kartstuff[k_itemroulette] >= roulettestop && !modeattacking)
 | 
						|
	{
 | 
						|
		// Mashing reduces your chances for the good items
 | 
						|
		mashed = FixedDiv((player->kartstuff[k_itemroulette])*FRACUNIT, ((TICRATE*3)+roulettestop)*FRACUNIT) - FRACUNIT;
 | 
						|
	}
 | 
						|
	else if (!(player->kartstuff[k_itemroulette] >= (TICRATE*3)))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (cmd->buttons & BT_ATTACK)
 | 
						|
		player->pflags |= PF_ATTACKDOWN;
 | 
						|
 | 
						|
	if (player->kartstuff[k_roulettetype] == 2) // Fake items
 | 
						|
	{
 | 
						|
		player->kartstuff[k_eggmanexplode] = 4*TICRATE;
 | 
						|
		//player->kartstuff[k_itemblink] = TICRATE;
 | 
						|
		//player->kartstuff[k_itemblinkmode] = 1;
 | 
						|
		player->kartstuff[k_itemroulette] = 0;
 | 
						|
		player->kartstuff[k_roulettetype] = 0;
 | 
						|
		if (P_IsLocalPlayer(player))
 | 
						|
			S_StartSound(NULL, sfx_itrole);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (cv_kartdebugitem.value != 0 && !modeattacking)
 | 
						|
	{
 | 
						|
		K_KartGetItemResult(player, cv_kartdebugitem.value);
 | 
						|
		player->kartstuff[k_itemamount] = cv_kartdebugamount.value;
 | 
						|
		player->kartstuff[k_itemblink] = TICRATE;
 | 
						|
		player->kartstuff[k_itemblinkmode] = 2;
 | 
						|
		player->kartstuff[k_itemroulette] = 0;
 | 
						|
		player->kartstuff[k_roulettetype] = 0;
 | 
						|
		if (P_IsLocalPlayer(player))
 | 
						|
			S_StartSound(NULL, sfx_dbgsal);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	// Initializes existing spawnchance values
 | 
						|
	for (i = 0; i < (NUMKARTRESULTS * NUMKARTODDS); i++)
 | 
						|
		spawnchance[i] = 0;
 | 
						|
 | 
						|
	// Split into another function for a debug function below
 | 
						|
	useodds = K_FindUseodds(player, mashed, pingame, bestbumper, (spbplace != -1 && player->kartstuff[k_position] == spbplace+1), dontforcespb);
 | 
						|
 | 
						|
#define SETITEMRESULT(itemnum) \
 | 
						|
	for (chance = 0; chance < K_KartGetItemOdds(useodds, itemnum, mashed); chance++) \
 | 
						|
		spawnchance[numchoices++] = itemnum
 | 
						|
 | 
						|
	for (i = 1; i < NUMKARTRESULTS; i++)
 | 
						|
		SETITEMRESULT(i);
 | 
						|
 | 
						|
#undef SETITEMRESULT
 | 
						|
 | 
						|
	// Award the player whatever power is rolled
 | 
						|
	if (numchoices > 0)
 | 
						|
		K_KartGetItemResult(player, spawnchance[P_RandomKey(numchoices)]);
 | 
						|
	else
 | 
						|
	{
 | 
						|
		player->kartstuff[k_itemtype] = KITEM_SAD;
 | 
						|
		player->kartstuff[k_itemamount] = 1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (P_IsLocalPlayer(player))
 | 
						|
		S_StartSound(NULL, ((player->kartstuff[k_roulettetype] == 1) ? sfx_itrolk : (mashed ? sfx_itrolm : sfx_itrolf)));
 | 
						|
 | 
						|
	player->kartstuff[k_itemblink] = TICRATE;
 | 
						|
	player->kartstuff[k_itemblinkmode] = ((player->kartstuff[k_roulettetype] == 1) ? 2 : (mashed ? 1 : 0));
 | 
						|
 | 
						|
	player->kartstuff[k_itemroulette] = 0; // Since we're done, clear the roulette number
 | 
						|
	player->kartstuff[k_roulettetype] = 0; // This too
 | 
						|
}
 | 
						|
 | 
						|
//}
 | 
						|
 | 
						|
//{ SRB2kart p_user.c Stuff
 | 
						|
 | 
						|
static fixed_t K_GetMobjWeight(mobj_t *mobj, mobj_t *against)
 | 
						|
{
 | 
						|
	fixed_t weight = 5<<FRACBITS;
 | 
						|
 | 
						|
	switch (mobj->type)
 | 
						|
	{
 | 
						|
		case MT_PLAYER:
 | 
						|
			if (!mobj->player)
 | 
						|
				break;
 | 
						|
			if (against->player && !against->player->kartstuff[k_spinouttimer] && mobj->player->kartstuff[k_spinouttimer])
 | 
						|
				weight = 0; // Do not bump
 | 
						|
			else
 | 
						|
			{
 | 
						|
				weight = (mobj->player->kartweight)<<FRACBITS;
 | 
						|
				if (mobj->player->speed > K_GetKartSpeed(mobj->player, false))
 | 
						|
					weight += (mobj->player->speed - K_GetKartSpeed(mobj->player, false))/8;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case MT_FALLINGROCK:
 | 
						|
			if (against->player)
 | 
						|
			{
 | 
						|
				if (against->player->kartstuff[k_invincibilitytimer]
 | 
						|
					|| against->player->kartstuff[k_growshrinktimer] > 0)
 | 
						|
					weight = 0;
 | 
						|
				else
 | 
						|
					weight = (against->player->kartweight)<<FRACBITS;
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case MT_ORBINAUT:
 | 
						|
		case MT_ORBINAUT_SHIELD:
 | 
						|
			if (against->player)
 | 
						|
				weight = (against->player->kartweight)<<FRACBITS;
 | 
						|
			break;
 | 
						|
		case MT_JAWZ:
 | 
						|
		case MT_JAWZ_DUD:
 | 
						|
		case MT_JAWZ_SHIELD:
 | 
						|
			if (against->player)
 | 
						|
				weight = (against->player->kartweight+3)<<FRACBITS;
 | 
						|
			else
 | 
						|
				weight = 8<<FRACBITS;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	return weight;
 | 
						|
}
 | 
						|
 | 
						|
void K_KartBouncing(mobj_t *mobj1, mobj_t *mobj2, boolean bounce, boolean solid)
 | 
						|
{
 | 
						|
	mobj_t *fx;
 | 
						|
	fixed_t momdifx, momdify;
 | 
						|
	fixed_t distx, disty;
 | 
						|
	fixed_t dot, p;
 | 
						|
	fixed_t mass1, mass2;
 | 
						|
 | 
						|
	if (!mobj1 || !mobj2)
 | 
						|
		return;
 | 
						|
 | 
						|
	// Don't bump when you're being reborn
 | 
						|
	if ((mobj1->player && mobj1->player->playerstate != PST_LIVE)
 | 
						|
		|| (mobj2->player && mobj2->player->playerstate != PST_LIVE))
 | 
						|
		return;
 | 
						|
 | 
						|
	if ((mobj1->player && mobj1->player->kartstuff[k_respawn])
 | 
						|
		|| (mobj2->player && mobj2->player->kartstuff[k_respawn]))
 | 
						|
		return;
 | 
						|
 | 
						|
	// Don't bump if you've recently bumped
 | 
						|
	if (mobj1->player && mobj1->player->kartstuff[k_justbumped])
 | 
						|
	{
 | 
						|
		mobj1->player->kartstuff[k_justbumped] = bumptime;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (mobj2->player && mobj2->player->kartstuff[k_justbumped])
 | 
						|
	{
 | 
						|
		mobj2->player->kartstuff[k_justbumped] = bumptime;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	mass1 = K_GetMobjWeight(mobj1, mobj2);
 | 
						|
 | 
						|
	if (solid == true && mass1 > 0)
 | 
						|
		mass2 = mass1;
 | 
						|
	else
 | 
						|
		mass2 = K_GetMobjWeight(mobj2, mobj1);
 | 
						|
 | 
						|
	momdifx = mobj1->momx - mobj2->momx;
 | 
						|
	momdify = mobj1->momy - mobj2->momy;
 | 
						|
 | 
						|
	// if the speed difference is less than this let's assume they're going proportionately faster from each other
 | 
						|
	if (P_AproxDistance(momdifx, momdify) < (25*mapobjectscale))
 | 
						|
	{
 | 
						|
		fixed_t momdiflength = P_AproxDistance(momdifx, momdify);
 | 
						|
		fixed_t normalisedx = FixedDiv(momdifx, momdiflength);
 | 
						|
		fixed_t normalisedy = FixedDiv(momdify, momdiflength);
 | 
						|
		momdifx = FixedMul((25*mapobjectscale), normalisedx);
 | 
						|
		momdify = FixedMul((25*mapobjectscale), normalisedy);
 | 
						|
	}
 | 
						|
 | 
						|
	// Adds the OTHER player's momentum, so that it reduces the chance of you being "inside" the other object
 | 
						|
	distx = (mobj1->x + mobj2->momx) - (mobj2->x + mobj1->momx);
 | 
						|
	disty = (mobj1->y + mobj2->momy) - (mobj2->y + mobj1->momy);
 | 
						|
 | 
						|
	{ // Don't allow dist to get WAY too low, that it pushes you stupidly huge amounts, or backwards...
 | 
						|
		fixed_t dist = P_AproxDistance(distx, disty);
 | 
						|
		fixed_t nx = FixedDiv(distx, dist);
 | 
						|
		fixed_t ny = FixedDiv(disty, dist);
 | 
						|
 | 
						|
		if (P_AproxDistance(distx, disty) < (3*mobj1->radius)/4)
 | 
						|
		{
 | 
						|
			distx = FixedMul((3*mobj1->radius)/4, nx);
 | 
						|
			disty = FixedMul((3*mobj1->radius)/4, ny);
 | 
						|
		}
 | 
						|
 | 
						|
		if (P_AproxDistance(distx, disty) < (3*mobj2->radius)/4)
 | 
						|
		{
 | 
						|
			distx = FixedMul((3*mobj2->radius)/4, nx);
 | 
						|
			disty = FixedMul((3*mobj2->radius)/4, ny);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (distx == 0 && disty == 0)
 | 
						|
	{
 | 
						|
		// if there's no distance between the 2, they're directly on top of each other, don't run this
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	dot = FixedMul(momdifx, distx) + FixedMul(momdify, disty);
 | 
						|
 | 
						|
	if (dot >= 0)
 | 
						|
	{
 | 
						|
		// They're moving away from each other
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	p = FixedDiv(dot, FixedMul(distx, distx)+FixedMul(disty, disty));
 | 
						|
 | 
						|
	if (bounce == true && mass2 > 0) // Perform a Goomba Bounce.
 | 
						|
		mobj1->momz = -mobj1->momz;
 | 
						|
	else
 | 
						|
	{
 | 
						|
		fixed_t newz = mobj1->momz;
 | 
						|
		if (mass2 > 0)
 | 
						|
			mobj1->momz = mobj2->momz;
 | 
						|
		if (mass1 > 0 && solid == false)
 | 
						|
			mobj2->momz = newz;
 | 
						|
	}
 | 
						|
 | 
						|
	if (mass2 > 0)
 | 
						|
	{
 | 
						|
		mobj1->momx = mobj1->momx - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), p), distx);
 | 
						|
		mobj1->momy = mobj1->momy - FixedMul(FixedMul(FixedDiv(2*mass2, mass1 + mass2), p), disty);
 | 
						|
	}
 | 
						|
 | 
						|
	if (mass1 > 0 && solid == false)
 | 
						|
	{
 | 
						|
		mobj2->momx = mobj2->momx - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), p), -distx);
 | 
						|
		mobj2->momy = mobj2->momy - FixedMul(FixedMul(FixedDiv(2*mass1, mass1 + mass2), p), -disty);
 | 
						|
	}
 | 
						|
 | 
						|
	// Do the bump fx when we've CONFIRMED we can bump.
 | 
						|
	S_StartSound(mobj1, sfx_s3k49);
 | 
						|
 | 
						|
	fx = P_SpawnMobj(mobj1->x/2 + mobj2->x/2, mobj1->y/2 + mobj2->y/2, mobj1->z/2 + mobj2->z/2, MT_BUMP);
 | 
						|
	if (mobj1->eflags & MFE_VERTICALFLIP)
 | 
						|
		fx->eflags |= MFE_VERTICALFLIP;
 | 
						|
	else
 | 
						|
		fx->eflags &= ~MFE_VERTICALFLIP;
 | 
						|
	P_SetScale(fx, mobj1->scale);
 | 
						|
 | 
						|
	// Because this is done during collision now, rmomx and rmomy need to be recalculated
 | 
						|
	// so that friction doesn't immediately decide to stop the player if they're at a standstill
 | 
						|
	// Also set justbumped here
 | 
						|
	if (mobj1->player)
 | 
						|
	{
 | 
						|
		mobj1->player->rmomx = mobj1->momx - mobj1->player->cmomx;
 | 
						|
		mobj1->player->rmomy = mobj1->momy - mobj1->player->cmomy;
 | 
						|
		mobj1->player->kartstuff[k_justbumped] = bumptime;
 | 
						|
		if (mobj1->player->kartstuff[k_spinouttimer])
 | 
						|
		{
 | 
						|
			mobj1->player->kartstuff[k_wipeoutslow] += wipeoutslowtime+1;
 | 
						|
			mobj1->player->kartstuff[k_spinouttimer] += wipeoutslowtime+1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (mobj2->player)
 | 
						|
	{
 | 
						|
		mobj2->player->rmomx = mobj2->momx - mobj2->player->cmomx;
 | 
						|
		mobj2->player->rmomy = mobj2->momy - mobj2->player->cmomy;
 | 
						|
		mobj2->player->kartstuff[k_justbumped] = bumptime;
 | 
						|
		if (mobj2->player->kartstuff[k_spinouttimer])
 | 
						|
		{
 | 
						|
			mobj2->player->kartstuff[k_wipeoutslow] += wipeoutslowtime+1;
 | 
						|
			mobj2->player->kartstuff[k_spinouttimer] += wipeoutslowtime+1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief	Checks that the player is on an offroad subsector for realsies
 | 
						|
 | 
						|
	\param	mo	player mobj object
 | 
						|
 | 
						|
	\return	boolean
 | 
						|
*/
 | 
						|
static UINT8 K_CheckOffroadCollide(mobj_t *mo, sector_t *sec)
 | 
						|
{
 | 
						|
	UINT8 i;
 | 
						|
	sector_t *sec2;
 | 
						|
 | 
						|
	I_Assert(mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(mo));
 | 
						|
 | 
						|
	sec2 = P_ThingOnSpecial3DFloor(mo);
 | 
						|
 | 
						|
	for (i = 2; i < 5; i++)
 | 
						|
	{
 | 
						|
		if ((sec2 && GETSECSPECIAL(sec2->special, 1) == i)
 | 
						|
			|| (P_IsObjectOnRealGround(mo, sec)
 | 
						|
			&& GETSECSPECIAL(sec->special, 1) == i))
 | 
						|
			return i;
 | 
						|
	}
 | 
						|
 | 
						|
	return 0;
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief	Updates the Player's offroad value once per frame
 | 
						|
 | 
						|
	\param	player	player object passed from K_KartPlayerThink
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
static void K_UpdateOffroad(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t kartweight = player->kartweight;
 | 
						|
	fixed_t offroad;
 | 
						|
	sector_t *nextsector = R_PointInSubsector(
 | 
						|
		player->mo->x + player->mo->momx*2, player->mo->y + player->mo->momy*2)->sector;
 | 
						|
 | 
						|
	fixed_t offroadstrength = 0;
 | 
						|
 | 
						|
	if (K_CheckOffroadCollide(player->mo, nextsector) == 2)	// Weak Offroad
 | 
						|
		offroadstrength = 1;
 | 
						|
	else if (K_CheckOffroadCollide(player->mo, nextsector) == 3)	// Mid Offroad
 | 
						|
		offroadstrength = 2;
 | 
						|
	else if (K_CheckOffroadCollide(player->mo, nextsector) == 4)	// Strong Offroad
 | 
						|
		offroadstrength = 3;
 | 
						|
 | 
						|
	// If you are offroad, a timer starts. Depending on your weight value, the timer increments differently.
 | 
						|
	//if ((nextsector->special & 256) && nextsector->special != 768
 | 
						|
	//	&& nextsector->special != 1024 && nextsector->special != 4864)
 | 
						|
	if (offroadstrength)
 | 
						|
	{
 | 
						|
		if (K_CheckOffroadCollide(player->mo, player->mo->subsector->sector) && player->kartstuff[k_offroad] == 0)
 | 
						|
			player->kartstuff[k_offroad] = 16;
 | 
						|
 | 
						|
		if (player->kartstuff[k_offroad] > 0)
 | 
						|
		{
 | 
						|
			// 1872 is the magic number - 35 frames adds up to approximately 65536. 1872/4 = 468/3 = 156
 | 
						|
			// A higher kart weight means you can stay offroad for longer without losing speed
 | 
						|
			offroad = (1872 + 5*156 - kartweight*156)*offroadstrength;
 | 
						|
 | 
						|
			//if (player->kartstuff[k_growshrinktimer] > 1) // grow slows down half as fast
 | 
						|
			//	offroad /= 2;
 | 
						|
 | 
						|
			player->kartstuff[k_offroad] += offroad;
 | 
						|
		}
 | 
						|
 | 
						|
		if (player->kartstuff[k_offroad] > FRACUNIT*offroadstrength)
 | 
						|
			player->kartstuff[k_offroad] = FRACUNIT*offroadstrength;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		player->kartstuff[k_offroad] = 0;
 | 
						|
}
 | 
						|
 | 
						|
// These have to go earlier than its sisters because of K_RespawnChecker...
 | 
						|
void K_MatchGenericExtraFlags(mobj_t *mo, mobj_t *master)
 | 
						|
{
 | 
						|
	// flipping
 | 
						|
	mo->eflags = (mo->eflags & ~MFE_VERTICALFLIP)|(master->eflags & MFE_VERTICALFLIP);
 | 
						|
	// visibility (usually for hyudoro)
 | 
						|
	mo->flags2 = (mo->flags2 & ~MF2_DONTDRAW)|(master->flags2 & MF2_DONTDRAW);
 | 
						|
	mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP1)|(master->eflags & MFE_DRAWONLYFORP1);
 | 
						|
	mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP2)|(master->eflags & MFE_DRAWONLYFORP2);
 | 
						|
	mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP3)|(master->eflags & MFE_DRAWONLYFORP3);
 | 
						|
	mo->eflags = (mo->eflags & ~MFE_DRAWONLYFORP4)|(master->eflags & MFE_DRAWONLYFORP4);
 | 
						|
}
 | 
						|
 | 
						|
static void K_SpawnDashDustRelease(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t newx;
 | 
						|
	fixed_t newy;
 | 
						|
	mobj_t *dust;
 | 
						|
	angle_t travelangle;
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	I_Assert(player != NULL);
 | 
						|
	I_Assert(player->mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(player->mo));
 | 
						|
 | 
						|
	if (!P_IsObjectOnGround(player->mo))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!player->speed && !player->kartstuff[k_startboost])
 | 
						|
		return;
 | 
						|
 | 
						|
	travelangle = player->mo->angle;
 | 
						|
 | 
						|
	if (player->kartstuff[k_drift] || player->kartstuff[k_driftend])
 | 
						|
		travelangle -= (ANGLE_45/5)*player->kartstuff[k_drift];
 | 
						|
 | 
						|
	for (i = 0; i < 2; i++)
 | 
						|
	{
 | 
						|
		newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_90, FixedMul(48*FRACUNIT, player->mo->scale));
 | 
						|
		newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_90, FixedMul(48*FRACUNIT, player->mo->scale));
 | 
						|
		dust = P_SpawnMobj(newx, newy, player->mo->z, MT_FASTDUST);
 | 
						|
 | 
						|
		P_SetTarget(&dust->target, player->mo);
 | 
						|
		dust->angle = travelangle - ((i&1) ? -1 : 1)*ANGLE_45;
 | 
						|
		dust->destscale = player->mo->scale;
 | 
						|
		P_SetScale(dust, player->mo->scale);
 | 
						|
 | 
						|
		dust->momx = 3*player->mo->momx/5;
 | 
						|
		dust->momy = 3*player->mo->momy/5;
 | 
						|
		//dust->momz = 3*player->mo->momz/5;
 | 
						|
 | 
						|
		K_MatchGenericExtraFlags(dust, player->mo);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_SpawnBrakeDriftSparks(player_t *player) // Be sure to update the mobj thinker case too!
 | 
						|
{
 | 
						|
	mobj_t *sparks;
 | 
						|
 | 
						|
	I_Assert(player != NULL);
 | 
						|
	I_Assert(player->mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(player->mo));
 | 
						|
 | 
						|
	// Position & etc are handled in its thinker, and its spawned invisible.
 | 
						|
	// This avoids needing to dupe code if we don't need it.
 | 
						|
	sparks = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BRAKEDRIFT);
 | 
						|
	P_SetTarget(&sparks->target, player->mo);
 | 
						|
	P_SetScale(sparks, (sparks->destscale = player->mo->scale));
 | 
						|
	K_MatchGenericExtraFlags(sparks, player->mo);
 | 
						|
	sparks->flags2 |= MF2_DONTDRAW;
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief	Calculates the respawn timer and drop-boosting
 | 
						|
 | 
						|
	\param	player	player object passed from K_KartPlayerThink
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
void K_RespawnChecker(player_t *player)
 | 
						|
{
 | 
						|
	ticcmd_t *cmd = &player->cmd;
 | 
						|
 | 
						|
	if (player->spectator)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (player->kartstuff[k_respawn] > 1)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_respawn]--;
 | 
						|
		player->mo->momz = 0;
 | 
						|
		player->powers[pw_flashing] = 2;
 | 
						|
		player->powers[pw_nocontrol] = 2;
 | 
						|
		if (leveltime % 8 == 0)
 | 
						|
		{
 | 
						|
			INT32 i;
 | 
						|
			if (!mapreset)
 | 
						|
				S_StartSound(player->mo, sfx_s3kcas);
 | 
						|
 | 
						|
			for (i = 0; i < 8; i++)
 | 
						|
			{
 | 
						|
				mobj_t *mo;
 | 
						|
				angle_t newangle;
 | 
						|
				fixed_t newx, newy, newz;
 | 
						|
 | 
						|
				newangle = FixedAngle(((360/8)*i)*FRACUNIT);
 | 
						|
				newx = player->mo->x + P_ReturnThrustX(player->mo, newangle, 31<<FRACBITS); // does NOT use scale, since this effect doesn't scale properly
 | 
						|
				newy = player->mo->y + P_ReturnThrustY(player->mo, newangle, 31<<FRACBITS);
 | 
						|
				if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
					newz = player->mo->z + player->mo->height;
 | 
						|
				else
 | 
						|
					newz = player->mo->z;
 | 
						|
 | 
						|
				mo = P_SpawnMobj(newx, newy, newz, MT_DEZLASER);
 | 
						|
				if (mo)
 | 
						|
				{
 | 
						|
					if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
						mo->eflags |= MFE_VERTICALFLIP;
 | 
						|
					P_SetTarget(&mo->target, player->mo);
 | 
						|
					mo->angle = newangle+ANGLE_90;
 | 
						|
					mo->momz = (8*FRACUNIT)*P_MobjFlip(player->mo);
 | 
						|
					P_SetScale(mo, (mo->destscale = FRACUNIT));
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (player->kartstuff[k_respawn] == 1)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_growshrinktimer] < 0)
 | 
						|
		{
 | 
						|
			player->mo->scalespeed = mapobjectscale/TICRATE;
 | 
						|
			player->mo->destscale = (6*mapobjectscale)/8;
 | 
						|
			if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
 | 
						|
				player->mo->destscale = (6*player->mo->destscale)/8;
 | 
						|
		}
 | 
						|
 | 
						|
		if (!P_IsObjectOnGround(player->mo) && !mapreset)
 | 
						|
		{
 | 
						|
			player->powers[pw_flashing] = 2;
 | 
						|
 | 
						|
			// Sal: The old behavior was stupid and prone to accidental usage.
 | 
						|
			// Let's rip off Mania instead, and turn this into a Drop Dash!
 | 
						|
 | 
						|
			if (cmd->buttons & BT_ACCELERATE)
 | 
						|
				player->kartstuff[k_dropdash]++;
 | 
						|
			else
 | 
						|
				player->kartstuff[k_dropdash] = 0;
 | 
						|
 | 
						|
			if (player->kartstuff[k_dropdash] == TICRATE/4)
 | 
						|
				S_StartSound(player->mo, sfx_ddash);
 | 
						|
 | 
						|
			if ((player->kartstuff[k_dropdash] >= TICRATE/4)
 | 
						|
				&& (player->kartstuff[k_dropdash] & 1))
 | 
						|
				player->mo->colorized = true;
 | 
						|
			else
 | 
						|
				player->mo->colorized = false;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if ((cmd->buttons & BT_ACCELERATE) && (player->kartstuff[k_dropdash] >= TICRATE/4))
 | 
						|
			{
 | 
						|
				S_StartSound(player->mo, sfx_s23c);
 | 
						|
				player->kartstuff[k_startboost] = 50;
 | 
						|
				K_SpawnDashDustRelease(player);
 | 
						|
			}
 | 
						|
			player->mo->colorized = false;
 | 
						|
			player->kartstuff[k_dropdash] = 0;
 | 
						|
			player->kartstuff[k_respawn] = 0;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief Handles the state changing for moving players, moved here to eliminate duplicate code
 | 
						|
 | 
						|
	\param	player	player data
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
void K_KartMoveAnimation(player_t *player)
 | 
						|
{
 | 
						|
	ticcmd_t *cmd = &player->cmd;
 | 
						|
	// Standing frames - S_KART_STND1   S_KART_STND1_L   S_KART_STND1_R
 | 
						|
	if (player->speed == 0)
 | 
						|
	{
 | 
						|
		if (cmd->driftturn < 0 && !(player->mo->state >= &states[S_KART_STND1_R] && player->mo->state <= &states[S_KART_STND2_R]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_STND1_R);
 | 
						|
		else if (cmd->driftturn > 0 && !(player->mo->state >= &states[S_KART_STND1_L] && player->mo->state <= &states[S_KART_STND2_L]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_STND1_L);
 | 
						|
		else if (cmd->driftturn == 0 && !(player->mo->state >= &states[S_KART_STND1] && player->mo->state <= &states[S_KART_STND2]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_STND1);
 | 
						|
	}
 | 
						|
	// Drifting Left - S_KART_DRIFT1_L
 | 
						|
	else if (player->kartstuff[k_drift] > 0 && P_IsObjectOnGround(player->mo))
 | 
						|
	{
 | 
						|
		if (!(player->mo->state >= &states[S_KART_DRIFT1_L] && player->mo->state <= &states[S_KART_DRIFT2_L]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_DRIFT1_L);
 | 
						|
	}
 | 
						|
	// Drifting Right - S_KART_DRIFT1_R
 | 
						|
	else if (player->kartstuff[k_drift] < 0 && P_IsObjectOnGround(player->mo))
 | 
						|
	{
 | 
						|
		if (!(player->mo->state >= &states[S_KART_DRIFT1_R] && player->mo->state <= &states[S_KART_DRIFT2_R]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_DRIFT1_R);
 | 
						|
	}
 | 
						|
	// Run frames - S_KART_RUN1   S_KART_RUN1_L   S_KART_RUN1_R
 | 
						|
	else if (player->speed > FixedMul(player->runspeed, player->mo->scale))
 | 
						|
	{
 | 
						|
		if (cmd->driftturn < 0 && !(player->mo->state >= &states[S_KART_RUN1_R] && player->mo->state <= &states[S_KART_RUN2_R]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_RUN1_R);
 | 
						|
		else if (cmd->driftturn > 0 && !(player->mo->state >= &states[S_KART_RUN1_L] && player->mo->state <= &states[S_KART_RUN2_L]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_RUN1_L);
 | 
						|
		else if (cmd->driftturn == 0 && !(player->mo->state >= &states[S_KART_RUN1] && player->mo->state <= &states[S_KART_RUN2]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_RUN1);
 | 
						|
	}
 | 
						|
	// Walk frames - S_KART_WALK1   S_KART_WALK1_L   S_KART_WALK1_R
 | 
						|
	else if (player->speed <= FixedMul(player->runspeed, player->mo->scale))
 | 
						|
	{
 | 
						|
		if (cmd->driftturn < 0 && !(player->mo->state >= &states[S_KART_WALK1_R] && player->mo->state <= &states[S_KART_WALK2_R]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_WALK1_R);
 | 
						|
		else if (cmd->driftturn > 0 && !(player->mo->state >= &states[S_KART_WALK1_L] && player->mo->state <= &states[S_KART_WALK2_L]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_WALK1_L);
 | 
						|
		else if (cmd->driftturn == 0 && !(player->mo->state >= &states[S_KART_WALK1] && player->mo->state <= &states[S_KART_WALK2]))
 | 
						|
			P_SetPlayerMobjState(player->mo, S_KART_WALK1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_TauntVoiceTimers(player_t *player)
 | 
						|
{
 | 
						|
	if (!player)
 | 
						|
		return;
 | 
						|
 | 
						|
	player->kartstuff[k_tauntvoices] = 6*TICRATE;
 | 
						|
	player->kartstuff[k_voices] = 4*TICRATE;
 | 
						|
}
 | 
						|
 | 
						|
static void K_RegularVoiceTimers(player_t *player)
 | 
						|
{
 | 
						|
	if (!player)
 | 
						|
		return;
 | 
						|
 | 
						|
	player->kartstuff[k_voices] = 4*TICRATE;
 | 
						|
 | 
						|
	if (player->kartstuff[k_tauntvoices] < 4*TICRATE)
 | 
						|
		player->kartstuff[k_tauntvoices] = 4*TICRATE;
 | 
						|
}
 | 
						|
 | 
						|
static void K_PlayAttackTaunt(mobj_t *source)
 | 
						|
{
 | 
						|
	sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons
 | 
						|
	boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]);
 | 
						|
 | 
						|
	if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2))
 | 
						|
		S_StartSound(source, sfx_kattk1+pick);
 | 
						|
 | 
						|
	if (!tasteful)
 | 
						|
		return;
 | 
						|
 | 
						|
	K_TauntVoiceTimers(source->player);
 | 
						|
}
 | 
						|
 | 
						|
static void K_PlayBoostTaunt(mobj_t *source)
 | 
						|
{
 | 
						|
	sfxenum_t pick = P_RandomKey(2); // Gotta roll the RNG every time this is called for sync reasons
 | 
						|
	boolean tasteful = (!source->player || !source->player->kartstuff[k_tauntvoices]);
 | 
						|
 | 
						|
	if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2))
 | 
						|
		S_StartSound(source, sfx_kbost1+pick);
 | 
						|
 | 
						|
	if (!tasteful)
 | 
						|
		return;
 | 
						|
 | 
						|
	K_TauntVoiceTimers(source->player);
 | 
						|
}
 | 
						|
 | 
						|
static void K_PlayOvertakeSound(mobj_t *source)
 | 
						|
{
 | 
						|
	boolean tasteful = (!source->player || !source->player->kartstuff[k_voices]);
 | 
						|
 | 
						|
	if (!G_RaceGametype()) // Only in race
 | 
						|
		return;
 | 
						|
 | 
						|
	// 4 seconds from before race begins, 10 seconds afterwards
 | 
						|
	if (leveltime < starttime+(10*TICRATE))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (cv_kartvoices.value && (tasteful || cv_kartvoices.value == 2))
 | 
						|
		S_StartSound(source, sfx_kslow);
 | 
						|
 | 
						|
	if (!tasteful)
 | 
						|
		return;
 | 
						|
 | 
						|
	K_RegularVoiceTimers(source->player);
 | 
						|
}
 | 
						|
 | 
						|
static void K_PlayHitEmSound(mobj_t *source)
 | 
						|
{
 | 
						|
	if (cv_kartvoices.value)
 | 
						|
		S_StartSound(source, sfx_khitem);
 | 
						|
	else
 | 
						|
		S_StartSound(source, sfx_s1c9); // The only lost gameplay functionality with voices disabled
 | 
						|
 | 
						|
	K_RegularVoiceTimers(source->player);
 | 
						|
}
 | 
						|
 | 
						|
static void K_PlayPowerGloatSound(mobj_t *source)
 | 
						|
{
 | 
						|
	if (cv_kartvoices.value)
 | 
						|
		S_StartSound(source, sfx_kgloat);
 | 
						|
 | 
						|
	K_RegularVoiceTimers(source->player);
 | 
						|
}
 | 
						|
 | 
						|
void K_MomentumToFacing(player_t *player)
 | 
						|
{
 | 
						|
	angle_t dangle = player->mo->angle - R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
 | 
						|
 | 
						|
	if (dangle > ANGLE_180)
 | 
						|
		dangle = InvAngle(dangle);
 | 
						|
 | 
						|
	// If you aren't on the ground or are moving in too different of a direction don't do this
 | 
						|
	if (player->mo->eflags & MFE_JUSTHITFLOOR)
 | 
						|
		; // Just hit floor ALWAYS redirects
 | 
						|
	else if (!P_IsObjectOnGround(player->mo) || dangle > ANGLE_90)
 | 
						|
		return;
 | 
						|
 | 
						|
	P_Thrust(player->mo, player->mo->angle, player->speed - FixedMul(player->speed, player->mo->friction));
 | 
						|
	player->mo->momx = FixedMul(player->mo->momx - player->cmomx, player->mo->friction) + player->cmomx;
 | 
						|
	player->mo->momy = FixedMul(player->mo->momy - player->cmomy, player->mo->friction) + player->cmomy;
 | 
						|
}
 | 
						|
 | 
						|
// sets k_boostpower, k_speedboost, and k_accelboost to whatever we need it to be
 | 
						|
static void K_GetKartBoostPower(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t boostpower = FRACUNIT;
 | 
						|
	fixed_t speedboost = 0, accelboost = 0;
 | 
						|
 | 
						|
	if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow] == 1) // Slow down after you've been bumped
 | 
						|
	{
 | 
						|
		player->kartstuff[k_boostpower] = player->kartstuff[k_speedboost] = player->kartstuff[k_accelboost] = 0;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	// Offroad is separate, it's difficult to factor it in with a variable value anyway.
 | 
						|
	if (!(player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_hyudorotimer] || player->kartstuff[k_sneakertimer])
 | 
						|
		&& player->kartstuff[k_offroad] >= 0)
 | 
						|
		boostpower = FixedDiv(boostpower, player->kartstuff[k_offroad] + FRACUNIT);
 | 
						|
 | 
						|
	if (player->kartstuff[k_itemtype] == KITEM_KITCHENSINK)
 | 
						|
		boostpower = max((TICRATE/2), (5*TICRATE)-(player->kartstuff[k_bananadrag]/2))*boostpower/(5*TICRATE);
 | 
						|
	else if (player->kartstuff[k_bananadrag] > TICRATE)
 | 
						|
		boostpower = 4*boostpower/5;
 | 
						|
 | 
						|
	// Banana drag/offroad dust
 | 
						|
	if (boostpower < FRACUNIT
 | 
						|
		&& player->mo && P_IsObjectOnGround(player->mo)
 | 
						|
		&& player->speed > 0
 | 
						|
		&& !player->spectator)
 | 
						|
	{
 | 
						|
		K_SpawnWipeoutTrail(player->mo, true);
 | 
						|
		if (leveltime % 6 == 0)
 | 
						|
			S_StartSound(player->mo, sfx_cdfm70);
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_sneakertimer]) // Sneaker
 | 
						|
	{
 | 
						|
		switch (gamespeed)
 | 
						|
		{
 | 
						|
			case 0:
 | 
						|
				speedboost = max(speedboost, 53740+768);
 | 
						|
				break;
 | 
						|
			case 2:
 | 
						|
				speedboost = max(speedboost, 17294+768);
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				speedboost = max(speedboost, 32768);
 | 
						|
				break;
 | 
						|
		}
 | 
						|
		accelboost = max(accelboost, 8*FRACUNIT); // + 800%
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_invincibilitytimer]) // Invincibility
 | 
						|
	{
 | 
						|
		speedboost = max(speedboost, 3*FRACUNIT/8); // + 37.5%
 | 
						|
		accelboost = max(accelboost, 3*FRACUNIT); // + 300%
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_growshrinktimer] > 0) // Grow
 | 
						|
	{
 | 
						|
		speedboost = max(speedboost, FRACUNIT/5); // + 20%
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_driftboost]) // Drift Boost
 | 
						|
	{
 | 
						|
		speedboost = max(speedboost, FRACUNIT/4); // + 25%
 | 
						|
		accelboost = max(accelboost, 4*FRACUNIT); // + 400%
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_startboost]) // Startup Boost
 | 
						|
	{
 | 
						|
		speedboost = max(speedboost, FRACUNIT/4); // + 25%
 | 
						|
		accelboost = max(accelboost, 6*FRACUNIT); // + 300%
 | 
						|
	}
 | 
						|
 | 
						|
	// don't average them anymore, this would make a small boost and a high boost less useful
 | 
						|
	// just take the highest we want instead
 | 
						|
 | 
						|
	player->kartstuff[k_boostpower] = boostpower;
 | 
						|
 | 
						|
	// value smoothing
 | 
						|
	if (speedboost > player->kartstuff[k_speedboost])
 | 
						|
		player->kartstuff[k_speedboost] = speedboost;
 | 
						|
	else
 | 
						|
		player->kartstuff[k_speedboost] += (speedboost - player->kartstuff[k_speedboost])/(TICRATE/2);
 | 
						|
 | 
						|
	player->kartstuff[k_accelboost] = accelboost;
 | 
						|
}
 | 
						|
 | 
						|
fixed_t K_GetKartSpeed(player_t *player, boolean doboostpower)
 | 
						|
{
 | 
						|
	fixed_t k_speed = 150;
 | 
						|
	fixed_t g_cc = FRACUNIT;
 | 
						|
	fixed_t xspd = 3072;		// 4.6875 aka 3/64
 | 
						|
	UINT8 kartspeed = player->kartspeed;
 | 
						|
	fixed_t finalspeed;
 | 
						|
 | 
						|
	if (doboostpower && !player->kartstuff[k_pogospring] && !P_IsObjectOnGround(player->mo))
 | 
						|
		return (75*mapobjectscale); // air speed cap
 | 
						|
 | 
						|
	switch (gamespeed)
 | 
						|
	{
 | 
						|
		case 0:
 | 
						|
			g_cc = 53248 + xspd; //  50cc =  81.25 + 4.69 =  85.94%
 | 
						|
			break;
 | 
						|
		case 2:
 | 
						|
			g_cc = 77824 + xspd; // 150cc = 118.75 + 4.69 = 123.44%
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			g_cc = 65536 + xspd; // 100cc = 100.00 + 4.69 = 104.69%
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0)
 | 
						|
		kartspeed = 1;
 | 
						|
 | 
						|
	k_speed += kartspeed*3; // 153 - 177
 | 
						|
 | 
						|
	finalspeed = FixedMul(FixedMul(k_speed<<14, g_cc), player->mo->scale);
 | 
						|
 | 
						|
	if (doboostpower)
 | 
						|
		return FixedMul(finalspeed, player->kartstuff[k_boostpower]+player->kartstuff[k_speedboost]);
 | 
						|
	return finalspeed;
 | 
						|
}
 | 
						|
 | 
						|
fixed_t K_GetKartAccel(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t k_accel = 32; // 36;
 | 
						|
	UINT8 kartspeed = player->kartspeed;
 | 
						|
 | 
						|
	if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0)
 | 
						|
		kartspeed = 1;
 | 
						|
 | 
						|
	//k_accel += 3 * (9 - kartspeed); // 36 - 60
 | 
						|
	k_accel += 4 * (9 - kartspeed); // 32 - 64
 | 
						|
 | 
						|
	return FixedMul(k_accel, FRACUNIT+player->kartstuff[k_accelboost]);
 | 
						|
}
 | 
						|
 | 
						|
UINT16 K_GetKartFlashing(player_t *player)
 | 
						|
{
 | 
						|
    UINT16 tics = flashingtics;
 | 
						|
    if (G_BattleGametype())
 | 
						|
        tics *= 2;
 | 
						|
    tics += (flashingtics/8) * (player->kartspeed);
 | 
						|
    return tics;
 | 
						|
}
 | 
						|
 | 
						|
fixed_t K_3dKartMovement(player_t *player, boolean onground, fixed_t forwardmove)
 | 
						|
{
 | 
						|
	fixed_t accelmax = 4000;
 | 
						|
	fixed_t newspeed, oldspeed, finalspeed;
 | 
						|
	fixed_t p_speed = K_GetKartSpeed(player, true);
 | 
						|
	fixed_t p_accel = K_GetKartAccel(player);
 | 
						|
 | 
						|
	if (!onground) return 0; // If the player isn't on the ground, there is no change in speed
 | 
						|
 | 
						|
	// ACCELCODE!!!1!11!
 | 
						|
	oldspeed = R_PointToDist2(0, 0, player->rmomx, player->rmomy); // FixedMul(P_AproxDistance(player->rmomx, player->rmomy), player->mo->scale);
 | 
						|
	newspeed = FixedDiv(FixedDiv(FixedMul(oldspeed, accelmax - p_accel) + FixedMul(p_speed, p_accel), accelmax), ORIG_FRICTION);
 | 
						|
 | 
						|
	if (player->kartstuff[k_pogospring]) // Pogo Spring minimum/maximum thrust
 | 
						|
	{
 | 
						|
		const fixed_t hscale = mapobjectscale /*+ (mapobjectscale - player->mo->scale)*/;
 | 
						|
		const fixed_t minspeed = 24*hscale;
 | 
						|
		const fixed_t maxspeed = 28*hscale;
 | 
						|
 | 
						|
		if (newspeed > maxspeed && player->kartstuff[k_pogospring] == 2)
 | 
						|
			newspeed = maxspeed;
 | 
						|
		if (newspeed < minspeed)
 | 
						|
			newspeed = minspeed;
 | 
						|
	}
 | 
						|
 | 
						|
	finalspeed = newspeed - oldspeed;
 | 
						|
 | 
						|
	// forwardmove is:
 | 
						|
	//  50 while accelerating,
 | 
						|
	//  25 while clutching,
 | 
						|
	//   0 with no gas, and
 | 
						|
	// -25 when only braking.
 | 
						|
 | 
						|
	finalspeed *= forwardmove/25;
 | 
						|
	finalspeed /= 2;
 | 
						|
 | 
						|
	if (forwardmove < 0 && finalspeed > FRACUNIT*2)
 | 
						|
		return finalspeed/2;
 | 
						|
	else if (forwardmove < 0)
 | 
						|
		return -FRACUNIT/2;
 | 
						|
 | 
						|
	if (finalspeed < 0)
 | 
						|
		finalspeed = 0;
 | 
						|
 | 
						|
	return finalspeed;
 | 
						|
}
 | 
						|
 | 
						|
void K_DoInstashield(player_t *player)
 | 
						|
{
 | 
						|
	mobj_t *layera;
 | 
						|
	mobj_t *layerb;
 | 
						|
 | 
						|
	if (player->kartstuff[k_instashield] > 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	player->kartstuff[k_instashield] = 15; // length of instashield animation
 | 
						|
	S_StartSound(player->mo, sfx_cdpcm9);
 | 
						|
 | 
						|
	layera = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTASHIELDA);
 | 
						|
	P_SetTarget(&layera->target, player->mo);
 | 
						|
 | 
						|
	layerb = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INSTASHIELDB);
 | 
						|
	P_SetTarget(&layerb->target, player->mo);
 | 
						|
}
 | 
						|
 | 
						|
void K_SpawnBattlePoints(player_t *source, player_t *victim, UINT8 amount)
 | 
						|
{
 | 
						|
	statenum_t st;
 | 
						|
	mobj_t *pt;
 | 
						|
 | 
						|
	if (!source || !source->mo)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (amount == 1)
 | 
						|
		st = S_BATTLEPOINT1A;
 | 
						|
	else if (amount == 2)
 | 
						|
		st = S_BATTLEPOINT2A;
 | 
						|
	else if (amount == 3)
 | 
						|
		st = S_BATTLEPOINT3A;
 | 
						|
	else
 | 
						|
		return; // NO STATE!
 | 
						|
 | 
						|
	pt = P_SpawnMobj(source->mo->x, source->mo->y, source->mo->z, MT_BATTLEPOINT);
 | 
						|
	P_SetTarget(&pt->target, source->mo);
 | 
						|
	P_SetMobjState(pt, st);
 | 
						|
	if (victim && victim->skincolor)
 | 
						|
		pt->color = victim->skincolor;
 | 
						|
	else
 | 
						|
		pt->color = source->skincolor;
 | 
						|
}
 | 
						|
 | 
						|
void K_SpinPlayer(player_t *player, mobj_t *source, INT32 type, mobj_t *inflictor, boolean trapitem)
 | 
						|
{
 | 
						|
	UINT8 scoremultiply = 1;
 | 
						|
	// PS: Inflictor is unused for all purposes here and is actually only ever relevant to Lua. It may be nil too.
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
	boolean force = false;	// Used to check if Lua ShouldSpin should get us damaged reguardless of flashtics or heck knows what.
 | 
						|
	UINT8 shouldForce = LUAh_ShouldSpin(player, inflictor, source);
 | 
						|
	if (P_MobjWasRemoved(player->mo))
 | 
						|
		return; // mobj was removed (in theory that shouldn't happen)
 | 
						|
	if (shouldForce == 1)
 | 
						|
		force = true;
 | 
						|
	else if (shouldForce == 2)
 | 
						|
		return;
 | 
						|
#else
 | 
						|
	static const boolean force = false;
 | 
						|
	(void)inflictor;	// in case some weirdo doesn't want Lua.
 | 
						|
#endif
 | 
						|
 | 
						|
 | 
						|
	if (!trapitem && G_BattleGametype())
 | 
						|
	{
 | 
						|
		if (K_IsPlayerWanted(player))
 | 
						|
			scoremultiply = 3;
 | 
						|
		else if (player->kartstuff[k_bumper] == 1)
 | 
						|
			scoremultiply = 2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->health <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0
 | 
						|
		|| player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0
 | 
						|
		|| (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1)))
 | 
						|
	{
 | 
						|
		if (!force)	// if shoulddamage force, we go THROUGH that.
 | 
						|
		{
 | 
						|
			K_DoInstashield(player);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (LUAh_PlayerSpin(player, inflictor, source))	// Let Lua do its thing or overwrite if it wants to. Make sure to let any possible instashield happen because we didn't get "damaged" in this case.
 | 
						|
		return;
 | 
						|
 | 
						|
	if (source && source != player->mo && source->player)
 | 
						|
		K_PlayHitEmSound(source);
 | 
						|
 | 
						|
	//player->kartstuff[k_sneakertimer] = 0;
 | 
						|
	player->kartstuff[k_driftboost] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_drift] = 0;
 | 
						|
	player->kartstuff[k_driftcharge] = 0;
 | 
						|
	player->kartstuff[k_pogospring] = 0;
 | 
						|
 | 
						|
	if (G_BattleGametype())
 | 
						|
	{
 | 
						|
		if (source && source->player && player != source->player)
 | 
						|
		{
 | 
						|
			P_AddPlayerScore(source->player, scoremultiply);
 | 
						|
			K_SpawnBattlePoints(source->player, player, scoremultiply);
 | 
						|
			if (!trapitem)
 | 
						|
			{
 | 
						|
				source->player->kartstuff[k_wanted] -= wantedreduce;
 | 
						|
				player->kartstuff[k_wanted] -= (wantedreduce/2);
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (player->kartstuff[k_bumper] > 0)
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_bumper] == 1)
 | 
						|
			{
 | 
						|
				mobj_t *karmahitbox = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_KARMAHITBOX); // Player hitbox is too small!!
 | 
						|
				P_SetTarget(&karmahitbox->target, player->mo);
 | 
						|
				karmahitbox->destscale = player->mo->scale;
 | 
						|
				P_SetScale(karmahitbox, player->mo->scale);
 | 
						|
				CONS_Printf(M_GetText("%s lost all of their bumpers!\n"), player_names[player-players]);
 | 
						|
			}
 | 
						|
			player->kartstuff[k_bumper]--;
 | 
						|
			if (K_IsPlayerWanted(player))
 | 
						|
				K_CalculateBattleWanted();
 | 
						|
		}
 | 
						|
 | 
						|
		if (!player->kartstuff[k_bumper])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_comebacktimer] = comebacktime;
 | 
						|
			if (player->kartstuff[k_comebackmode] == 2)
 | 
						|
			{
 | 
						|
				mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE);
 | 
						|
				S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound);
 | 
						|
				player->kartstuff[k_comebackmode] = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		K_CheckBumpers();
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_spinouttype] = type;
 | 
						|
 | 
						|
	if (player->kartstuff[k_spinouttype] <= 0) // type 0 is spinout, type 1 is wipeout
 | 
						|
	{
 | 
						|
		// At spinout, player speed is increased to 1/4 their regular speed, moving them forward
 | 
						|
		if (player->speed < K_GetKartSpeed(player, true)/4)
 | 
						|
			P_InstaThrust(player->mo, player->mo->angle, FixedMul(K_GetKartSpeed(player, true)/4, player->mo->scale));
 | 
						|
		S_StartSound(player->mo, sfx_slip);
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_spinouttimer] = (3*TICRATE/2)+2;
 | 
						|
	player->powers[pw_flashing] = K_GetKartFlashing(player);
 | 
						|
 | 
						|
	if (player->mo->state != &states[S_KART_SPIN])
 | 
						|
		P_SetPlayerMobjState(player->mo, S_KART_SPIN);
 | 
						|
 | 
						|
	player->kartstuff[k_instashield] = 15;
 | 
						|
	if (cv_kartdebughuddrop.value && !modeattacking)
 | 
						|
		K_DropItems(player);
 | 
						|
	else
 | 
						|
		K_DropHnextList(player);
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
static void K_RemoveGrowShrink(player_t *player)
 | 
						|
{
 | 
						|
	player->kartstuff[k_growshrinktimer] = 0;
 | 
						|
	if (player->kartstuff[k_invincibilitytimer] == 0)
 | 
						|
		player->mo->color = player->skincolor;
 | 
						|
	player->mo->scalespeed = mapobjectscale/TICRATE;
 | 
						|
	player->mo->destscale = mapobjectscale;
 | 
						|
	if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
 | 
						|
		player->mo->destscale = (6*player->mo->destscale)/8;
 | 
						|
	P_RestoreMusic(player);
 | 
						|
}
 | 
						|
 | 
						|
void K_SquishPlayer(player_t *player, mobj_t *source, mobj_t *inflictor)
 | 
						|
{
 | 
						|
	UINT8 scoremultiply = 1;
 | 
						|
	// PS: Inflictor is unused for all purposes here and is actually only ever relevant to Lua. It may be nil too.
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
	boolean force = false;	// Used to check if Lua ShouldSquish should get us damaged reguardless of flashtics or heck knows what.
 | 
						|
	UINT8 shouldForce = LUAh_ShouldSquish(player, inflictor, source);
 | 
						|
	if (P_MobjWasRemoved(player->mo))
 | 
						|
		return; // mobj was removed (in theory that shouldn't happen)
 | 
						|
	if (shouldForce == 1)
 | 
						|
		force = true;
 | 
						|
	else if (shouldForce == 2)
 | 
						|
		return;
 | 
						|
#else
 | 
						|
	static const boolean force = false;
 | 
						|
	(void)inflictor;	// Please stop forgetting to put inflictor in yer functions thank -Lat'
 | 
						|
#endif
 | 
						|
 | 
						|
	if (G_BattleGametype())
 | 
						|
	{
 | 
						|
		if (K_IsPlayerWanted(player))
 | 
						|
			scoremultiply = 3;
 | 
						|
		else if (player->kartstuff[k_bumper] == 1)
 | 
						|
			scoremultiply = 2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->health <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_invincibilitytimer] > 0
 | 
						|
		|| player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0
 | 
						|
		|| (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1)))
 | 
						|
	{
 | 
						|
		if (!force)	// You know the drill by now.
 | 
						|
		{
 | 
						|
			K_DoInstashield(player);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (LUAh_PlayerSquish(player, inflictor, source))	// Let Lua do its thing or overwrite if it wants to. Make sure to let any possible instashield happen because we didn't get "damaged" in this case.
 | 
						|
		return;
 | 
						|
 | 
						|
	player->kartstuff[k_sneakertimer] = 0;
 | 
						|
	player->kartstuff[k_driftboost] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_drift] = 0;
 | 
						|
	player->kartstuff[k_driftcharge] = 0;
 | 
						|
	player->kartstuff[k_pogospring] = 0;
 | 
						|
 | 
						|
	if (G_BattleGametype())
 | 
						|
	{
 | 
						|
		if (source && source->player && player != source->player)
 | 
						|
		{
 | 
						|
			P_AddPlayerScore(source->player, scoremultiply);
 | 
						|
			K_SpawnBattlePoints(source->player, player, scoremultiply);
 | 
						|
			source->player->kartstuff[k_wanted] -= wantedreduce;
 | 
						|
			player->kartstuff[k_wanted] -= (wantedreduce/2);
 | 
						|
		}
 | 
						|
 | 
						|
		if (player->kartstuff[k_bumper] > 0)
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_bumper] == 1)
 | 
						|
			{
 | 
						|
				mobj_t *karmahitbox = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_KARMAHITBOX); // Player hitbox is too small!!
 | 
						|
				P_SetTarget(&karmahitbox->target, player->mo);
 | 
						|
				karmahitbox->destscale = player->mo->scale;
 | 
						|
				P_SetScale(karmahitbox, player->mo->scale);
 | 
						|
				CONS_Printf(M_GetText("%s lost all of their bumpers!\n"), player_names[player-players]);
 | 
						|
			}
 | 
						|
			player->kartstuff[k_bumper]--;
 | 
						|
			if (K_IsPlayerWanted(player))
 | 
						|
				K_CalculateBattleWanted();
 | 
						|
		}
 | 
						|
 | 
						|
		if (!player->kartstuff[k_bumper])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_comebacktimer] = comebacktime;
 | 
						|
			if (player->kartstuff[k_comebackmode] == 2)
 | 
						|
			{
 | 
						|
				mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE);
 | 
						|
				S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound);
 | 
						|
				player->kartstuff[k_comebackmode] = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		K_CheckBumpers();
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_squishedtimer] = TICRATE;
 | 
						|
 | 
						|
	// Reduce Shrink timer
 | 
						|
	if (player->kartstuff[k_growshrinktimer] < 0)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_growshrinktimer] += TICRATE;
 | 
						|
		if (player->kartstuff[k_growshrinktimer] >= 0)
 | 
						|
			K_RemoveGrowShrink(player);
 | 
						|
	}
 | 
						|
 | 
						|
	player->powers[pw_flashing] = K_GetKartFlashing(player);
 | 
						|
 | 
						|
	player->mo->flags |= MF_NOCLIP;
 | 
						|
 | 
						|
	if (player->mo->state != &states[S_KART_SQUISH]) // Squash
 | 
						|
		P_SetPlayerMobjState(player->mo, S_KART_SQUISH);
 | 
						|
 | 
						|
	P_PlayRinglossSound(player->mo);
 | 
						|
 | 
						|
	player->kartstuff[k_instashield] = 15;
 | 
						|
	if (cv_kartdebughuddrop.value && !modeattacking)
 | 
						|
		K_DropItems(player);
 | 
						|
	else
 | 
						|
		K_DropHnextList(player);
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A bit of a hack, we just throw the player up higher here and extend their spinout timer
 | 
						|
{
 | 
						|
	UINT8 scoremultiply = 1;
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
	boolean force = false;	// Used to check if Lua ShouldExplode should get us damaged reguardless of flashtics or heck knows what.
 | 
						|
	UINT8 shouldForce = LUAh_ShouldExplode(player, inflictor, source);
 | 
						|
	if (P_MobjWasRemoved(player->mo))
 | 
						|
		return; // mobj was removed (in theory that shouldn't happen)
 | 
						|
	if (shouldForce == 1)
 | 
						|
		force = true;
 | 
						|
	else if (shouldForce == 2)
 | 
						|
		return;
 | 
						|
 | 
						|
#else
 | 
						|
	static const boolean force = false;
 | 
						|
#endif
 | 
						|
	if (G_BattleGametype())
 | 
						|
	{
 | 
						|
		if (K_IsPlayerWanted(player))
 | 
						|
			scoremultiply = 3;
 | 
						|
		else if (player->kartstuff[k_bumper] == 1)
 | 
						|
			scoremultiply = 2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->health <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (/*player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0 // Explosions should combo, because of SPB and Eggman
 | 
						|
		||*/player->kartstuff[k_invincibilitytimer] > 0 || player->kartstuff[k_growshrinktimer] > 0 || player->kartstuff[k_hyudorotimer] > 0
 | 
						|
		|| (G_BattleGametype() && ((player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]) || player->kartstuff[k_comebackmode] == 1)))
 | 
						|
	{
 | 
						|
		if (!force)	// ShouldDamage can bypass that, again.
 | 
						|
		{
 | 
						|
			K_DoInstashield(player);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (LUAh_PlayerExplode(player, inflictor, source))	// Same thing. Also make sure to let Instashield happen blah blah
 | 
						|
		return;
 | 
						|
 | 
						|
	if (source && source != player->mo && source->player)
 | 
						|
		K_PlayHitEmSound(source);
 | 
						|
 | 
						|
	player->mo->momz = 18*mapobjectscale;
 | 
						|
	player->mo->momx = player->mo->momy = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_sneakertimer] = 0;
 | 
						|
	player->kartstuff[k_driftboost] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_drift] = 0;
 | 
						|
	player->kartstuff[k_driftcharge] = 0;
 | 
						|
	player->kartstuff[k_pogospring] = 0;
 | 
						|
 | 
						|
	// This is the only part that SHOULDN'T combo :VVVVV
 | 
						|
	if (G_BattleGametype() && !(player->powers[pw_flashing] > 0 || player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0))
 | 
						|
	{
 | 
						|
		if (source && source->player && player != source->player)
 | 
						|
		{
 | 
						|
			P_AddPlayerScore(source->player, scoremultiply);
 | 
						|
			K_SpawnBattlePoints(source->player, player, scoremultiply);
 | 
						|
			source->player->kartstuff[k_wanted] -= wantedreduce;
 | 
						|
			player->kartstuff[k_wanted] -= (wantedreduce/2);
 | 
						|
		}
 | 
						|
 | 
						|
		if (player->kartstuff[k_bumper] > 0)
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_bumper] == 1)
 | 
						|
			{
 | 
						|
				mobj_t *karmahitbox = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_KARMAHITBOX); // Player hitbox is too small!!
 | 
						|
				P_SetTarget(&karmahitbox->target, player->mo);
 | 
						|
				karmahitbox->destscale = player->mo->scale;
 | 
						|
				P_SetScale(karmahitbox, player->mo->scale);
 | 
						|
				CONS_Printf(M_GetText("%s lost all of their bumpers!\n"), player_names[player-players]);
 | 
						|
			}
 | 
						|
			player->kartstuff[k_bumper]--;
 | 
						|
			if (K_IsPlayerWanted(player))
 | 
						|
				K_CalculateBattleWanted();
 | 
						|
		}
 | 
						|
 | 
						|
		if (!player->kartstuff[k_bumper])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_comebacktimer] = comebacktime;
 | 
						|
			if (player->kartstuff[k_comebackmode] == 2)
 | 
						|
			{
 | 
						|
				mobj_t *poof = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EXPLODE);
 | 
						|
				S_StartSound(poof, mobjinfo[MT_KARMAHITBOX].seesound);
 | 
						|
				player->kartstuff[k_comebackmode] = 0;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		K_CheckBumpers();
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_spinouttype] = 1;
 | 
						|
	player->kartstuff[k_spinouttimer] = 2*TICRATE+(TICRATE/2);
 | 
						|
 | 
						|
	player->powers[pw_flashing] = K_GetKartFlashing(player);
 | 
						|
 | 
						|
	if (inflictor && inflictor->type == MT_SPBEXPLOSION && inflictor->extravalue1)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_spinouttimer] = ((3*player->kartstuff[k_spinouttimer])/2)+1;
 | 
						|
		player->mo->momz *= 2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->mo->state != &states[S_KART_SPIN])
 | 
						|
		P_SetPlayerMobjState(player->mo, S_KART_SPIN);
 | 
						|
 | 
						|
	P_PlayRinglossSound(player->mo);
 | 
						|
 | 
						|
	if (P_IsLocalPlayer(player))
 | 
						|
	{
 | 
						|
		quake.intensity = 64*FRACUNIT;
 | 
						|
		quake.time = 5;
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_instashield] = 15;
 | 
						|
	K_DropItems(player);
 | 
						|
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
void K_StealBumper(player_t *player, player_t *victim, boolean force)
 | 
						|
{
 | 
						|
	INT32 newbumper;
 | 
						|
	angle_t newangle, diff;
 | 
						|
	fixed_t newx, newy;
 | 
						|
	mobj_t *newmo;
 | 
						|
 | 
						|
	if (!G_BattleGametype())
 | 
						|
		return;
 | 
						|
 | 
						|
	if (player->health <= 0 || victim->health <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!force)
 | 
						|
	{
 | 
						|
		if (victim->kartstuff[k_bumper] <= 0) // || player->kartstuff[k_bumper] >= cv_kartbumpers.value+2
 | 
						|
			return;
 | 
						|
 | 
						|
		if (player->kartstuff[k_squishedtimer] > 0 || player->kartstuff[k_spinouttimer] > 0)
 | 
						|
			return;
 | 
						|
 | 
						|
		if (victim->powers[pw_flashing] > 0 || victim->kartstuff[k_squishedtimer] > 0 || victim->kartstuff[k_spinouttimer] > 0
 | 
						|
			|| victim->kartstuff[k_invincibilitytimer] > 0 || victim->kartstuff[k_growshrinktimer] > 0 || victim->kartstuff[k_hyudorotimer] > 0)
 | 
						|
		{
 | 
						|
			K_DoInstashield(victim);
 | 
						|
			return;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (netgame && player->kartstuff[k_bumper] <= 0)
 | 
						|
		CONS_Printf(M_GetText("%s is back in the game!\n"), player_names[player-players]);
 | 
						|
 | 
						|
	newbumper = player->kartstuff[k_bumper];
 | 
						|
	if (newbumper <= 1)
 | 
						|
		diff = 0;
 | 
						|
	else
 | 
						|
		diff = FixedAngle(360*FRACUNIT/newbumper);
 | 
						|
 | 
						|
	newangle = player->mo->angle;
 | 
						|
	newx = player->mo->x + P_ReturnThrustX(player->mo, newangle + ANGLE_180, 64*FRACUNIT);
 | 
						|
	newy = player->mo->y + P_ReturnThrustY(player->mo, newangle + ANGLE_180, 64*FRACUNIT);
 | 
						|
 | 
						|
	newmo = P_SpawnMobj(newx, newy, player->mo->z, MT_BATTLEBUMPER);
 | 
						|
	newmo->threshold = newbumper;
 | 
						|
	P_SetTarget(&newmo->tracer, victim->mo);
 | 
						|
	P_SetTarget(&newmo->target, player->mo);
 | 
						|
	newmo->angle = (diff * (newbumper-1));
 | 
						|
	newmo->color = victim->skincolor;
 | 
						|
 | 
						|
	if (newbumper+1 < 2)
 | 
						|
		P_SetMobjState(newmo, S_BATTLEBUMPER3);
 | 
						|
	else if (newbumper+1 < 3)
 | 
						|
		P_SetMobjState(newmo, S_BATTLEBUMPER2);
 | 
						|
	else
 | 
						|
		P_SetMobjState(newmo, S_BATTLEBUMPER1);
 | 
						|
 | 
						|
	S_StartSound(player->mo, sfx_3db06);
 | 
						|
 | 
						|
	player->kartstuff[k_bumper]++;
 | 
						|
	player->kartstuff[k_comebackpoints] = 0;
 | 
						|
	player->powers[pw_flashing] = K_GetKartFlashing(player);
 | 
						|
	player->kartstuff[k_comebacktimer] = comebacktime;
 | 
						|
 | 
						|
	/*victim->powers[pw_flashing] = K_GetKartFlashing(victim);
 | 
						|
	victim->kartstuff[k_comebacktimer] = comebacktime;*/
 | 
						|
 | 
						|
	victim->kartstuff[k_instashield] = 15;
 | 
						|
	if (cv_kartdebughuddrop.value && !modeattacking)
 | 
						|
		K_DropItems(victim);
 | 
						|
	else
 | 
						|
		K_DropHnextList(victim);
 | 
						|
	return;
 | 
						|
}
 | 
						|
 | 
						|
// source is the mobj that originally threw the bomb that exploded etc.
 | 
						|
// Spawns the sphere around the explosion that handles spinout
 | 
						|
void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 number, mobjtype_t type, angle_t rotangle, boolean spawncenter, boolean ghostit, mobj_t *source)
 | 
						|
{
 | 
						|
	mobj_t *mobj;
 | 
						|
	mobj_t *ghost = NULL;
 | 
						|
	INT32 i;
 | 
						|
	TVector v;
 | 
						|
	TVector *res;
 | 
						|
	fixed_t finalx, finaly, finalz, dist;
 | 
						|
	//mobj_t hoopcenter;
 | 
						|
	angle_t degrees, fa, closestangle;
 | 
						|
	fixed_t mobjx, mobjy, mobjz;
 | 
						|
 | 
						|
	//hoopcenter.x = x;
 | 
						|
	//hoopcenter.y = y;
 | 
						|
	//hoopcenter.z = z;
 | 
						|
 | 
						|
	//hoopcenter.z = z - mobjinfo[type].height/2;
 | 
						|
 | 
						|
	degrees = FINEANGLES/number;
 | 
						|
 | 
						|
	closestangle = 0;
 | 
						|
 | 
						|
	// Create the hoop!
 | 
						|
	for (i = 0; i < number; i++)
 | 
						|
	{
 | 
						|
		fa = (i*degrees);
 | 
						|
		v[0] = FixedMul(FINECOSINE(fa),radius);
 | 
						|
		v[1] = 0;
 | 
						|
		v[2] = FixedMul(FINESINE(fa),radius);
 | 
						|
		v[3] = FRACUNIT;
 | 
						|
 | 
						|
		res = VectorMatrixMultiply(v, *RotateXMatrix(rotangle));
 | 
						|
		M_Memcpy(&v, res, sizeof (v));
 | 
						|
		res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
 | 
						|
		M_Memcpy(&v, res, sizeof (v));
 | 
						|
 | 
						|
		finalx = x + v[0];
 | 
						|
		finaly = y + v[1];
 | 
						|
		finalz = z + v[2];
 | 
						|
 | 
						|
		mobj = P_SpawnMobj(finalx, finaly, finalz, type);
 | 
						|
 | 
						|
		mobj->z -= mobj->height>>1;
 | 
						|
 | 
						|
		// change angle
 | 
						|
		mobj->angle = R_PointToAngle2(mobj->x, mobj->y, x, y);
 | 
						|
 | 
						|
		// change slope
 | 
						|
		dist = P_AproxDistance(P_AproxDistance(x - mobj->x, y - mobj->y), z - mobj->z);
 | 
						|
 | 
						|
		if (dist < 1)
 | 
						|
			dist = 1;
 | 
						|
 | 
						|
		mobjx = mobj->x;
 | 
						|
		mobjy = mobj->y;
 | 
						|
		mobjz = mobj->z;
 | 
						|
 | 
						|
		if (ghostit)
 | 
						|
		{
 | 
						|
			ghost = P_SpawnGhostMobj(mobj);
 | 
						|
			P_SetMobjState(mobj, S_NULL);
 | 
						|
			mobj = ghost;
 | 
						|
		}
 | 
						|
 | 
						|
		if (spawncenter)
 | 
						|
		{
 | 
						|
			mobj->x = x;
 | 
						|
			mobj->y = y;
 | 
						|
			mobj->z = z;
 | 
						|
		}
 | 
						|
 | 
						|
		mobj->momx = FixedMul(FixedDiv(mobjx - x, dist), FixedDiv(dist, 6*FRACUNIT));
 | 
						|
		mobj->momy = FixedMul(FixedDiv(mobjy - y, dist), FixedDiv(dist, 6*FRACUNIT));
 | 
						|
		mobj->momz = FixedMul(FixedDiv(mobjz - z, dist), FixedDiv(dist, 6*FRACUNIT));
 | 
						|
 | 
						|
		if (source && !P_MobjWasRemoved(source))
 | 
						|
			P_SetTarget(&mobj->target, source);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Spawns the purely visual explosion
 | 
						|
void K_SpawnMineExplosion(mobj_t *source, UINT8 color)
 | 
						|
{
 | 
						|
	INT32 i, radius, height;
 | 
						|
	mobj_t *smoldering = P_SpawnMobj(source->x, source->y, source->z, MT_SMOLDERING);
 | 
						|
	mobj_t *dust;
 | 
						|
	mobj_t *truc;
 | 
						|
	INT32 speed, speed2;
 | 
						|
 | 
						|
	smoldering->tics = TICRATE*3;
 | 
						|
	radius = source->radius>>FRACBITS;
 | 
						|
	height = source->height>>FRACBITS;
 | 
						|
 | 
						|
	if (!color)
 | 
						|
		color = SKINCOLOR_KETCHUP;
 | 
						|
 | 
						|
	for (i = 0; i < 32; i++)
 | 
						|
	{
 | 
						|
		dust = P_SpawnMobj(source->x, source->y, source->z, MT_SMOKE);
 | 
						|
		dust->angle = (ANGLE_180/16) * i;
 | 
						|
		P_SetScale(dust, source->scale);
 | 
						|
		dust->destscale = source->scale*10;
 | 
						|
		dust->scalespeed = source->scale/12;
 | 
						|
		P_InstaThrust(dust, dust->angle, FixedMul(20*FRACUNIT, source->scale));
 | 
						|
 | 
						|
		truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT,
 | 
						|
			source->y + P_RandomRange(-radius, radius)*FRACUNIT,
 | 
						|
			source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMEXPLODE);
 | 
						|
		P_SetScale(truc, source->scale);
 | 
						|
		truc->destscale = source->scale*6;
 | 
						|
		truc->scalespeed = source->scale/12;
 | 
						|
		speed = FixedMul(10*FRACUNIT, source->scale)>>FRACBITS;
 | 
						|
		truc->momx = P_RandomRange(-speed, speed)*FRACUNIT;
 | 
						|
		truc->momy = P_RandomRange(-speed, speed)*FRACUNIT;
 | 
						|
		speed = FixedMul(20*FRACUNIT, source->scale)>>FRACBITS;
 | 
						|
		truc->momz = P_RandomRange(-speed, speed)*FRACUNIT;
 | 
						|
		truc->color = color;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < 16; i++)
 | 
						|
	{
 | 
						|
		dust = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT,
 | 
						|
			source->y + P_RandomRange(-radius, radius)*FRACUNIT,
 | 
						|
			source->z + P_RandomRange(0, height)*FRACUNIT, MT_SMOKE);
 | 
						|
		P_SetScale(dust, source->scale);
 | 
						|
		dust->destscale = source->scale*10;
 | 
						|
		dust->scalespeed = source->scale/12;
 | 
						|
		dust->tics = 30;
 | 
						|
		dust->momz = P_RandomRange(FixedMul(3*FRACUNIT, source->scale)>>FRACBITS, FixedMul(7*FRACUNIT, source->scale)>>FRACBITS)*FRACUNIT;
 | 
						|
 | 
						|
		truc = P_SpawnMobj(source->x + P_RandomRange(-radius, radius)*FRACUNIT,
 | 
						|
			source->y + P_RandomRange(-radius, radius)*FRACUNIT,
 | 
						|
			source->z + P_RandomRange(0, height)*FRACUNIT, MT_BOOMPARTICLE);
 | 
						|
		P_SetScale(truc, source->scale);
 | 
						|
		truc->destscale = source->scale*5;
 | 
						|
		truc->scalespeed = source->scale/12;
 | 
						|
		speed = FixedMul(20*FRACUNIT, source->scale)>>FRACBITS;
 | 
						|
		truc->momx = P_RandomRange(-speed, speed)*FRACUNIT;
 | 
						|
		truc->momy = P_RandomRange(-speed, speed)*FRACUNIT;
 | 
						|
		speed = FixedMul(15*FRACUNIT, source->scale)>>FRACBITS;
 | 
						|
		speed2 = FixedMul(45*FRACUNIT, source->scale)>>FRACBITS;
 | 
						|
		truc->momz = P_RandomRange(speed, speed2)*FRACUNIT;
 | 
						|
		if (P_RandomChance(FRACUNIT/2))
 | 
						|
			truc->momz = -truc->momz;
 | 
						|
		truc->tics = TICRATE*2;
 | 
						|
		truc->color = color;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed)
 | 
						|
{
 | 
						|
	mobj_t *th;
 | 
						|
	fixed_t x, y, z;
 | 
						|
	fixed_t finalspeed = speed;
 | 
						|
	mobj_t *throwmo;
 | 
						|
 | 
						|
	if (source->player && source->player->speed > K_GetKartSpeed(source->player, false))
 | 
						|
	{
 | 
						|
		angle_t input = source->angle - an;
 | 
						|
		boolean invert = (input > ANGLE_180);
 | 
						|
		if (invert)
 | 
						|
			input = InvAngle(input);
 | 
						|
 | 
						|
		finalspeed = max(speed, FixedMul(speed, FixedMul(
 | 
						|
			FixedDiv(source->player->speed, K_GetKartSpeed(source->player, false)), // Multiply speed to be proportional to your own, boosted maxspeed.
 | 
						|
			(((180<<FRACBITS) - AngleFixed(input)) / 180) // multiply speed based on angle diff... i.e: don't do this for firing backward :V
 | 
						|
			)));
 | 
						|
	}
 | 
						|
 | 
						|
	x = source->x + source->momx + FixedMul(finalspeed, FINECOSINE(an>>ANGLETOFINESHIFT));
 | 
						|
	y = source->y + source->momy + FixedMul(finalspeed, FINESINE(an>>ANGLETOFINESHIFT));
 | 
						|
	z = source->z; // spawn on the ground please
 | 
						|
 | 
						|
	if (P_MobjFlip(source) < 0)
 | 
						|
	{
 | 
						|
		z = source->z+source->height - mobjinfo[type].height;
 | 
						|
	}
 | 
						|
 | 
						|
	th = P_SpawnMobj(x, y, z, type);
 | 
						|
 | 
						|
	th->flags2 |= flags2;
 | 
						|
 | 
						|
	th->threshold = 10;
 | 
						|
 | 
						|
	if (th->info->seesound)
 | 
						|
		S_StartSound(source, th->info->seesound);
 | 
						|
 | 
						|
	P_SetTarget(&th->target, source);
 | 
						|
 | 
						|
	if (P_IsObjectOnGround(source))
 | 
						|
	{
 | 
						|
		// floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn
 | 
						|
		// This should set it for FOFs
 | 
						|
		P_TeleportMove(th, th->x, th->y, th->z);
 | 
						|
		// spawn on the ground if the player is on the ground
 | 
						|
		if (P_MobjFlip(source) < 0)
 | 
						|
		{
 | 
						|
			th->z = th->ceilingz - th->height;
 | 
						|
			th->eflags |= MFE_VERTICALFLIP;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			th->z = th->floorz;
 | 
						|
	}
 | 
						|
 | 
						|
	th->angle = an;
 | 
						|
	th->momx = FixedMul(finalspeed, FINECOSINE(an>>ANGLETOFINESHIFT));
 | 
						|
	th->momy = FixedMul(finalspeed, FINESINE(an>>ANGLETOFINESHIFT));
 | 
						|
 | 
						|
	switch (type)
 | 
						|
	{
 | 
						|
		case MT_ORBINAUT:
 | 
						|
			if (source && source->player)
 | 
						|
				th->color = source->player->skincolor;
 | 
						|
			else
 | 
						|
				th->color = SKINCOLOR_GREY;
 | 
						|
			th->movefactor = finalspeed;
 | 
						|
			break;
 | 
						|
		case MT_JAWZ:
 | 
						|
			if (source && source->player)
 | 
						|
				th->cvmem = source->player->skincolor;
 | 
						|
			else
 | 
						|
				th->cvmem = SKINCOLOR_KETCHUP;
 | 
						|
			/* FALLTHRU */
 | 
						|
		case MT_JAWZ_DUD:
 | 
						|
			S_StartSound(th, th->info->activesound);
 | 
						|
			/* FALLTHRU */
 | 
						|
		case MT_SPB:
 | 
						|
			th->movefactor = finalspeed;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	x = x + P_ReturnThrustX(source, an, source->radius + th->radius);
 | 
						|
	y = y + P_ReturnThrustY(source, an, source->radius + th->radius);
 | 
						|
	throwmo = P_SpawnMobj(x, y, z, MT_FIREDITEM);
 | 
						|
	throwmo->movecount = 1;
 | 
						|
	throwmo->movedir = source->angle - an;
 | 
						|
	P_SetTarget(&throwmo->target, source);
 | 
						|
 | 
						|
	return NULL;
 | 
						|
}
 | 
						|
 | 
						|
static void K_SpawnDriftSparks(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t newx;
 | 
						|
	fixed_t newy;
 | 
						|
	mobj_t *spark;
 | 
						|
	angle_t travelangle;
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	I_Assert(player != NULL);
 | 
						|
	I_Assert(player->mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(player->mo));
 | 
						|
 | 
						|
	if (leveltime % 2 == 1)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!P_IsObjectOnGround(player->mo))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!player->kartstuff[k_drift] || player->kartstuff[k_driftcharge] < K_GetKartDriftSparkValue(player))
 | 
						|
		return;
 | 
						|
 | 
						|
	travelangle = player->mo->angle-(ANGLE_45/5)*player->kartstuff[k_drift];
 | 
						|
 | 
						|
	for (i = 0; i < 2; i++)
 | 
						|
	{
 | 
						|
		newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale));
 | 
						|
		newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(32*FRACUNIT, player->mo->scale));
 | 
						|
		spark = P_SpawnMobj(newx, newy, player->mo->z, MT_DRIFTSPARK);
 | 
						|
 | 
						|
		P_SetTarget(&spark->target, player->mo);
 | 
						|
		spark->angle = travelangle-(ANGLE_45/5)*player->kartstuff[k_drift];
 | 
						|
		spark->destscale = player->mo->scale;
 | 
						|
		P_SetScale(spark, player->mo->scale);
 | 
						|
 | 
						|
		spark->momx = player->mo->momx/2;
 | 
						|
		spark->momy = player->mo->momy/2;
 | 
						|
		//spark->momz = player->mo->momz/2;
 | 
						|
 | 
						|
		if (player->kartstuff[k_driftcharge] >= K_GetKartDriftSparkValue(player)*4)
 | 
						|
		{
 | 
						|
			spark->color = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1)));
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_driftcharge] >= K_GetKartDriftSparkValue(player)*2)
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_driftcharge] <= (K_GetKartDriftSparkValue(player)*2)+(24*3))
 | 
						|
				spark->color = SKINCOLOR_RASPBERRY; // transition
 | 
						|
			else
 | 
						|
				spark->color = SKINCOLOR_KETCHUP;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			spark->color = SKINCOLOR_SAPPHIRE;
 | 
						|
		}
 | 
						|
 | 
						|
		if ((player->kartstuff[k_drift] > 0 && player->cmd.driftturn > 0) // Inward drifts
 | 
						|
			|| (player->kartstuff[k_drift] < 0 && player->cmd.driftturn < 0))
 | 
						|
		{
 | 
						|
			if ((player->kartstuff[k_drift] < 0 && (i & 1))
 | 
						|
				|| (player->kartstuff[k_drift] > 0 && !(i & 1)))
 | 
						|
				P_SetMobjState(spark, S_DRIFTSPARK_A1);
 | 
						|
			else if ((player->kartstuff[k_drift] < 0 && !(i & 1))
 | 
						|
				|| (player->kartstuff[k_drift] > 0 && (i & 1)))
 | 
						|
				P_SetMobjState(spark, S_DRIFTSPARK_C1);
 | 
						|
		}
 | 
						|
		else if ((player->kartstuff[k_drift] > 0 && player->cmd.driftturn < 0) // Outward drifts
 | 
						|
			|| (player->kartstuff[k_drift] < 0 && player->cmd.driftturn > 0))
 | 
						|
		{
 | 
						|
			if ((player->kartstuff[k_drift] < 0 && (i & 1))
 | 
						|
				|| (player->kartstuff[k_drift] > 0 && !(i & 1)))
 | 
						|
				P_SetMobjState(spark, S_DRIFTSPARK_C1);
 | 
						|
			else if ((player->kartstuff[k_drift] < 0 && !(i & 1))
 | 
						|
				|| (player->kartstuff[k_drift] > 0 && (i & 1)))
 | 
						|
				P_SetMobjState(spark, S_DRIFTSPARK_A1);
 | 
						|
		}
 | 
						|
 | 
						|
		K_MatchGenericExtraFlags(spark, player->mo);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_SpawnAIZDust(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t newx;
 | 
						|
	fixed_t newy;
 | 
						|
	mobj_t *spark;
 | 
						|
	angle_t travelangle;
 | 
						|
 | 
						|
	I_Assert(player != NULL);
 | 
						|
	I_Assert(player->mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(player->mo));
 | 
						|
 | 
						|
	if (leveltime % 2 == 1)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!P_IsObjectOnGround(player->mo))
 | 
						|
		return;
 | 
						|
 | 
						|
	travelangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
 | 
						|
	//S_StartSound(player->mo, sfx_s3k47);
 | 
						|
 | 
						|
	{
 | 
						|
		newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle - (player->kartstuff[k_aizdriftstrat]*ANGLE_45), FixedMul(24*FRACUNIT, player->mo->scale));
 | 
						|
		newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle - (player->kartstuff[k_aizdriftstrat]*ANGLE_45), FixedMul(24*FRACUNIT, player->mo->scale));
 | 
						|
		spark = P_SpawnMobj(newx, newy, player->mo->z, MT_AIZDRIFTSTRAT);
 | 
						|
 | 
						|
		spark->angle = travelangle+(player->kartstuff[k_aizdriftstrat]*ANGLE_90);
 | 
						|
		P_SetScale(spark, (spark->destscale = (3*player->mo->scale)>>2));
 | 
						|
 | 
						|
		spark->momx = (6*player->mo->momx)/5;
 | 
						|
		spark->momy = (6*player->mo->momy)/5;
 | 
						|
		//spark->momz = player->mo->momz/2;
 | 
						|
 | 
						|
		K_MatchGenericExtraFlags(spark, player->mo);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void K_SpawnBoostTrail(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t newx;
 | 
						|
	fixed_t newy;
 | 
						|
	fixed_t ground;
 | 
						|
	mobj_t *flame;
 | 
						|
	angle_t travelangle;
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	I_Assert(player != NULL);
 | 
						|
	I_Assert(player->mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(player->mo));
 | 
						|
 | 
						|
	if (!P_IsObjectOnGround(player->mo)
 | 
						|
		|| player->kartstuff[k_hyudorotimer] != 0
 | 
						|
		|| (G_BattleGametype() && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer]))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
		ground = player->mo->ceilingz - FixedMul(mobjinfo[MT_SNEAKERTRAIL].height, player->mo->scale);
 | 
						|
	else
 | 
						|
		ground = player->mo->floorz;
 | 
						|
 | 
						|
	if (player->kartstuff[k_drift] != 0)
 | 
						|
		travelangle = player->mo->angle;
 | 
						|
	else
 | 
						|
		travelangle = R_PointToAngle2(0, 0, player->rmomx, player->rmomy);
 | 
						|
 | 
						|
	for (i = 0; i < 2; i++)
 | 
						|
	{
 | 
						|
		newx = player->mo->x + P_ReturnThrustX(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale));
 | 
						|
		newy = player->mo->y + P_ReturnThrustY(player->mo, travelangle + ((i&1) ? -1 : 1)*ANGLE_135, FixedMul(24*FRACUNIT, player->mo->scale));
 | 
						|
#ifdef ESLOPE
 | 
						|
		if (player->mo->standingslope)
 | 
						|
		{
 | 
						|
			ground = P_GetZAt(player->mo->standingslope, newx, newy);
 | 
						|
			if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
				ground -= FixedMul(mobjinfo[MT_SNEAKERTRAIL].height, player->mo->scale);
 | 
						|
		}
 | 
						|
#endif
 | 
						|
		flame = P_SpawnMobj(newx, newy, ground, MT_SNEAKERTRAIL);
 | 
						|
 | 
						|
		P_SetTarget(&flame->target, player->mo);
 | 
						|
		flame->angle = travelangle;
 | 
						|
		flame->fuse = TICRATE*2;
 | 
						|
		flame->destscale = player->mo->scale;
 | 
						|
		P_SetScale(flame, player->mo->scale);
 | 
						|
		flame->eflags = (flame->eflags & ~MFE_VERTICALFLIP)|(player->mo->eflags & MFE_VERTICALFLIP); // not K_MatchGenericExtraFlags so that a stolen sneaker can be seen
 | 
						|
 | 
						|
		flame->momx = 8;
 | 
						|
		P_XYMovement(flame);
 | 
						|
		if (P_MobjWasRemoved(flame))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
		{
 | 
						|
			if (flame->z + flame->height < flame->ceilingz)
 | 
						|
				P_RemoveMobj(flame);
 | 
						|
		}
 | 
						|
		else if (flame->z > flame->floorz)
 | 
						|
			P_RemoveMobj(flame);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void K_SpawnSparkleTrail(mobj_t *mo)
 | 
						|
{
 | 
						|
	const INT32 rad = (mo->radius*2)>>FRACBITS;
 | 
						|
	mobj_t *sparkle;
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	I_Assert(mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(mo));
 | 
						|
 | 
						|
	for (i = 0; i < 3; i++)
 | 
						|
	{
 | 
						|
		fixed_t newx = mo->x + mo->momx + (P_RandomRange(-rad, rad)<<FRACBITS);
 | 
						|
		fixed_t newy = mo->y + mo->momy + (P_RandomRange(-rad, rad)<<FRACBITS);
 | 
						|
		fixed_t newz = mo->z + mo->momz + (P_RandomRange(0, mo->height>>FRACBITS)<<FRACBITS);
 | 
						|
 | 
						|
		sparkle = P_SpawnMobj(newx, newy, newz, MT_SPARKLETRAIL);
 | 
						|
 | 
						|
		//if (i == 0)
 | 
						|
			//P_SetMobjState(sparkle, S_KARTINVULN_LARGE1);
 | 
						|
 | 
						|
		P_SetTarget(&sparkle->target, mo);
 | 
						|
		sparkle->destscale = mo->destscale;
 | 
						|
		P_SetScale(sparkle, mo->scale);
 | 
						|
		sparkle->eflags = (sparkle->eflags & ~MFE_VERTICALFLIP)|(mo->eflags & MFE_VERTICALFLIP); // not K_MatchGenericExtraFlags so that a stolen invincibility can be seen
 | 
						|
		sparkle->color = mo->color;
 | 
						|
		//sparkle->colorized = mo->colorized;
 | 
						|
	}
 | 
						|
 | 
						|
	P_SetMobjState(sparkle, S_KARTINVULN_LARGE1);
 | 
						|
}
 | 
						|
 | 
						|
void K_SpawnWipeoutTrail(mobj_t *mo, boolean translucent)
 | 
						|
{
 | 
						|
	mobj_t *dust;
 | 
						|
 | 
						|
	I_Assert(mo != NULL);
 | 
						|
	I_Assert(!P_MobjWasRemoved(mo));
 | 
						|
 | 
						|
	dust = P_SpawnMobj(mo->x + (P_RandomRange(-25,25) * mo->scale), mo->y + (P_RandomRange(-25,25) * mo->scale), mo->z, MT_WIPEOUTTRAIL);
 | 
						|
 | 
						|
	P_SetTarget(&dust->target, mo);
 | 
						|
	dust->angle = R_PointToAngle2(0,0,mo->momx,mo->momy);
 | 
						|
	dust->destscale = mo->scale;
 | 
						|
	P_SetScale(dust, mo->scale);
 | 
						|
	dust->eflags = (dust->eflags & ~MFE_VERTICALFLIP)|(mo->eflags & MFE_VERTICALFLIP); // not K_MatchGenericExtraFlags because hyudoro shouldn't be able to wipeout
 | 
						|
 | 
						|
	if (translucent) // offroad effect
 | 
						|
	{
 | 
						|
		dust->momx = mo->momx/2;
 | 
						|
		dust->momy = mo->momy/2;
 | 
						|
		dust->momz = mo->momz/2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (translucent)
 | 
						|
		dust->flags2 |= MF2_SHADOW;
 | 
						|
}
 | 
						|
 | 
						|
//	K_DriftDustHandling
 | 
						|
//	Parameters:
 | 
						|
//		spawner: The map object that is spawning the drift dust
 | 
						|
//	Description: Spawns the drift dust for objects, players use rmomx/y, other objects use regular momx/y.
 | 
						|
//		Also plays the drift sound.
 | 
						|
//		Other objects should be angled towards where they're trying to go so they don't randomly spawn dust
 | 
						|
//		Do note that most of the function won't run in odd intervals of frames
 | 
						|
void K_DriftDustHandling(mobj_t *spawner)
 | 
						|
{
 | 
						|
	angle_t anglediff;
 | 
						|
	const INT16 spawnrange = spawner->radius>>FRACBITS;
 | 
						|
 | 
						|
	if (!P_IsObjectOnGround(spawner) || leveltime % 2 != 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (spawner->player)
 | 
						|
	{
 | 
						|
		if (spawner->player->pflags & PF_SKIDDOWN)
 | 
						|
		{
 | 
						|
			anglediff = abs((signed)(spawner->angle - spawner->player->frameangle));
 | 
						|
			if (leveltime % 6 == 0)
 | 
						|
				S_StartSound(spawner, sfx_screec); // repeated here because it doesn't always happen to be within the range when this is the case
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			angle_t playerangle = spawner->angle;
 | 
						|
 | 
						|
			if (spawner->player->speed < 5<<FRACBITS)
 | 
						|
				return;
 | 
						|
 | 
						|
			if (spawner->player->cmd.forwardmove < 0)
 | 
						|
				playerangle += ANGLE_180;
 | 
						|
 | 
						|
			anglediff = abs((signed)(playerangle - R_PointToAngle2(0, 0, spawner->player->rmomx, spawner->player->rmomy)));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (P_AproxDistance(spawner->momx, spawner->momy) < 5<<FRACBITS)
 | 
						|
			return;
 | 
						|
 | 
						|
		anglediff = abs((signed)(spawner->angle - R_PointToAngle2(0, 0, spawner->momx, spawner->momy)));
 | 
						|
	}
 | 
						|
 | 
						|
	if (anglediff > ANGLE_180)
 | 
						|
		anglediff = InvAngle(anglediff);
 | 
						|
 | 
						|
	if (anglediff > ANG10*4) // Trying to turn further than 40 degrees
 | 
						|
	{
 | 
						|
		fixed_t spawnx = P_RandomRange(-spawnrange, spawnrange)<<FRACBITS;
 | 
						|
		fixed_t spawny = P_RandomRange(-spawnrange, spawnrange)<<FRACBITS;
 | 
						|
		INT32 speedrange = 2;
 | 
						|
		mobj_t *dust = P_SpawnMobj(spawner->x + spawnx, spawner->y + spawny, spawner->z, MT_DRIFTDUST);
 | 
						|
		if (spawner->eflags & MFE_VERTICALFLIP)
 | 
						|
		{
 | 
						|
			dust->z += spawner->height - dust->height;
 | 
						|
		}
 | 
						|
		dust->momx = FixedMul(spawner->momx + (P_RandomRange(-speedrange, speedrange)<<FRACBITS), 3*(spawner->scale)/4);
 | 
						|
		dust->momy = FixedMul(spawner->momy + (P_RandomRange(-speedrange, speedrange)<<FRACBITS), 3*(spawner->scale)/4);
 | 
						|
		dust->momz = P_MobjFlip(spawner) * (P_RandomRange(1, 4) * (spawner->scale));
 | 
						|
		P_SetScale(dust, spawner->scale/2);
 | 
						|
		dust->destscale = spawner->scale * 3;
 | 
						|
		dust->scalespeed = spawner->scale/12;
 | 
						|
 | 
						|
		if (leveltime % 6 == 0)
 | 
						|
			S_StartSound(spawner, sfx_screec);
 | 
						|
 | 
						|
		K_MatchGenericExtraFlags(dust, spawner);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static mobj_t *K_FindLastTrailMobj(player_t *player)
 | 
						|
{
 | 
						|
	mobj_t *trail;
 | 
						|
 | 
						|
	if (!player || !(trail = player->mo) || !player->mo->hnext || !player->mo->hnext->health)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	while (trail->hnext && !P_MobjWasRemoved(trail->hnext) && trail->hnext->health)
 | 
						|
	{
 | 
						|
		trail = trail->hnext;
 | 
						|
	}
 | 
						|
 | 
						|
	return trail;
 | 
						|
}
 | 
						|
 | 
						|
static mobj_t *K_ThrowKartItem(player_t *player, boolean missile, mobjtype_t mapthing, INT32 defaultDir, INT32 altthrow)
 | 
						|
{
 | 
						|
	mobj_t *mo;
 | 
						|
	INT32 dir, PROJSPEED;
 | 
						|
	angle_t newangle;
 | 
						|
	fixed_t newx, newy, newz;
 | 
						|
	mobj_t *throwmo;
 | 
						|
 | 
						|
	if (!player)
 | 
						|
		return NULL;
 | 
						|
 | 
						|
	// Figure out projectile speed by game speed
 | 
						|
	if (missile && mapthing != MT_BALLHOG) // Trying to keep compatability...
 | 
						|
	{
 | 
						|
		PROJSPEED = mobjinfo[mapthing].speed;
 | 
						|
		if (gamespeed == 0)
 | 
						|
			PROJSPEED = FixedMul(PROJSPEED, FRACUNIT-FRACUNIT/4);
 | 
						|
		else if (gamespeed == 2)
 | 
						|
			PROJSPEED = FixedMul(PROJSPEED, FRACUNIT+FRACUNIT/4);
 | 
						|
		PROJSPEED = FixedMul(PROJSPEED, mapobjectscale);
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		switch (gamespeed)
 | 
						|
		{
 | 
						|
			case 0:
 | 
						|
				PROJSPEED = 68*mapobjectscale; // Avg Speed is 34
 | 
						|
				break;
 | 
						|
			case 2:
 | 
						|
				PROJSPEED = 96*mapobjectscale; // Avg Speed is 48
 | 
						|
				break;
 | 
						|
			default:
 | 
						|
				PROJSPEED = 82*mapobjectscale; // Avg Speed is 41
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (altthrow)
 | 
						|
	{
 | 
						|
		if (altthrow == 2) // Kitchen sink throwing
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_throwdir] == 1)
 | 
						|
				dir = 3;
 | 
						|
			else if (player->kartstuff[k_throwdir] == -1)
 | 
						|
				dir = 1;
 | 
						|
			else
 | 
						|
				dir = 2;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_throwdir] == 1)
 | 
						|
				dir = 2;
 | 
						|
			else if (player->kartstuff[k_throwdir] == -1)
 | 
						|
				dir = -1;
 | 
						|
			else
 | 
						|
				dir = 1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_throwdir] != 0)
 | 
						|
			dir = player->kartstuff[k_throwdir];
 | 
						|
		else
 | 
						|
			dir = defaultDir;
 | 
						|
	}
 | 
						|
 | 
						|
	if (missile) // Shootables
 | 
						|
	{
 | 
						|
		if (mapthing == MT_BALLHOG) // Messy
 | 
						|
		{
 | 
						|
			if (dir == -1)
 | 
						|
			{
 | 
						|
				// Shoot backward
 | 
						|
				mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180 - 0x06000000, 0, PROJSPEED/4);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180 - 0x03000000, 0, PROJSPEED/4);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180, 0, PROJSPEED/4);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180 + 0x03000000, 0, PROJSPEED/4);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180 + 0x06000000, 0, PROJSPEED/4);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				// Shoot forward
 | 
						|
				mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle - 0x06000000, 0, PROJSPEED);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle - 0x03000000, 0, PROJSPEED);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle, 0, PROJSPEED);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + 0x03000000, 0, PROJSPEED);
 | 
						|
				K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + 0x06000000, 0, PROJSPEED);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (dir == -1 && mapthing != MT_SPB)
 | 
						|
			{
 | 
						|
				// Shoot backward
 | 
						|
				mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle + ANGLE_180, 0, PROJSPEED/2);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				// Shoot forward
 | 
						|
				mo = K_SpawnKartMissile(player->mo, mapthing, player->mo->angle, 0, PROJSPEED);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		player->kartstuff[k_bananadrag] = 0; // RESET timer, for multiple bananas
 | 
						|
 | 
						|
		if (dir > 0)
 | 
						|
		{
 | 
						|
			// Shoot forward
 | 
						|
			mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, mapthing);
 | 
						|
 | 
						|
			mo->threshold = 10;
 | 
						|
			P_SetTarget(&mo->target, player->mo);
 | 
						|
 | 
						|
			S_StartSound(player->mo, mo->info->seesound);
 | 
						|
 | 
						|
			if (mo)
 | 
						|
			{
 | 
						|
				angle_t fa = player->mo->angle>>ANGLETOFINESHIFT;
 | 
						|
				INT32 HEIGHT = (20 + (dir*10))*mapobjectscale + player->mo->momz;
 | 
						|
 | 
						|
				mo->momx = player->mo->momx + FixedMul(FINECOSINE(fa), (altthrow == 2 ? 2*PROJSPEED/3 : PROJSPEED));
 | 
						|
				mo->momy = player->mo->momy + FixedMul(FINESINE(fa), (altthrow == 2 ? 2*PROJSPEED/3 : PROJSPEED));
 | 
						|
				mo->momz = P_MobjFlip(player->mo) * HEIGHT;
 | 
						|
 | 
						|
				if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
					mo->eflags |= MFE_VERTICALFLIP;
 | 
						|
			}
 | 
						|
 | 
						|
			throwmo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FIREDITEM);
 | 
						|
			P_SetTarget(&throwmo->target, player->mo);
 | 
						|
			throwmo->movecount = 0; // above player
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			mobj_t *lasttrail = K_FindLastTrailMobj(player);
 | 
						|
 | 
						|
			if (lasttrail)
 | 
						|
			{
 | 
						|
				newx = lasttrail->x;
 | 
						|
				newy = lasttrail->y;
 | 
						|
				newz = lasttrail->z;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				// Drop it directly behind you.
 | 
						|
				fixed_t dropradius = FixedHypot(player->mo->radius, player->mo->radius) + FixedHypot(mobjinfo[mapthing].radius, mobjinfo[mapthing].radius);
 | 
						|
 | 
						|
				newangle = player->mo->angle;
 | 
						|
 | 
						|
				newx = player->mo->x + P_ReturnThrustX(player->mo, newangle + ANGLE_180, dropradius);
 | 
						|
				newy = player->mo->y + P_ReturnThrustY(player->mo, newangle + ANGLE_180, dropradius);
 | 
						|
				newz = player->mo->z;
 | 
						|
			}
 | 
						|
 | 
						|
			mo = P_SpawnMobj(newx, newy, newz, mapthing);
 | 
						|
 | 
						|
			if (P_MobjFlip(player->mo) < 0)
 | 
						|
				mo->z = player->mo->z + player->mo->height - mo->height;
 | 
						|
 | 
						|
			mo->threshold = 10;
 | 
						|
			P_SetTarget(&mo->target, player->mo);
 | 
						|
 | 
						|
			if (P_IsObjectOnGround(player->mo))
 | 
						|
			{
 | 
						|
				// floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn
 | 
						|
				// This should set it for FOFs
 | 
						|
				P_TeleportMove(mo, mo->x, mo->y, mo->z);
 | 
						|
 | 
						|
				if (P_MobjFlip(mo) > 0)
 | 
						|
				{
 | 
						|
					if (mo->floorz > mo->target->z - mo->height)
 | 
						|
					{
 | 
						|
						mo->z = mo->floorz;
 | 
						|
					}
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					if (mo->ceilingz < mo->target->z + mo->target->height + mo->height)
 | 
						|
					{
 | 
						|
						mo->z = mo->ceilingz - mo->height;
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (mo)
 | 
						|
			{
 | 
						|
				if (player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
					mo->eflags |= MFE_VERTICALFLIP;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return mo;
 | 
						|
}
 | 
						|
 | 
						|
#define THUNDERRADIUS 320
 | 
						|
 | 
						|
static void K_DoThunderShield(player_t *player)
 | 
						|
{
 | 
						|
	mobj_t *mo;
 | 
						|
	int i = 0;
 | 
						|
	fixed_t sx;
 | 
						|
	fixed_t sy;
 | 
						|
	angle_t an;
 | 
						|
 | 
						|
	S_StartSound(player->mo, sfx_zio3);
 | 
						|
	//player->kartstuff[k_thunderanim] = 35;
 | 
						|
	P_NukeEnemies(player->mo, player->mo, RING_DIST/4);
 | 
						|
 | 
						|
	// spawn vertical bolt
 | 
						|
	mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THOK);
 | 
						|
	P_SetTarget(&mo->target, player->mo);
 | 
						|
	P_SetMobjState(mo, S_LZIO11);
 | 
						|
	mo->color = SKINCOLOR_TEAL;
 | 
						|
	mo->scale = player->mo->scale*3 + (player->mo->scale/2);
 | 
						|
 | 
						|
	mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THOK);
 | 
						|
	P_SetTarget(&mo->target, player->mo);
 | 
						|
	P_SetMobjState(mo, S_LZIO21);
 | 
						|
	mo->color = SKINCOLOR_CYAN;
 | 
						|
	mo->scale = player->mo->scale*3 + (player->mo->scale/2);
 | 
						|
 | 
						|
	// spawn horizontal bolts;
 | 
						|
	for (i=0; i<7; i++)
 | 
						|
	{
 | 
						|
		mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THOK);
 | 
						|
		mo->angle = P_RandomRange(0, 359)*ANG1;
 | 
						|
		mo->fuse = P_RandomRange(20, 50);
 | 
						|
		P_SetTarget(&mo->target, player->mo);
 | 
						|
		P_SetMobjState(mo, S_KLIT1);
 | 
						|
	}
 | 
						|
 | 
						|
	// spawn the radius thing:
 | 
						|
	an = ANGLE_22h;
 | 
						|
	for (i=0; i<15; i++)
 | 
						|
	{
 | 
						|
		sx = player->mo->x + FixedMul((player->mo->scale*THUNDERRADIUS), FINECOSINE((an*i)>>ANGLETOFINESHIFT));
 | 
						|
		sy = player->mo->y + FixedMul((player->mo->scale*THUNDERRADIUS), FINESINE((an*i)>>ANGLETOFINESHIFT));
 | 
						|
		mo = P_SpawnMobj(sx, sy, player->mo->z, MT_THOK);
 | 
						|
		mo-> angle = an*i;
 | 
						|
		mo->extravalue1 = THUNDERRADIUS;	// Used to know whether we should teleport by radius or something.
 | 
						|
		mo->scale = player->mo->scale*3;
 | 
						|
		P_SetTarget(&mo->target, player->mo);
 | 
						|
		P_SetMobjState(mo, S_KSPARK1);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
#undef THUNDERRADIUS
 | 
						|
 | 
						|
static void K_DoHyudoroSteal(player_t *player)
 | 
						|
{
 | 
						|
	INT32 i, numplayers = 0;
 | 
						|
	INT32 playerswappable[MAXPLAYERS];
 | 
						|
	INT32 stealplayer = -1; // The player that's getting stolen from
 | 
						|
	INT32 prandom = 0;
 | 
						|
	boolean sink = P_RandomChance(FRACUNIT/64);
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (playeringame[i] && players[i].mo && players[i].mo->health > 0 && players[i].playerstate == PST_LIVE
 | 
						|
			&& player != &players[i] && !players[i].exiting && !players[i].spectator // Player in-game
 | 
						|
 | 
						|
			// Can steal from this player
 | 
						|
			&& (G_RaceGametype() //&& players[i].kartstuff[k_position] < player->kartstuff[k_position])
 | 
						|
			|| (G_BattleGametype() && players[i].kartstuff[k_bumper] > 0))
 | 
						|
 | 
						|
			// Has an item
 | 
						|
			&& (players[i].kartstuff[k_itemtype]
 | 
						|
			&& players[i].kartstuff[k_itemamount]
 | 
						|
			&& !players[i].kartstuff[k_itemheld]
 | 
						|
			&& !players[i].kartstuff[k_itemblink]))
 | 
						|
		{
 | 
						|
			playerswappable[numplayers] = i;
 | 
						|
			numplayers++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	prandom = P_RandomFixed();
 | 
						|
	S_StartSound(player->mo, sfx_s3k92);
 | 
						|
 | 
						|
	if (sink && numplayers > 0 && cv_kitchensink.value) // BEHOLD THE KITCHEN SINK
 | 
						|
	{
 | 
						|
		player->kartstuff[k_hyudorotimer] = hyudorotime;
 | 
						|
		player->kartstuff[k_stealingtimer] = stealtime;
 | 
						|
 | 
						|
		player->kartstuff[k_itemtype] = KITEM_KITCHENSINK;
 | 
						|
		player->kartstuff[k_itemamount] = 1;
 | 
						|
		player->kartstuff[k_itemheld] = 0;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else if ((G_RaceGametype() && player->kartstuff[k_position] == 1) || numplayers == 0) // No-one can be stolen from? Oh well...
 | 
						|
	{
 | 
						|
		player->kartstuff[k_hyudorotimer] = hyudorotime;
 | 
						|
		player->kartstuff[k_stealingtimer] = stealtime;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
	else if (numplayers == 1) // With just 2 players, we just need to set the other player to be the one to steal from
 | 
						|
	{
 | 
						|
		stealplayer = playerswappable[numplayers-1];
 | 
						|
	}
 | 
						|
	else if (numplayers > 1) // We need to choose between the available candidates for the 2nd player
 | 
						|
	{
 | 
						|
		stealplayer = playerswappable[prandom%(numplayers-1)];
 | 
						|
	}
 | 
						|
 | 
						|
	if (stealplayer > -1) // Now here's where we do the stealing, has to be done here because we still know the player we're stealing from
 | 
						|
	{
 | 
						|
		player->kartstuff[k_hyudorotimer] = hyudorotime;
 | 
						|
		player->kartstuff[k_stealingtimer] = stealtime;
 | 
						|
		players[stealplayer].kartstuff[k_stolentimer] = stealtime;
 | 
						|
 | 
						|
		player->kartstuff[k_itemtype] = players[stealplayer].kartstuff[k_itemtype];
 | 
						|
		player->kartstuff[k_itemamount] = players[stealplayer].kartstuff[k_itemamount];
 | 
						|
		player->kartstuff[k_itemheld] = 0;
 | 
						|
 | 
						|
		players[stealplayer].kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
		players[stealplayer].kartstuff[k_itemamount] = 0;
 | 
						|
		players[stealplayer].kartstuff[k_itemheld] = 0;
 | 
						|
 | 
						|
		if (P_IsLocalPlayer(&players[stealplayer]) && !splitscreen)
 | 
						|
			S_StartSound(NULL, sfx_s3k92);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void K_DoSneaker(player_t *player, INT32 type)
 | 
						|
{
 | 
						|
	fixed_t intendedboost;
 | 
						|
 | 
						|
	switch (gamespeed)
 | 
						|
	{
 | 
						|
		case 0:
 | 
						|
			intendedboost = 53740+768;
 | 
						|
			break;
 | 
						|
		case 2:
 | 
						|
			intendedboost = 17294+768;
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			intendedboost = 32768;
 | 
						|
			break;
 | 
						|
	}
 | 
						|
 | 
						|
	if (!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3)
 | 
						|
	{
 | 
						|
		S_StartSound(player->mo, sfx_cdfm01);
 | 
						|
		K_SpawnDashDustRelease(player);
 | 
						|
		if (intendedboost > player->kartstuff[k_speedboost])
 | 
						|
			player->kartstuff[k_destboostcam] = FixedMul(FRACUNIT, FixedDiv((intendedboost - player->kartstuff[k_speedboost]), intendedboost));
 | 
						|
	}
 | 
						|
 | 
						|
	if (!player->kartstuff[k_sneakertimer])
 | 
						|
	{
 | 
						|
		if (type == 2)
 | 
						|
		{
 | 
						|
			if (player->mo->hnext)
 | 
						|
			{
 | 
						|
				mobj_t *cur = player->mo->hnext;
 | 
						|
				while (cur && !P_MobjWasRemoved(cur))
 | 
						|
				{
 | 
						|
					if (!cur->tracer)
 | 
						|
					{
 | 
						|
						mobj_t *overlay = P_SpawnMobj(cur->x, cur->y, cur->z, MT_BOOSTFLAME);
 | 
						|
						P_SetTarget(&overlay->target, cur);
 | 
						|
						P_SetTarget(&cur->tracer, overlay);
 | 
						|
						P_SetScale(overlay, (overlay->destscale = 3*cur->scale/4));
 | 
						|
					}
 | 
						|
					cur = cur->hnext;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BOOSTFLAME);
 | 
						|
			P_SetTarget(&overlay->target, player->mo);
 | 
						|
			P_SetScale(overlay, (overlay->destscale = player->mo->scale));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_sneakertimer] = sneakertime;
 | 
						|
 | 
						|
	if (type != 0)
 | 
						|
	{
 | 
						|
		player->pflags |= PF_ATTACKDOWN;
 | 
						|
		K_PlayBoostTaunt(player->mo);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_DoShrink(player_t *user)
 | 
						|
{
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	S_StartSound(user->mo, sfx_kc46); // Sound the BANG!
 | 
						|
	user->pflags |= PF_ATTACKDOWN;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator || !players[i].mo)
 | 
						|
			continue;
 | 
						|
		if (&players[i] == user)
 | 
						|
			continue;
 | 
						|
		if (players[i].kartstuff[k_position] < user->kartstuff[k_position])
 | 
						|
		{
 | 
						|
			// Don't hit while invulnerable!
 | 
						|
			if (!players[i].kartstuff[k_invincibilitytimer]
 | 
						|
				&& players[i].kartstuff[k_growshrinktimer] <= 0
 | 
						|
				&& !players[i].kartstuff[k_hyudorotimer])
 | 
						|
			{
 | 
						|
				// Start shrinking!
 | 
						|
				K_DropItems(&players[i]);
 | 
						|
				players[i].mo->scalespeed = mapobjectscale/TICRATE;
 | 
						|
				players[i].mo->destscale = (6*mapobjectscale)/8;
 | 
						|
				if (cv_kartdebugshrink.value && !modeattacking && !players[i].bot)
 | 
						|
					players[i].mo->destscale = (6*players[i].mo->destscale)/8;
 | 
						|
				players[i].kartstuff[k_growshrinktimer] = -(200+(40*(MAXPLAYERS-players[i].kartstuff[k_position])));
 | 
						|
			}
 | 
						|
 | 
						|
			// Grow should get taken away.
 | 
						|
			if (players[i].kartstuff[k_growshrinktimer] > 0)
 | 
						|
				K_RemoveGrowShrink(&players[i]);
 | 
						|
 | 
						|
			//P_FlashPal(&players[i], PAL_NUKE, 10);
 | 
						|
			S_StartSound(players[i].mo, sfx_kc59);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
 | 
						|
void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound)
 | 
						|
{
 | 
						|
	const fixed_t vscale = mapobjectscale + (mo->scale - mapobjectscale);
 | 
						|
 | 
						|
	if (mo->player && mo->player->spectator)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (mo->eflags & MFE_SPRUNG)
 | 
						|
		return;
 | 
						|
 | 
						|
#ifdef ESLOPE
 | 
						|
	mo->standingslope = NULL;
 | 
						|
#endif
 | 
						|
 | 
						|
	mo->eflags |= MFE_SPRUNG;
 | 
						|
 | 
						|
	if (mo->eflags & MFE_VERTICALFLIP)
 | 
						|
		vertispeed *= -1;
 | 
						|
 | 
						|
	if (vertispeed == 0)
 | 
						|
	{
 | 
						|
		fixed_t thrust;
 | 
						|
 | 
						|
		if (mo->player)
 | 
						|
		{
 | 
						|
			thrust = 3*mo->player->speed/2;
 | 
						|
			if (thrust < 48<<FRACBITS)
 | 
						|
				thrust = 48<<FRACBITS;
 | 
						|
			if (thrust > 72<<FRACBITS)
 | 
						|
				thrust = 72<<FRACBITS;
 | 
						|
			if (mo->player->kartstuff[k_pogospring] != 2)
 | 
						|
			{
 | 
						|
				if (mo->player->kartstuff[k_sneakertimer])
 | 
						|
					thrust = FixedMul(thrust, 5*FRACUNIT/4);
 | 
						|
				else if (mo->player->kartstuff[k_invincibilitytimer])
 | 
						|
					thrust = FixedMul(thrust, 9*FRACUNIT/8);
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			thrust = FixedDiv(3*P_AproxDistance(mo->momx, mo->momy)/2, 5*FRACUNIT/2);
 | 
						|
			if (thrust < 16<<FRACBITS)
 | 
						|
				thrust = 16<<FRACBITS;
 | 
						|
			if (thrust > 32<<FRACBITS)
 | 
						|
				thrust = 32<<FRACBITS;
 | 
						|
		}
 | 
						|
 | 
						|
		mo->momz = FixedMul(FINESINE(ANGLE_22h>>ANGLETOFINESHIFT), FixedMul(thrust, vscale));
 | 
						|
	}
 | 
						|
	else
 | 
						|
		mo->momz = FixedMul(vertispeed, vscale);
 | 
						|
 | 
						|
	if (sound)
 | 
						|
		S_StartSound(mo, (sound == 1 ? sfx_kc2f : sfx_kpogos));
 | 
						|
}
 | 
						|
 | 
						|
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source)
 | 
						|
{
 | 
						|
	mobj_t *cachenext;
 | 
						|
 | 
						|
killnext:
 | 
						|
	cachenext = banana->hnext;
 | 
						|
 | 
						|
	if (banana->health)
 | 
						|
	{
 | 
						|
		if (banana->eflags & MFE_VERTICALFLIP)
 | 
						|
			banana->z -= banana->height;
 | 
						|
		else
 | 
						|
			banana->z += banana->height;
 | 
						|
 | 
						|
		S_StartSound(banana, banana->info->deathsound);
 | 
						|
		P_KillMobj(banana, inflictor, source);
 | 
						|
 | 
						|
		P_SetObjectMomZ(banana, 8*FRACUNIT, false);
 | 
						|
		if (inflictor)
 | 
						|
			P_InstaThrust(banana, R_PointToAngle2(inflictor->x, inflictor->y, banana->x, banana->y)+ANGLE_90, 16*FRACUNIT);
 | 
						|
	}
 | 
						|
 | 
						|
	if ((banana = cachenext))
 | 
						|
		goto killnext;
 | 
						|
}
 | 
						|
 | 
						|
// Just for firing/dropping items.
 | 
						|
void K_UpdateHnextList(player_t *player, boolean clean)
 | 
						|
{
 | 
						|
	mobj_t *work = player->mo, *nextwork;
 | 
						|
 | 
						|
	if (!work)
 | 
						|
		return;
 | 
						|
 | 
						|
	nextwork = work->hnext;
 | 
						|
 | 
						|
	while ((work = nextwork) && !P_MobjWasRemoved(work))
 | 
						|
	{
 | 
						|
		nextwork = work->hnext;
 | 
						|
 | 
						|
		if (!clean && (!work->movedir || work->movedir <= (UINT16)player->kartstuff[k_itemamount]))
 | 
						|
			continue;
 | 
						|
 | 
						|
		P_RemoveMobj(work);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// For getting hit!
 | 
						|
void K_DropHnextList(player_t *player)
 | 
						|
{
 | 
						|
	mobj_t *work = player->mo, *nextwork, *dropwork;
 | 
						|
	INT32 flip;
 | 
						|
	mobjtype_t type;
 | 
						|
	boolean orbit, ponground, dropall = true;
 | 
						|
 | 
						|
	if (!work)
 | 
						|
		return;
 | 
						|
 | 
						|
	flip = P_MobjFlip(player->mo);
 | 
						|
	ponground = P_IsObjectOnGround(player->mo);
 | 
						|
 | 
						|
	if (player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD && player->kartstuff[k_itemamount])
 | 
						|
	{
 | 
						|
		K_DoThunderShield(player);
 | 
						|
		player->kartstuff[k_itemamount] = 0;
 | 
						|
		player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
		player->kartstuff[k_curshield] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	nextwork = work->hnext;
 | 
						|
 | 
						|
	while ((work = nextwork) && !P_MobjWasRemoved(work))
 | 
						|
	{
 | 
						|
		nextwork = work->hnext;
 | 
						|
 | 
						|
		switch (work->type)
 | 
						|
		{
 | 
						|
			// Kart orbit items
 | 
						|
			case MT_ORBINAUT_SHIELD:
 | 
						|
				orbit = true;
 | 
						|
				type = MT_ORBINAUT;
 | 
						|
				break;
 | 
						|
			case MT_JAWZ_SHIELD:
 | 
						|
				orbit = true;
 | 
						|
				type = MT_JAWZ_DUD;
 | 
						|
				break;
 | 
						|
			// Kart trailing items
 | 
						|
			case MT_BANANA_SHIELD:
 | 
						|
				orbit = false;
 | 
						|
				type = MT_BANANA;
 | 
						|
				break;
 | 
						|
			case MT_SSMINE_SHIELD:
 | 
						|
				orbit = false;
 | 
						|
				dropall = false;
 | 
						|
				type = MT_SSMINE;
 | 
						|
				break;
 | 
						|
			case MT_EGGMANITEM_SHIELD:
 | 
						|
				orbit = false;
 | 
						|
				type = MT_EGGMANITEM;
 | 
						|
				break;
 | 
						|
			// intentionally do nothing
 | 
						|
			case MT_SINK_SHIELD:
 | 
						|
			case MT_ROCKETSNEAKER:
 | 
						|
				return;
 | 
						|
			default:
 | 
						|
				continue;
 | 
						|
		}
 | 
						|
 | 
						|
		dropwork = P_SpawnMobj(work->x, work->y, work->z, type);
 | 
						|
		P_SetTarget(&dropwork->target, player->mo);
 | 
						|
		dropwork->angle = work->angle;
 | 
						|
		dropwork->flags2 = work->flags2;
 | 
						|
		dropwork->flags |= MF_NOCLIPTHING;
 | 
						|
		dropwork->floorz = work->floorz;
 | 
						|
		dropwork->ceilingz = work->ceilingz;
 | 
						|
 | 
						|
		if (ponground)
 | 
						|
		{
 | 
						|
			// floorz and ceilingz aren't properly set to account for FOFs and Polyobjects on spawn
 | 
						|
			// This should set it for FOFs
 | 
						|
			//P_TeleportMove(dropwork, dropwork->x, dropwork->y, dropwork->z); -- handled better by above floorz/ceilingz passing
 | 
						|
 | 
						|
			if (flip == 1)
 | 
						|
			{
 | 
						|
				if (dropwork->floorz > dropwork->target->z - dropwork->height)
 | 
						|
				{
 | 
						|
					dropwork->z = dropwork->floorz;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (dropwork->ceilingz < dropwork->target->z + dropwork->target->height + dropwork->height)
 | 
						|
				{
 | 
						|
					dropwork->z = dropwork->ceilingz - dropwork->height;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (orbit) // splay out
 | 
						|
		{
 | 
						|
			dropwork->flags2 |= MF2_AMBUSH;
 | 
						|
			dropwork->z += flip;
 | 
						|
			dropwork->momx = player->mo->momx>>1;
 | 
						|
			dropwork->momy = player->mo->momy>>1;
 | 
						|
			dropwork->momz = 3*flip*mapobjectscale;
 | 
						|
			P_Thrust(dropwork, work->angle - ANGLE_90, 6*mapobjectscale);
 | 
						|
			dropwork->movecount = 2;
 | 
						|
			dropwork->movedir = work->angle - ANGLE_90;
 | 
						|
			P_SetMobjState(dropwork, dropwork->info->deathstate);
 | 
						|
			dropwork->tics = -1;
 | 
						|
			if (type == MT_JAWZ_DUD)
 | 
						|
				dropwork->z += 20*flip*dropwork->scale;
 | 
						|
			else
 | 
						|
			{
 | 
						|
				dropwork->color = work->color;
 | 
						|
				dropwork->angle -= ANGLE_90;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else // plop on the ground
 | 
						|
		{
 | 
						|
			dropwork->flags &= ~MF_NOCLIPTHING;
 | 
						|
			dropwork->threshold = 10;
 | 
						|
		}
 | 
						|
 | 
						|
		P_RemoveMobj(work);
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		// we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic...
 | 
						|
		P_SetTarget(&player->mo->hnext, NULL);
 | 
						|
		player->kartstuff[k_bananadrag] = 0;
 | 
						|
		if (player->kartstuff[k_eggmanheld])
 | 
						|
			player->kartstuff[k_eggmanheld] = 0;
 | 
						|
		else if (player->kartstuff[k_itemheld]
 | 
						|
			&& (dropall || (--player->kartstuff[k_itemamount] <= 0)))
 | 
						|
		{
 | 
						|
			player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// For getting EXTRA hit!
 | 
						|
void K_DropItems(player_t *player)
 | 
						|
{
 | 
						|
	boolean thunderhack = (player->kartstuff[k_curshield] && player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD);
 | 
						|
 | 
						|
	if (thunderhack)
 | 
						|
		player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
 | 
						|
	K_DropHnextList(player);
 | 
						|
 | 
						|
	if (player->mo && player->kartstuff[k_itemamount])
 | 
						|
	{
 | 
						|
		mobj_t *drop = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z + player->mo->height/2, MT_FLOATINGITEM);
 | 
						|
		P_SetScale(drop, drop->scale>>4);
 | 
						|
		drop->destscale = (3*drop->destscale)/2;;
 | 
						|
 | 
						|
		drop->angle = player->mo->angle + ANGLE_90;
 | 
						|
		P_Thrust(drop,
 | 
						|
			FixedAngle(P_RandomFixed()*180) + player->mo->angle + ANGLE_90,
 | 
						|
			16*mapobjectscale);
 | 
						|
		drop->momz = P_MobjFlip(player->mo)*3*mapobjectscale;
 | 
						|
 | 
						|
		drop->threshold = (thunderhack ? KITEM_THUNDERSHIELD : player->kartstuff[k_itemtype]);
 | 
						|
		drop->movecount = player->kartstuff[k_itemamount];
 | 
						|
 | 
						|
		drop->flags |= MF_NOCLIPTHING;
 | 
						|
	}
 | 
						|
 | 
						|
	K_StripItems(player);
 | 
						|
}
 | 
						|
 | 
						|
// When an item in the hnext chain dies.
 | 
						|
void K_RepairOrbitChain(mobj_t *orbit)
 | 
						|
{
 | 
						|
	mobj_t *cachenext = orbit->hnext;
 | 
						|
 | 
						|
	// First, repair the chain
 | 
						|
	if (orbit->hnext && orbit->hnext->health && !P_MobjWasRemoved(orbit->hnext))
 | 
						|
	{
 | 
						|
		P_SetTarget(&orbit->hnext->hprev, orbit->hprev);
 | 
						|
		P_SetTarget(&orbit->hnext, NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	if (orbit->hprev && orbit->hprev->health && !P_MobjWasRemoved(orbit->hprev))
 | 
						|
	{
 | 
						|
		P_SetTarget(&orbit->hprev->hnext, cachenext);
 | 
						|
		P_SetTarget(&orbit->hprev, NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	// Then recount to make sure item amount is correct
 | 
						|
	if (orbit->target && orbit->target->player)
 | 
						|
	{
 | 
						|
		INT32 num = 0;
 | 
						|
 | 
						|
		mobj_t *cur = orbit->target->hnext;
 | 
						|
		mobj_t *prev = NULL;
 | 
						|
 | 
						|
		while (cur && !P_MobjWasRemoved(cur))
 | 
						|
		{
 | 
						|
			prev = cur;
 | 
						|
			cur = cur->hnext;
 | 
						|
			if (++num > orbit->target->player->kartstuff[k_itemamount])
 | 
						|
				P_RemoveMobj(prev);
 | 
						|
			else
 | 
						|
				prev->movedir = num;
 | 
						|
		}
 | 
						|
 | 
						|
		if (orbit->target->player->kartstuff[k_itemamount] != num)
 | 
						|
			orbit->target->player->kartstuff[k_itemamount] = num;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Move the hnext chain!
 | 
						|
static void K_MoveHeldObjects(player_t *player)
 | 
						|
{
 | 
						|
	if (!player->mo)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!player->mo->hnext)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_bananadrag] = 0;
 | 
						|
		if (player->kartstuff[k_eggmanheld])
 | 
						|
			player->kartstuff[k_eggmanheld] = 0;
 | 
						|
		else if (player->kartstuff[k_itemheld])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if (P_MobjWasRemoved(player->mo->hnext))
 | 
						|
	{
 | 
						|
		// we need this here too because this is done in afterthink - pointers are cleaned up at the START of each tic...
 | 
						|
		P_SetTarget(&player->mo->hnext, NULL);
 | 
						|
		player->kartstuff[k_bananadrag] = 0;
 | 
						|
		if (player->kartstuff[k_eggmanheld])
 | 
						|
			player->kartstuff[k_eggmanheld] = 0;
 | 
						|
		else if (player->kartstuff[k_itemheld])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
		}
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	switch (player->mo->hnext->type)
 | 
						|
	{
 | 
						|
		case MT_ORBINAUT_SHIELD: // Kart orbit items
 | 
						|
		case MT_JAWZ_SHIELD:
 | 
						|
			{
 | 
						|
				mobj_t *cur = player->mo->hnext;
 | 
						|
 | 
						|
				player->kartstuff[k_bananadrag] = 0; // Just to make sure
 | 
						|
 | 
						|
				while (cur && !P_MobjWasRemoved(cur))
 | 
						|
				{
 | 
						|
					const fixed_t radius = FixedHypot(player->mo->radius, player->mo->radius) + FixedHypot(cur->radius, cur->radius); // mobj's distance from its Target, or Radius.
 | 
						|
					fixed_t z;
 | 
						|
 | 
						|
					if (!cur->health)
 | 
						|
					{
 | 
						|
						cur = cur->hnext;
 | 
						|
						continue;
 | 
						|
					}
 | 
						|
 | 
						|
					cur->color = player->skincolor;
 | 
						|
 | 
						|
					cur->angle -= ANGLE_90;
 | 
						|
					cur->angle += FixedAngle(cur->info->speed);
 | 
						|
 | 
						|
					if (cur->extravalue1 < radius)
 | 
						|
						cur->extravalue1 += FixedMul(P_AproxDistance(cur->extravalue1, radius), FRACUNIT/12);
 | 
						|
					if (cur->extravalue1 > radius)
 | 
						|
						cur->extravalue1 = radius;
 | 
						|
 | 
						|
					// If the player is on the ceiling, then flip your items as well.
 | 
						|
					if (player && player->mo->eflags & MFE_VERTICALFLIP)
 | 
						|
						cur->eflags |= MFE_VERTICALFLIP;
 | 
						|
					else
 | 
						|
						cur->eflags &= ~MFE_VERTICALFLIP;
 | 
						|
 | 
						|
					// Shrink your items if the player shrunk too.
 | 
						|
					P_SetScale(cur, (cur->destscale = FixedMul(FixedDiv(cur->extravalue1, radius), player->mo->scale)));
 | 
						|
 | 
						|
					if (P_MobjFlip(cur) > 0)
 | 
						|
						z = player->mo->z;
 | 
						|
					else
 | 
						|
						z = player->mo->z + player->mo->height - cur->height;
 | 
						|
 | 
						|
					cur->flags |= MF_NOCLIPTHING; // temporarily make them noclip other objects so they can't hit anyone while in the player
 | 
						|
					P_TeleportMove(cur, player->mo->x, player->mo->y, z);
 | 
						|
					cur->momx = FixedMul(FINECOSINE(cur->angle>>ANGLETOFINESHIFT), cur->extravalue1);
 | 
						|
					cur->momy = FixedMul(FINESINE(cur->angle>>ANGLETOFINESHIFT), cur->extravalue1);
 | 
						|
					cur->flags &= ~MF_NOCLIPTHING;
 | 
						|
					if (!P_TryMove(cur, player->mo->x + cur->momx, player->mo->y + cur->momy, true))
 | 
						|
						P_SlideMove(cur, true);
 | 
						|
					if (P_IsObjectOnGround(player->mo))
 | 
						|
					{
 | 
						|
						if (P_MobjFlip(cur) > 0)
 | 
						|
						{
 | 
						|
							if (cur->floorz > player->mo->z - cur->height)
 | 
						|
								z = cur->floorz;
 | 
						|
						}
 | 
						|
						else
 | 
						|
						{
 | 
						|
							if (cur->ceilingz < player->mo->z + player->mo->height + cur->height)
 | 
						|
								z = cur->ceilingz - cur->height;
 | 
						|
						}
 | 
						|
					}
 | 
						|
 | 
						|
					// Center it during the scale up animation
 | 
						|
					z += (FixedMul(mobjinfo[cur->type].height, player->mo->scale - cur->scale)>>1) * P_MobjFlip(cur);
 | 
						|
 | 
						|
					cur->z = z;
 | 
						|
					cur->momx = cur->momy = 0;
 | 
						|
					cur->angle += ANGLE_90;
 | 
						|
 | 
						|
					cur = cur->hnext;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case MT_BANANA_SHIELD: // Kart trailing items
 | 
						|
		case MT_SSMINE_SHIELD:
 | 
						|
		case MT_EGGMANITEM_SHIELD:
 | 
						|
		case MT_SINK_SHIELD:
 | 
						|
			{
 | 
						|
				mobj_t *cur = player->mo->hnext;
 | 
						|
				mobj_t *targ = player->mo;
 | 
						|
 | 
						|
				if (P_IsObjectOnGround(player->mo) && player->speed > 0)
 | 
						|
					player->kartstuff[k_bananadrag]++;
 | 
						|
 | 
						|
				while (cur && !P_MobjWasRemoved(cur))
 | 
						|
				{
 | 
						|
					const fixed_t radius = FixedHypot(targ->radius, targ->radius) + FixedHypot(cur->radius, cur->radius);
 | 
						|
					angle_t ang;
 | 
						|
					fixed_t targx, targy, targz;
 | 
						|
					fixed_t speed, dist;
 | 
						|
 | 
						|
					cur->flags &= ~MF_NOCLIPTHING;
 | 
						|
 | 
						|
					if (!cur->health)
 | 
						|
					{
 | 
						|
						cur = cur->hnext;
 | 
						|
						continue;
 | 
						|
					}
 | 
						|
 | 
						|
					if (cur->extravalue1 < radius)
 | 
						|
						cur->extravalue1 += FixedMul(P_AproxDistance(cur->extravalue1, radius), FRACUNIT/12);
 | 
						|
					if (cur->extravalue1 > radius)
 | 
						|
						cur->extravalue1 = radius;
 | 
						|
 | 
						|
					if (cur != player->mo->hnext)
 | 
						|
					{
 | 
						|
						targ = cur->hprev;
 | 
						|
						dist = cur->extravalue1/4;
 | 
						|
					}
 | 
						|
					else
 | 
						|
						dist = cur->extravalue1/2;
 | 
						|
 | 
						|
					if (!targ || P_MobjWasRemoved(targ))
 | 
						|
						continue;
 | 
						|
 | 
						|
					// Shrink your items if the player shrunk too.
 | 
						|
					P_SetScale(cur, (cur->destscale = FixedMul(FixedDiv(cur->extravalue1, radius), player->mo->scale)));
 | 
						|
 | 
						|
					ang = targ->angle;
 | 
						|
					targx = targ->x + P_ReturnThrustX(cur, ang + ANGLE_180, dist);
 | 
						|
					targy = targ->y + P_ReturnThrustY(cur, ang + ANGLE_180, dist);
 | 
						|
					targz = targ->z;
 | 
						|
					speed = FixedMul(R_PointToDist2(cur->x, cur->y, targx, targy), 3*FRACUNIT/4);
 | 
						|
					if (P_IsObjectOnGround(targ))
 | 
						|
						targz = cur->floorz;
 | 
						|
 | 
						|
					cur->angle = R_PointToAngle2(cur->x, cur->y, targx, targy);
 | 
						|
 | 
						|
					/*if (P_IsObjectOnGround(player->mo) && player->speed > 0 && player->kartstuff[k_bananadrag] > TICRATE
 | 
						|
						&& P_RandomChance(min(FRACUNIT/2, FixedDiv(player->speed, K_GetKartSpeed(player, false))/2)))
 | 
						|
					{
 | 
						|
						if (leveltime & 1)
 | 
						|
							targz += 8*(2*FRACUNIT)/7;
 | 
						|
						else
 | 
						|
							targz -= 8*(2*FRACUNIT)/7;
 | 
						|
					}*/
 | 
						|
 | 
						|
					if (speed > dist)
 | 
						|
						P_InstaThrust(cur, cur->angle, speed-dist);
 | 
						|
 | 
						|
					P_SetObjectMomZ(cur, FixedMul(targz - cur->z, 7*FRACUNIT/8) - gravity, false);
 | 
						|
 | 
						|
					if (R_PointToDist2(cur->x, cur->y, targx, targy) > 768*FRACUNIT)
 | 
						|
						P_TeleportMove(cur, targx, targy, cur->z);
 | 
						|
 | 
						|
					cur = cur->hnext;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		case MT_ROCKETSNEAKER: // Special rocket sneaker stuff
 | 
						|
			{
 | 
						|
				mobj_t *cur = player->mo->hnext;
 | 
						|
				INT32 num = 0;
 | 
						|
 | 
						|
				while (cur && !P_MobjWasRemoved(cur))
 | 
						|
				{
 | 
						|
					const fixed_t radius = FixedHypot(player->mo->radius, player->mo->radius) + FixedHypot(cur->radius, cur->radius);
 | 
						|
					boolean vibrate = ((leveltime & 1) && !cur->tracer);
 | 
						|
					angle_t angoffset;
 | 
						|
					fixed_t targx, targy, targz;
 | 
						|
 | 
						|
					cur->flags &= ~MF_NOCLIPTHING;
 | 
						|
 | 
						|
					if (player->kartstuff[k_rocketsneakertimer] <= TICRATE && (leveltime & 1))
 | 
						|
						cur->flags2 |= MF2_DONTDRAW;
 | 
						|
					else
 | 
						|
						cur->flags2 &= ~MF2_DONTDRAW;
 | 
						|
 | 
						|
					if (num & 1)
 | 
						|
						P_SetMobjStateNF(cur, (vibrate ? S_ROCKETSNEAKER_LVIBRATE : S_ROCKETSNEAKER_L));
 | 
						|
					else
 | 
						|
						P_SetMobjStateNF(cur, (vibrate ? S_ROCKETSNEAKER_RVIBRATE : S_ROCKETSNEAKER_R));
 | 
						|
 | 
						|
					if (!player->kartstuff[k_rocketsneakertimer] || cur->extravalue2 || !cur->health)
 | 
						|
					{
 | 
						|
						num = (num+1) % 2;
 | 
						|
						cur = cur->hnext;
 | 
						|
						continue;
 | 
						|
					}
 | 
						|
 | 
						|
					if (cur->extravalue1 < radius)
 | 
						|
						cur->extravalue1 += FixedMul(P_AproxDistance(cur->extravalue1, radius), FRACUNIT/12);
 | 
						|
					if (cur->extravalue1 > radius)
 | 
						|
						cur->extravalue1 = radius;
 | 
						|
 | 
						|
					// Shrink your items if the player shrunk too.
 | 
						|
					P_SetScale(cur, (cur->destscale = FixedMul(FixedDiv(cur->extravalue1, radius), player->mo->scale)));
 | 
						|
 | 
						|
#if 1
 | 
						|
					{
 | 
						|
						angle_t input = player->frameangle - cur->angle;
 | 
						|
						boolean invert = (input > ANGLE_180);
 | 
						|
						if (invert)
 | 
						|
							input = InvAngle(input);
 | 
						|
 | 
						|
						input = FixedAngle(AngleFixed(input)/4);
 | 
						|
						if (invert)
 | 
						|
							input = InvAngle(input);
 | 
						|
 | 
						|
						cur->angle = cur->angle + input;
 | 
						|
					}
 | 
						|
#else
 | 
						|
					cur->angle = player->frameangle;
 | 
						|
#endif
 | 
						|
 | 
						|
					angoffset = ANGLE_90 + (ANGLE_180 * num);
 | 
						|
 | 
						|
					targx = player->mo->x + P_ReturnThrustX(cur, cur->angle + angoffset, cur->extravalue1);
 | 
						|
					targy = player->mo->y + P_ReturnThrustY(cur, cur->angle + angoffset, cur->extravalue1);
 | 
						|
 | 
						|
					{ // bobbing, copy pasted from my kimokawaiii entry
 | 
						|
						const fixed_t pi = (22<<FRACBITS) / 7; // loose approximation, this doesn't need to be incredibly precise
 | 
						|
						fixed_t sine = 8 * FINESINE((((2*pi*(4*TICRATE)) * leveltime)>>ANGLETOFINESHIFT) & FINEMASK);
 | 
						|
						targz = (player->mo->z + (player->mo->height/2)) + sine;
 | 
						|
					}
 | 
						|
 | 
						|
					if (cur->tracer)
 | 
						|
					{
 | 
						|
						fixed_t diffx, diffy, diffz;
 | 
						|
 | 
						|
						diffx = targx - cur->x;
 | 
						|
						diffy = targy - cur->y;
 | 
						|
						diffz = targz - cur->z;
 | 
						|
 | 
						|
						P_TeleportMove(cur->tracer, cur->tracer->x + diffx + P_ReturnThrustX(cur, cur->angle + angoffset, 6*cur->scale),
 | 
						|
							cur->tracer->y + diffy + P_ReturnThrustY(cur, cur->angle + angoffset, 6*cur->scale), cur->tracer->z + diffz);
 | 
						|
						P_SetScale(cur->tracer, (cur->tracer->destscale = 3*cur->scale/4));
 | 
						|
					}
 | 
						|
 | 
						|
					P_TeleportMove(cur, targx, targy, targz);
 | 
						|
 | 
						|
					num = (num+1) % 2;
 | 
						|
					cur = cur->hnext;
 | 
						|
				}
 | 
						|
			}
 | 
						|
			break;
 | 
						|
		default:
 | 
						|
			break;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
player_t *K_FindJawzTarget(mobj_t *actor, player_t *source)
 | 
						|
{
 | 
						|
	fixed_t best = -1;
 | 
						|
	player_t *wtarg = NULL;
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		angle_t thisang;
 | 
						|
		player_t *player;
 | 
						|
 | 
						|
		if (!playeringame[i])
 | 
						|
			continue;
 | 
						|
 | 
						|
		player = &players[i];
 | 
						|
 | 
						|
		if (player->spectator)
 | 
						|
			continue; // spectator
 | 
						|
 | 
						|
		if (!player->mo)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (player->mo->health <= 0)
 | 
						|
			continue; // dead
 | 
						|
 | 
						|
		// Don't target yourself, stupid.
 | 
						|
		if (player == source)
 | 
						|
			continue;
 | 
						|
 | 
						|
		// Don't home in on teammates.
 | 
						|
		if (G_GametypeHasTeams() && source->ctfteam == player->ctfteam)
 | 
						|
			continue;
 | 
						|
 | 
						|
		// Invisible, don't bother
 | 
						|
		if (player->kartstuff[k_hyudorotimer])
 | 
						|
			continue;
 | 
						|
 | 
						|
		// Find the angle, see who's got the best.
 | 
						|
		thisang = actor->angle - R_PointToAngle2(actor->x, actor->y, player->mo->x, player->mo->y);
 | 
						|
		if (thisang > ANGLE_180)
 | 
						|
			thisang = InvAngle(thisang);
 | 
						|
 | 
						|
		if (thisang > ANGLE_45) // Don't go for people who are behind you
 | 
						|
			continue;
 | 
						|
 | 
						|
		// Jawz only go after the person directly ahead of you in race... sort of literally now!
 | 
						|
		if (G_RaceGametype())
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_position] >= source->kartstuff[k_position]) // Don't pay attention to people behind you
 | 
						|
				continue;
 | 
						|
			if ((best == -1) || (player->kartstuff[k_position] > best))
 | 
						|
			{
 | 
						|
				wtarg = player;
 | 
						|
				best = player->kartstuff[k_position];
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			fixed_t thisdist;
 | 
						|
			fixed_t thisavg;
 | 
						|
 | 
						|
			if (player->kartstuff[k_bumper] <= 0)
 | 
						|
				continue;
 | 
						|
 | 
						|
			// Z pos too high/low
 | 
						|
			if (abs(player->mo->z - (actor->z + actor->momz)) > RING_DIST/8)
 | 
						|
				continue;
 | 
						|
 | 
						|
			thisdist = P_AproxDistance(player->mo->x - (actor->x + actor->momx), player->mo->y - (actor->y + actor->momy));
 | 
						|
 | 
						|
			if (thisdist > 2*RING_DIST) // Don't go for people who are too far away
 | 
						|
				continue;
 | 
						|
 | 
						|
			thisavg = (AngleFixed(thisang) + thisdist) / 2;
 | 
						|
 | 
						|
			//CONS_Printf("got avg %d from player # %d\n", thisavg>>FRACBITS, i);
 | 
						|
 | 
						|
			if ((best == -1) || (thisavg < best))
 | 
						|
			{
 | 
						|
				wtarg = player;
 | 
						|
				best = thisavg;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return wtarg;
 | 
						|
}
 | 
						|
 | 
						|
// Engine Sounds.
 | 
						|
static void K_UpdateEngineSounds(player_t *player, ticcmd_t *cmd)
 | 
						|
{
 | 
						|
	const INT32 numsnds = 13;
 | 
						|
	INT32 class, s, w; // engine class number
 | 
						|
	UINT8 volume = 255;
 | 
						|
	fixed_t volumedampen = 0;
 | 
						|
	INT32 targetsnd = 0;
 | 
						|
	INT32 i;
 | 
						|
 | 
						|
	s = (player->kartspeed-1)/3;
 | 
						|
	w = (player->kartweight-1)/3;
 | 
						|
 | 
						|
#define LOCKSTAT(stat) \
 | 
						|
	if (stat < 0) { stat = 0; } \
 | 
						|
	if (stat > 2) { stat = 2; }
 | 
						|
	LOCKSTAT(s);
 | 
						|
	LOCKSTAT(w);
 | 
						|
#undef LOCKSTAT
 | 
						|
 | 
						|
	class = s+(3*w);
 | 
						|
 | 
						|
	// Silence the engines
 | 
						|
	if (leveltime < 8 || player->spectator || player->exiting)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_enginesnd] = 0; // Reset sound number
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
#if 0
 | 
						|
	if ((leveltime % 8) != ((player-players) % 8)) // Per-player offset, to make engines sound distinct!
 | 
						|
#else
 | 
						|
	if (leveltime % 8) // .25 seconds of wait time between engine sounds
 | 
						|
#endif
 | 
						|
		return;
 | 
						|
 | 
						|
	if ((leveltime >= starttime-(2*TICRATE) && leveltime <= starttime) || (player->kartstuff[k_respawn] == 1)) // Startup boosts
 | 
						|
		targetsnd = ((cmd->buttons & BT_ACCELERATE) ? 12 : 0);
 | 
						|
	else
 | 
						|
		targetsnd = (((6*cmd->forwardmove)/25) + ((player->speed / mapobjectscale)/5))/2;
 | 
						|
 | 
						|
	if (targetsnd < 0)
 | 
						|
		targetsnd = 0;
 | 
						|
	if (targetsnd > 12)
 | 
						|
		targetsnd = 12;
 | 
						|
 | 
						|
	if (player->kartstuff[k_enginesnd] < targetsnd)
 | 
						|
		player->kartstuff[k_enginesnd]++;
 | 
						|
	if (player->kartstuff[k_enginesnd] > targetsnd)
 | 
						|
		player->kartstuff[k_enginesnd]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_enginesnd] < 0)
 | 
						|
		player->kartstuff[k_enginesnd] = 0;
 | 
						|
	if (player->kartstuff[k_enginesnd] > 12)
 | 
						|
		player->kartstuff[k_enginesnd] = 12;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		UINT8 thisvol = 0;
 | 
						|
		fixed_t dist;
 | 
						|
 | 
						|
		if (!playeringame[i] || !players[i].mo || players[i].spectator || players[i].exiting)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if ((i == displayplayer)
 | 
						|
			|| (i == secondarydisplayplayer && splitscreen)
 | 
						|
			|| (i == thirddisplayplayer && splitscreen > 1)
 | 
						|
			|| (i == fourthdisplayplayer && splitscreen > 2))
 | 
						|
		{
 | 
						|
			volumedampen += FRACUNIT; // We already know what this is gonna be, let's not waste our time.
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
 | 
						|
		dist = P_AproxDistance(P_AproxDistance(player->mo->x-players[i].mo->x,
 | 
						|
			player->mo->y-players[i].mo->y), player->mo->z-players[i].mo->z) / 2;
 | 
						|
 | 
						|
		dist = FixedDiv(dist, mapobjectscale);
 | 
						|
 | 
						|
		if (dist > 1536<<FRACBITS)
 | 
						|
			continue;
 | 
						|
		else if (dist < 160<<FRACBITS) // engine sounds' approx. range
 | 
						|
			thisvol = 255;
 | 
						|
		else
 | 
						|
			thisvol = (15 * (((160<<FRACBITS) - dist)>>FRACBITS)) / (((1536<<FRACBITS)-(160<<FRACBITS))>>(FRACBITS+4));
 | 
						|
 | 
						|
		if (thisvol == 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
		volumedampen += (thisvol * 257); // 255 * 257 = FRACUNIT
 | 
						|
	}
 | 
						|
 | 
						|
	if (volumedampen > FRACUNIT)
 | 
						|
		volume = FixedDiv(volume<<FRACBITS, volumedampen)>>FRACBITS;
 | 
						|
 | 
						|
	if (volume <= 0) // Might as well
 | 
						|
		return;
 | 
						|
 | 
						|
	S_StartSoundAtVolume(player->mo, (sfx_krta00 + player->kartstuff[k_enginesnd]) + (class*numsnds), volume);
 | 
						|
}
 | 
						|
 | 
						|
static void K_UpdateInvincibilitySounds(player_t *player)
 | 
						|
{
 | 
						|
	INT32 sfxnum = sfx_None;
 | 
						|
 | 
						|
	if (player->mo->health > 0 && !P_IsLocalPlayer(player))
 | 
						|
	{
 | 
						|
		if (cv_kartinvinsfx.value)
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_growshrinktimer] > 0) // Prioritize Grow
 | 
						|
				sfxnum = sfx_alarmg;
 | 
						|
			else if (player->kartstuff[k_invincibilitytimer] > 0)
 | 
						|
				sfxnum = sfx_alarmi;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_growshrinktimer] > 0)
 | 
						|
				sfxnum = sfx_kgrow;
 | 
						|
			else if (player->kartstuff[k_invincibilitytimer] > 0)
 | 
						|
				sfxnum = sfx_kinvnc;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (sfxnum != sfx_None && !S_SoundPlaying(player->mo, sfxnum))
 | 
						|
		S_StartSound(player->mo, sfxnum);
 | 
						|
 | 
						|
#define STOPTHIS(this) \
 | 
						|
	if (sfxnum != this && S_SoundPlaying(player->mo, this)) \
 | 
						|
		S_StopSoundByID(player->mo, this);
 | 
						|
	STOPTHIS(sfx_alarmi);
 | 
						|
	STOPTHIS(sfx_alarmg);
 | 
						|
	STOPTHIS(sfx_kinvnc);
 | 
						|
	STOPTHIS(sfx_kgrow);
 | 
						|
#undef STOPTHIS
 | 
						|
}
 | 
						|
 | 
						|
void K_KartPlayerHUDUpdate(player_t *player)
 | 
						|
{
 | 
						|
	if (player->kartstuff[k_lapanimation])
 | 
						|
		player->kartstuff[k_lapanimation]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_yougotem])
 | 
						|
		player->kartstuff[k_yougotem]--;
 | 
						|
 | 
						|
	if (G_BattleGametype() && (player->exiting || player->kartstuff[k_comebacktimer]))
 | 
						|
	{
 | 
						|
		if (player->exiting)
 | 
						|
		{
 | 
						|
			if (player->exiting < 6*TICRATE)
 | 
						|
				player->kartstuff[k_cardanimation] += ((164-player->kartstuff[k_cardanimation])/8)+1;
 | 
						|
			else if (player->exiting == 6*TICRATE)
 | 
						|
				player->kartstuff[k_cardanimation] = 0;
 | 
						|
			else if (player->kartstuff[k_cardanimation] < 2*TICRATE)
 | 
						|
				player->kartstuff[k_cardanimation]++;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_comebacktimer] < 6*TICRATE)
 | 
						|
				player->kartstuff[k_cardanimation] -= ((164-player->kartstuff[k_cardanimation])/8)+1;
 | 
						|
			else if (player->kartstuff[k_comebacktimer] < 9*TICRATE)
 | 
						|
				player->kartstuff[k_cardanimation] += ((164-player->kartstuff[k_cardanimation])/8)+1;
 | 
						|
		}
 | 
						|
 | 
						|
		if (player->kartstuff[k_cardanimation] > 164)
 | 
						|
			player->kartstuff[k_cardanimation] = 164;
 | 
						|
		if (player->kartstuff[k_cardanimation] < 0)
 | 
						|
			player->kartstuff[k_cardanimation] = 0;
 | 
						|
	}
 | 
						|
	else if (G_RaceGametype() && player->exiting)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_cardanimation] < 2*TICRATE)
 | 
						|
			player->kartstuff[k_cardanimation]++;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		player->kartstuff[k_cardanimation] = 0;
 | 
						|
}
 | 
						|
 | 
						|
/**	\brief	Decreases various kart timers and powers per frame. Called in P_PlayerThink in p_user.c
 | 
						|
 | 
						|
	\param	player	player object passed from P_PlayerThink
 | 
						|
	\param	cmd		control input from player
 | 
						|
 | 
						|
	\return	void
 | 
						|
*/
 | 
						|
void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
 | 
						|
{
 | 
						|
	K_UpdateOffroad(player);
 | 
						|
	K_UpdateEngineSounds(player, cmd); // Thanks, VAda!
 | 
						|
	K_GetKartBoostPower(player);
 | 
						|
 | 
						|
	// Speed lines
 | 
						|
	if ((player->kartstuff[k_sneakertimer] || player->kartstuff[k_driftboost] || player->kartstuff[k_startboost]) && player->speed > 0)
 | 
						|
	{
 | 
						|
		mobj_t *fast = P_SpawnMobj(player->mo->x + (P_RandomRange(-36,36) * player->mo->scale),
 | 
						|
			player->mo->y + (P_RandomRange(-36,36) * player->mo->scale),
 | 
						|
			player->mo->z + (player->mo->height/2) + (P_RandomRange(-20,20) * player->mo->scale),
 | 
						|
			MT_FASTLINE);
 | 
						|
		fast->angle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
 | 
						|
		fast->momx = 3*player->mo->momx/4;
 | 
						|
		fast->momy = 3*player->mo->momy/4;
 | 
						|
		fast->momz = 3*player->mo->momz/4;
 | 
						|
		K_MatchGenericExtraFlags(fast, player->mo);
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->playerstate == PST_DEAD || player->kartstuff[k_respawn] > 1) // Ensure these are set correctly here
 | 
						|
	{
 | 
						|
		player->mo->colorized = false;
 | 
						|
		player->mo->color = player->skincolor;
 | 
						|
	}
 | 
						|
	else if (player->kartstuff[k_eggmanexplode]) // You're gonna diiiiie
 | 
						|
	{
 | 
						|
		const INT32 flashtime = 4<<(player->kartstuff[k_eggmanexplode]/TICRATE);
 | 
						|
		if (player->kartstuff[k_eggmanexplode] == 1 || (player->kartstuff[k_eggmanexplode] % (flashtime/2) != 0))
 | 
						|
		{
 | 
						|
			player->mo->colorized = false;
 | 
						|
			player->mo->color = player->skincolor;
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_eggmanexplode] % flashtime == 0)
 | 
						|
		{
 | 
						|
			player->mo->colorized = true;
 | 
						|
			player->mo->color = SKINCOLOR_BLACK;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			player->mo->colorized = true;
 | 
						|
			player->mo->color = SKINCOLOR_CRIMSON;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else if (player->kartstuff[k_invincibilitytimer]) // setting players to use the star colormap and spawning afterimages
 | 
						|
	{
 | 
						|
		mobj_t *ghost;
 | 
						|
		player->mo->colorized = true;
 | 
						|
		ghost = P_SpawnGhostMobj(player->mo);
 | 
						|
		ghost->fuse = 4;
 | 
						|
		ghost->frame |= FF_FULLBRIGHT;
 | 
						|
	}
 | 
						|
	else if (player->kartstuff[k_growshrinktimer]) // Ditto, for grow/shrink
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_growshrinktimer] % 5 == 0)
 | 
						|
		{
 | 
						|
			player->mo->colorized = true;
 | 
						|
			player->mo->color = (player->kartstuff[k_growshrinktimer] < 0 ? SKINCOLOR_CREAMSICLE : SKINCOLOR_PERIWINKLE);
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			player->mo->colorized = false;
 | 
						|
			player->mo->color = player->skincolor;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		player->mo->colorized = false;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_dashpadcooldown]) // Twinkle Circuit inspired afterimages
 | 
						|
	{
 | 
						|
		mobj_t *ghost;
 | 
						|
		ghost = P_SpawnGhostMobj(player->mo);
 | 
						|
		ghost->fuse = player->kartstuff[k_dashpadcooldown]+1;
 | 
						|
		ghost->momx = player->mo->momx / (player->kartstuff[k_dashpadcooldown]+1);
 | 
						|
		ghost->momy = player->mo->momy / (player->kartstuff[k_dashpadcooldown]+1);
 | 
						|
		ghost->momz = player->mo->momz / (player->kartstuff[k_dashpadcooldown]+1);
 | 
						|
		player->kartstuff[k_dashpadcooldown]--;
 | 
						|
	}
 | 
						|
 | 
						|
	// DKR style camera for boosting
 | 
						|
	if (player->kartstuff[k_boostcam] != 0 || player->kartstuff[k_destboostcam] != 0)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_boostcam] < player->kartstuff[k_destboostcam]
 | 
						|
			&& player->kartstuff[k_destboostcam] != 0)
 | 
						|
		{
 | 
						|
			player->kartstuff[k_boostcam] += FRACUNIT/(TICRATE/4);
 | 
						|
			if (player->kartstuff[k_boostcam] >= player->kartstuff[k_destboostcam])
 | 
						|
				player->kartstuff[k_destboostcam] = 0;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			player->kartstuff[k_boostcam] -= FRACUNIT/TICRATE;
 | 
						|
			if (player->kartstuff[k_boostcam] < player->kartstuff[k_destboostcam])
 | 
						|
				player->kartstuff[k_boostcam] = player->kartstuff[k_destboostcam] = 0;
 | 
						|
		}
 | 
						|
		//CONS_Printf("cam: %d, dest: %d\n", player->kartstuff[k_boostcam], player->kartstuff[k_destboostcam]);
 | 
						|
	}
 | 
						|
 | 
						|
	player->kartstuff[k_timeovercam] = 0;
 | 
						|
 | 
						|
	// Make ABSOLUTELY SURE that your flashing tics don't get set WHILE you're still in hit animations.
 | 
						|
	if (player->kartstuff[k_spinouttimer] != 0
 | 
						|
		|| player->kartstuff[k_wipeoutslow] != 0
 | 
						|
		|| player->kartstuff[k_squishedtimer] != 0)
 | 
						|
	{
 | 
						|
		player->powers[pw_flashing] = K_GetKartFlashing(player);
 | 
						|
	}
 | 
						|
	else if (player->powers[pw_flashing] == K_GetKartFlashing(player))
 | 
						|
	{
 | 
						|
		player->powers[pw_flashing]--;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_spinouttimer])
 | 
						|
	{
 | 
						|
		if ((P_IsObjectOnGround(player->mo) || player->kartstuff[k_spinouttype] == 1)
 | 
						|
			&& (player->kartstuff[k_sneakertimer] == 0))
 | 
						|
		{
 | 
						|
			player->kartstuff[k_spinouttimer]--;
 | 
						|
			if (player->kartstuff[k_wipeoutslow] > 1)
 | 
						|
				player->kartstuff[k_wipeoutslow]--;
 | 
						|
			if (player->kartstuff[k_spinouttimer] == 0)
 | 
						|
				player->kartstuff[k_spinouttype] = 0; // Reset type
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_wipeoutslow] == 1)
 | 
						|
			player->mo->friction = ORIG_FRICTION;
 | 
						|
		player->kartstuff[k_wipeoutslow] = 0;
 | 
						|
		if (!comeback)
 | 
						|
			player->kartstuff[k_comebacktimer] = comebacktime;
 | 
						|
		else if (player->kartstuff[k_comebacktimer])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_comebacktimer]--;
 | 
						|
			if (P_IsLocalPlayer(player) && player->kartstuff[k_bumper] <= 0 && player->kartstuff[k_comebacktimer] <= 0)
 | 
						|
				comebackshowninfo = true; // client has already seen the message
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/*if (player->kartstuff[k_thunderanim])
 | 
						|
		player->kartstuff[k_thunderanim]--;*/
 | 
						|
 | 
						|
	if (player->kartstuff[k_sneakertimer])
 | 
						|
	{
 | 
						|
		player->kartstuff[k_sneakertimer]--;
 | 
						|
		if (player->kartstuff[k_wipeoutslow] > 0 && player->kartstuff[k_wipeoutslow] < wipeoutslowtime+1)
 | 
						|
			player->kartstuff[k_wipeoutslow] = wipeoutslowtime+1;
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_floorboost])
 | 
						|
		player->kartstuff[k_floorboost]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_driftboost])
 | 
						|
		player->kartstuff[k_driftboost]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_startboost])
 | 
						|
		player->kartstuff[k_startboost]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_invincibilitytimer])
 | 
						|
		player->kartstuff[k_invincibilitytimer]--;
 | 
						|
 | 
						|
	if (!player->kartstuff[k_respawn] && player->kartstuff[k_growshrinktimer] != 0)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_growshrinktimer] > 0)
 | 
						|
			player->kartstuff[k_growshrinktimer]--;
 | 
						|
		if (player->kartstuff[k_growshrinktimer] < 0)
 | 
						|
			player->kartstuff[k_growshrinktimer]++;
 | 
						|
 | 
						|
		// Back to normal
 | 
						|
		if (player->kartstuff[k_growshrinktimer] == 0)
 | 
						|
			K_RemoveGrowShrink(player);
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_stealingtimer] == 0 && player->kartstuff[k_stolentimer] == 0
 | 
						|
		&& player->kartstuff[k_rocketsneakertimer])
 | 
						|
		player->kartstuff[k_rocketsneakertimer]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_hyudorotimer])
 | 
						|
		player->kartstuff[k_hyudorotimer]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_sadtimer])
 | 
						|
		player->kartstuff[k_sadtimer]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_stealingtimer])
 | 
						|
		player->kartstuff[k_stealingtimer]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_stolentimer])
 | 
						|
		player->kartstuff[k_stolentimer]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_squishedtimer])
 | 
						|
		player->kartstuff[k_squishedtimer]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_justbumped])
 | 
						|
		player->kartstuff[k_justbumped]--;
 | 
						|
 | 
						|
	// This doesn't go in HUD update because it has potential gameplay ramifications
 | 
						|
	if (player->kartstuff[k_itemblink] && player->kartstuff[k_itemblink]-- <= 0)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_itemblinkmode] = 0;
 | 
						|
		player->kartstuff[k_itemblink] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	K_KartPlayerHUDUpdate(player);
 | 
						|
 | 
						|
	if (player->kartstuff[k_voices])
 | 
						|
		player->kartstuff[k_voices]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_tauntvoices])
 | 
						|
		player->kartstuff[k_tauntvoices]--;
 | 
						|
 | 
						|
	if (G_BattleGametype() && player->kartstuff[k_bumper] > 0)
 | 
						|
		player->kartstuff[k_wanted]++;
 | 
						|
 | 
						|
	if (P_IsObjectOnGround(player->mo))
 | 
						|
		player->kartstuff[k_waterskip] = 0;
 | 
						|
 | 
						|
	if (player->kartstuff[k_instashield])
 | 
						|
		player->kartstuff[k_instashield]--;
 | 
						|
 | 
						|
	if (player->kartstuff[k_eggmanexplode])
 | 
						|
	{
 | 
						|
		if (player->spectator || (G_BattleGametype() && !player->kartstuff[k_bumper]))
 | 
						|
			player->kartstuff[k_eggmanexplode] = 0;
 | 
						|
		else
 | 
						|
		{
 | 
						|
			player->kartstuff[k_eggmanexplode]--;
 | 
						|
			if (player->kartstuff[k_eggmanexplode] <= 0)
 | 
						|
			{
 | 
						|
				mobj_t *eggsexplode;
 | 
						|
				//player->powers[pw_flashing] = 0;
 | 
						|
				eggsexplode = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SPBEXPLOSION);
 | 
						|
				if (player->kartstuff[k_eggmanblame] >= 0
 | 
						|
				&& player->kartstuff[k_eggmanblame] < MAXPLAYERS
 | 
						|
				&& playeringame[player->kartstuff[k_eggmanblame]]
 | 
						|
				&& !players[player->kartstuff[k_eggmanblame]].spectator
 | 
						|
				&& players[player->kartstuff[k_eggmanblame]].mo)
 | 
						|
					P_SetTarget(&eggsexplode->target, players[player->kartstuff[k_eggmanblame]].mo);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// ???
 | 
						|
	/*
 | 
						|
	if (player->kartstuff[k_jmp] > 1 && onground)
 | 
						|
	{
 | 
						|
		S_StartSound(player->mo, sfx_spring);
 | 
						|
		P_DoJump(player, false);
 | 
						|
		player->mo->momz *= player->kartstuff[k_jmp];
 | 
						|
		player->kartstuff[k_jmp] = 0;
 | 
						|
	}
 | 
						|
	*/
 | 
						|
 | 
						|
	if (player->kartstuff[k_comebacktimer])
 | 
						|
		player->kartstuff[k_comebackmode] = 0;
 | 
						|
 | 
						|
	if (P_IsObjectOnGround(player->mo) && player->mo->momz <= 0 && player->kartstuff[k_pogospring])
 | 
						|
		player->kartstuff[k_pogospring] = 0;
 | 
						|
 | 
						|
	if (cmd->buttons & BT_DRIFT)
 | 
						|
		player->kartstuff[k_jmp] = 1;
 | 
						|
	else
 | 
						|
		player->kartstuff[k_jmp] = 0;
 | 
						|
 | 
						|
	// Respawn Checker
 | 
						|
	if (player->kartstuff[k_respawn])
 | 
						|
		K_RespawnChecker(player);
 | 
						|
 | 
						|
	// Roulette Code
 | 
						|
	K_KartItemRoulette(player, cmd);
 | 
						|
 | 
						|
	// Handle invincibility sfx
 | 
						|
	K_UpdateInvincibilitySounds(player); // Also thanks, VAda!
 | 
						|
 | 
						|
	// Plays the music after the starting countdown.
 | 
						|
	if (P_IsLocalPlayer(player) && leveltime == (starttime + (TICRATE/2)))
 | 
						|
		S_ChangeMusicInternal(mapmusname, true);
 | 
						|
}
 | 
						|
 | 
						|
void K_KartPlayerAfterThink(player_t *player)
 | 
						|
{
 | 
						|
	if (player->kartstuff[k_curshield]
 | 
						|
		|| player->kartstuff[k_invincibilitytimer]
 | 
						|
		|| (player->kartstuff[k_growshrinktimer] != 0 && player->kartstuff[k_growshrinktimer] % 5 == 4)) // 4 instead of 0 because this is afterthink!
 | 
						|
	{
 | 
						|
		player->mo->frame |= FF_FULLBRIGHT;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (!(player->mo->state->frame & FF_FULLBRIGHT))
 | 
						|
			player->mo->frame &= ~FF_FULLBRIGHT;
 | 
						|
	}
 | 
						|
 | 
						|
	// Move held objects (Bananas, Orbinaut, etc)
 | 
						|
	K_MoveHeldObjects(player);
 | 
						|
 | 
						|
	// Jawz reticule (seeking)
 | 
						|
	if (player->kartstuff[k_itemtype] == KITEM_JAWZ && player->kartstuff[k_itemheld])
 | 
						|
	{
 | 
						|
		player_t *targ = K_FindJawzTarget(player->mo, player);
 | 
						|
		mobj_t *ret;
 | 
						|
 | 
						|
		if (!targ)
 | 
						|
		{
 | 
						|
			player->kartstuff[k_lastjawztarget] = -1;
 | 
						|
			return;
 | 
						|
		}
 | 
						|
 | 
						|
		ret = P_SpawnMobj(targ->mo->x, targ->mo->y, targ->mo->z, MT_PLAYERRETICULE);
 | 
						|
		P_SetTarget(&ret->target, targ->mo);
 | 
						|
		ret->frame |= ((leveltime % 10) / 2);
 | 
						|
		ret->tics = 1;
 | 
						|
		ret->color = player->skincolor;
 | 
						|
 | 
						|
		if (targ-players != player->kartstuff[k_lastjawztarget])
 | 
						|
		{
 | 
						|
			if (P_IsLocalPlayer(player) || P_IsLocalPlayer(targ))
 | 
						|
				S_StartSound(NULL, sfx_s3k89);
 | 
						|
			else
 | 
						|
				S_StartSound(targ->mo, sfx_s3k89);
 | 
						|
 | 
						|
			player->kartstuff[k_lastjawztarget] = targ-players;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		player->kartstuff[k_lastjawztarget] = -1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Returns false if this player being placed here causes them to collide with any other player
 | 
						|
// Used in g_game.c for match etc. respawning
 | 
						|
// This does not check along the z because the z is not correctly set for the spawnee at this point
 | 
						|
boolean K_CheckPlayersRespawnColliding(INT32 playernum, fixed_t x, fixed_t y)
 | 
						|
{
 | 
						|
	INT32 i;
 | 
						|
	fixed_t p1radius = players[playernum].mo->radius;
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (playernum == i || !playeringame[i] || players[i].spectator || !players[i].mo || players[i].mo->health <= 0
 | 
						|
			|| players[i].playerstate != PST_LIVE || (players[i].mo->flags & MF_NOCLIP) || (players[i].mo->flags & MF_NOCLIPTHING))
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (abs(x - players[i].mo->x) < (p1radius + players[i].mo->radius)
 | 
						|
			&& abs(y - players[i].mo->y) < (p1radius + players[i].mo->radius))
 | 
						|
		{
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return true;
 | 
						|
}
 | 
						|
 | 
						|
// countersteer is how strong the controls are telling us we are turning
 | 
						|
// turndir is the direction the controls are telling us to turn, -1 if turning right and 1 if turning left
 | 
						|
static INT16 K_GetKartDriftValue(player_t *player, fixed_t countersteer)
 | 
						|
{
 | 
						|
	INT16 basedrift, driftangle;
 | 
						|
	fixed_t driftweight = player->kartweight*14; // 12
 | 
						|
 | 
						|
	// If they aren't drifting or on the ground this doesn't apply
 | 
						|
	if (player->kartstuff[k_drift] == 0 || !P_IsObjectOnGround(player->mo))
 | 
						|
		return 0;
 | 
						|
 | 
						|
	if (player->kartstuff[k_driftend] != 0)
 | 
						|
	{
 | 
						|
		return -266*player->kartstuff[k_drift]; // Drift has ended and we are tweaking their angle back a bit
 | 
						|
	}
 | 
						|
 | 
						|
	//basedrift = 90*player->kartstuff[k_drift]; // 450
 | 
						|
	//basedrift = 93*player->kartstuff[k_drift] - driftweight*3*player->kartstuff[k_drift]/10; // 447 - 303
 | 
						|
	basedrift = 83*player->kartstuff[k_drift] - (driftweight - 14)*player->kartstuff[k_drift]/5; // 415 - 303
 | 
						|
	driftangle = abs((252 - driftweight)*player->kartstuff[k_drift]/5);
 | 
						|
 | 
						|
	return basedrift + FixedMul(driftangle, countersteer);
 | 
						|
}
 | 
						|
 | 
						|
INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue)
 | 
						|
{
 | 
						|
	fixed_t p_maxspeed = FixedMul(K_GetKartSpeed(player, false), 3*FRACUNIT);
 | 
						|
	fixed_t adjustangle = FixedDiv((p_maxspeed>>16) - (player->speed>>16), (p_maxspeed>>16) + player->kartweight);
 | 
						|
 | 
						|
	if (player->spectator)
 | 
						|
		return turnvalue;
 | 
						|
 | 
						|
	if (player->kartstuff[k_drift] != 0 && P_IsObjectOnGround(player->mo))
 | 
						|
	{
 | 
						|
		// If we're drifting we have a completely different turning value
 | 
						|
		if (player->kartstuff[k_driftend] == 0)
 | 
						|
		{
 | 
						|
			// 800 is the max set in g_game.c with angleturn
 | 
						|
			fixed_t countersteer = FixedDiv(turnvalue*FRACUNIT, 800*FRACUNIT);
 | 
						|
			turnvalue = K_GetKartDriftValue(player, countersteer);
 | 
						|
		}
 | 
						|
		else
 | 
						|
			turnvalue = (INT16)(turnvalue + K_GetKartDriftValue(player, FRACUNIT));
 | 
						|
 | 
						|
		return turnvalue;
 | 
						|
	}
 | 
						|
 | 
						|
	turnvalue = FixedMul(turnvalue, adjustangle); // Weight has a small effect on turning
 | 
						|
 | 
						|
	if (player->kartstuff[k_invincibilitytimer] || player->kartstuff[k_sneakertimer] || player->kartstuff[k_growshrinktimer] > 0)
 | 
						|
		turnvalue = FixedMul(turnvalue, FixedDiv(5*FRACUNIT, 4*FRACUNIT));
 | 
						|
 | 
						|
	return turnvalue;
 | 
						|
}
 | 
						|
 | 
						|
INT32 K_GetKartDriftSparkValue(player_t *player)
 | 
						|
{
 | 
						|
	UINT8 kartspeed = (G_BattleGametype() && player->kartstuff[k_bumper] <= 0)
 | 
						|
		? 1
 | 
						|
		: player->kartspeed;
 | 
						|
	return (26*4 + kartspeed*2 + (9 - player->kartweight))*8;
 | 
						|
}
 | 
						|
 | 
						|
static void K_KartDrift(player_t *player, boolean onground)
 | 
						|
{
 | 
						|
	INT32 dsone = K_GetKartDriftSparkValue(player);
 | 
						|
	INT32 dstwo = dsone*2;
 | 
						|
	INT32 dsthree = dstwo*2;
 | 
						|
 | 
						|
	// Drifting is actually straffing + automatic turning.
 | 
						|
	// Holding the Jump button will enable drifting.
 | 
						|
 | 
						|
	// Drift Release (Moved here so you can't "chain" drifts)
 | 
						|
	if ((player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5)
 | 
						|
		// || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1))
 | 
						|
		&& player->kartstuff[k_driftcharge] < dsone
 | 
						|
		&& onground)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_driftcharge] = 0;
 | 
						|
	}
 | 
						|
	else if ((player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5)
 | 
						|
		// || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1))
 | 
						|
		&& (player->kartstuff[k_driftcharge] >= dsone && player->kartstuff[k_driftcharge] < dstwo)
 | 
						|
		&& onground)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_driftboost] < 20)
 | 
						|
			player->kartstuff[k_driftboost] = 20;
 | 
						|
		S_StartSound(player->mo, sfx_s23c);
 | 
						|
		//K_SpawnDashDustRelease(player);
 | 
						|
		player->kartstuff[k_driftcharge] = 0;
 | 
						|
	}
 | 
						|
	else if ((player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5)
 | 
						|
		// || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1))
 | 
						|
		&& player->kartstuff[k_driftcharge] < dsthree
 | 
						|
		&& onground)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_driftboost] < 50)
 | 
						|
			player->kartstuff[k_driftboost] = 50;
 | 
						|
		S_StartSound(player->mo, sfx_s23c);
 | 
						|
		//K_SpawnDashDustRelease(player);
 | 
						|
		player->kartstuff[k_driftcharge] = 0;
 | 
						|
	}
 | 
						|
	else if ((player->kartstuff[k_drift] != -5 && player->kartstuff[k_drift] != 5)
 | 
						|
		// || (player->kartstuff[k_drift] >= 1 && player->kartstuff[k_turndir] != 1) || (player->kartstuff[k_drift] <= -1 && player->kartstuff[k_turndir] != -1))
 | 
						|
		&& player->kartstuff[k_driftcharge] >= dsthree
 | 
						|
		&& onground)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_driftboost] < 125)
 | 
						|
			player->kartstuff[k_driftboost] = 125;
 | 
						|
		S_StartSound(player->mo, sfx_s23c);
 | 
						|
		//K_SpawnDashDustRelease(player);
 | 
						|
		player->kartstuff[k_driftcharge] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	// Drifting: left or right?
 | 
						|
	if ((player->cmd.driftturn > 0) && player->speed > FixedMul(10<<16, player->mo->scale) && player->kartstuff[k_jmp] == 1
 | 
						|
		&& (player->kartstuff[k_drift] == 0 || player->kartstuff[k_driftend] == 1)) // && player->kartstuff[k_drift] != 1)
 | 
						|
	{
 | 
						|
		// Starting left drift
 | 
						|
		player->kartstuff[k_drift] = 1;
 | 
						|
		player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0;
 | 
						|
	}
 | 
						|
	else if ((player->cmd.driftturn < 0) && player->speed > FixedMul(10<<16, player->mo->scale) && player->kartstuff[k_jmp] == 1
 | 
						|
		&& (player->kartstuff[k_drift] == 0 || player->kartstuff[k_driftend] == 1)) // && player->kartstuff[k_drift] != -1)
 | 
						|
	{
 | 
						|
		// Starting right drift
 | 
						|
		player->kartstuff[k_drift] = -1;
 | 
						|
		player->kartstuff[k_driftend] = player->kartstuff[k_driftcharge] = 0;
 | 
						|
	}
 | 
						|
	else if (player->kartstuff[k_jmp] == 0) // || player->kartstuff[k_turndir] == 0)
 | 
						|
	{
 | 
						|
		// drift is not being performed so if we're just finishing set driftend and decrement counters
 | 
						|
		if (player->kartstuff[k_drift] > 0)
 | 
						|
		{
 | 
						|
			player->kartstuff[k_drift]--;
 | 
						|
			player->kartstuff[k_driftend] = 1;
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_drift] < 0)
 | 
						|
		{
 | 
						|
			player->kartstuff[k_drift]++;
 | 
						|
			player->kartstuff[k_driftend] = 1;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			player->kartstuff[k_driftend] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	// Incease/decrease the drift value to continue drifting in that direction
 | 
						|
	if (player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_jmp] == 1 && onground && player->kartstuff[k_drift] != 0)
 | 
						|
	{
 | 
						|
		fixed_t driftadditive = 24;
 | 
						|
 | 
						|
		if (player->kartstuff[k_drift] >= 1) // Drifting to the left
 | 
						|
		{
 | 
						|
			player->kartstuff[k_drift]++;
 | 
						|
			if (player->kartstuff[k_drift] > 5)
 | 
						|
				player->kartstuff[k_drift] = 5;
 | 
						|
 | 
						|
			if (player->cmd.driftturn > 0) // Inward
 | 
						|
				driftadditive += abs(player->cmd.driftturn)/100;
 | 
						|
			if (player->cmd.driftturn < 0) // Outward
 | 
						|
				driftadditive -= abs(player->cmd.driftturn)/75;
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_drift] <= -1) // Drifting to the right
 | 
						|
		{
 | 
						|
			player->kartstuff[k_drift]--;
 | 
						|
			if (player->kartstuff[k_drift] < -5)
 | 
						|
				player->kartstuff[k_drift] = -5;
 | 
						|
 | 
						|
			if (player->cmd.driftturn < 0) // Inward
 | 
						|
				driftadditive += abs(player->cmd.driftturn)/100;
 | 
						|
			if (player->cmd.driftturn > 0) // Outward
 | 
						|
				driftadditive -= abs(player->cmd.driftturn)/75;
 | 
						|
		}
 | 
						|
 | 
						|
		// This spawns the drift sparks
 | 
						|
		if (player->kartstuff[k_driftcharge] + driftadditive >= dsone)
 | 
						|
			K_SpawnDriftSparks(player);
 | 
						|
 | 
						|
		// Sound whenever you get a different tier of sparks
 | 
						|
		if (P_IsLocalPlayer(player) // UGHGHGH...
 | 
						|
			&& ((player->kartstuff[k_driftcharge] < dsone && player->kartstuff[k_driftcharge]+driftadditive >= dsone)
 | 
						|
			|| (player->kartstuff[k_driftcharge] < dstwo && player->kartstuff[k_driftcharge]+driftadditive >= dstwo)
 | 
						|
			|| (player->kartstuff[k_driftcharge] < dsthree && player->kartstuff[k_driftcharge]+driftadditive >= dsthree)))
 | 
						|
		{
 | 
						|
			//S_StartSound(player->mo, sfx_s3ka2);
 | 
						|
			S_StartSoundAtVolume(player->mo, sfx_s3ka2, 192); // Ugh...
 | 
						|
		}
 | 
						|
 | 
						|
		player->kartstuff[k_driftcharge] += driftadditive;
 | 
						|
		player->kartstuff[k_driftend] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	// Stop drifting
 | 
						|
	if (player->kartstuff[k_spinouttimer] > 0 // banana peel
 | 
						|
		|| player->speed < FixedMul(10<<16, player->mo->scale)) // you're too slow!
 | 
						|
	{
 | 
						|
		player->kartstuff[k_drift] = player->kartstuff[k_driftcharge] = 0;
 | 
						|
		player->kartstuff[k_aizdriftstrat] = player->kartstuff[k_brakedrift] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((!player->kartstuff[k_sneakertimer])
 | 
						|
	|| (!player->cmd.driftturn)
 | 
						|
	|| (player->cmd.driftturn > 0) != (player->kartstuff[k_aizdriftstrat] > 0))
 | 
						|
	{
 | 
						|
		if (!player->kartstuff[k_drift])
 | 
						|
			player->kartstuff[k_aizdriftstrat] = 0;
 | 
						|
		else
 | 
						|
			player->kartstuff[k_aizdriftstrat] = ((player->kartstuff[k_drift] > 0) ? 1 : -1);
 | 
						|
	}
 | 
						|
	else if (player->kartstuff[k_aizdriftstrat] && !player->kartstuff[k_drift])
 | 
						|
		K_SpawnAIZDust(player);
 | 
						|
 | 
						|
	if (player->kartstuff[k_drift]
 | 
						|
		&& ((player->cmd.buttons & BT_BRAKE)
 | 
						|
		|| !(player->cmd.buttons & BT_ACCELERATE))
 | 
						|
		&& P_IsObjectOnGround(player->mo))
 | 
						|
	{
 | 
						|
		if (!player->kartstuff[k_brakedrift])
 | 
						|
			K_SpawnBrakeDriftSparks(player);
 | 
						|
		player->kartstuff[k_brakedrift] = 1;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		player->kartstuff[k_brakedrift] = 0;
 | 
						|
}
 | 
						|
//
 | 
						|
// K_KartUpdatePosition
 | 
						|
//
 | 
						|
void K_KartUpdatePosition(player_t *player)
 | 
						|
{
 | 
						|
	fixed_t position = 1;
 | 
						|
	fixed_t oldposition = player->kartstuff[k_position];
 | 
						|
	fixed_t i, ppcd, pncd, ipcd, incd;
 | 
						|
	fixed_t pmo, imo;
 | 
						|
	mobj_t *mo;
 | 
						|
 | 
						|
	if (player->spectator || !player->mo)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator || !players[i].mo)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (G_RaceGametype())
 | 
						|
		{
 | 
						|
			if ((((players[i].starpostnum) + (numstarposts + 1) * players[i].laps) >
 | 
						|
				((player->starpostnum) + (numstarposts + 1) * player->laps)))
 | 
						|
				position++;
 | 
						|
			else if (((players[i].starpostnum) + (numstarposts+1)*players[i].laps) ==
 | 
						|
				((player->starpostnum) + (numstarposts+1)*player->laps))
 | 
						|
			{
 | 
						|
				ppcd = pncd = ipcd = incd = 0;
 | 
						|
 | 
						|
				player->kartstuff[k_prevcheck] = players[i].kartstuff[k_prevcheck] = 0;
 | 
						|
				player->kartstuff[k_nextcheck] = players[i].kartstuff[k_nextcheck] = 0;
 | 
						|
 | 
						|
				// This checks every thing on the map, and looks for MT_BOSS3WAYPOINT (the thing we're using for checkpoint wp's, for now)
 | 
						|
				for (mo = waypointcap; mo != NULL; mo = mo->tracer)
 | 
						|
				{
 | 
						|
					pmo = P_AproxDistance(P_AproxDistance(	mo->x - player->mo->x,
 | 
						|
															mo->y - player->mo->y),
 | 
						|
															mo->z - player->mo->z) / FRACUNIT;
 | 
						|
					imo = P_AproxDistance(P_AproxDistance(	mo->x - players[i].mo->x,
 | 
						|
															mo->y - players[i].mo->y),
 | 
						|
															mo->z - players[i].mo->z) / FRACUNIT;
 | 
						|
 | 
						|
					if (mo->health == player->starpostnum && (!mo->movecount || mo->movecount == player->laps+1))
 | 
						|
					{
 | 
						|
						player->kartstuff[k_prevcheck] += pmo;
 | 
						|
						ppcd++;
 | 
						|
					}
 | 
						|
					if (mo->health == (player->starpostnum + 1) && (!mo->movecount || mo->movecount == player->laps+1))
 | 
						|
					{
 | 
						|
						player->kartstuff[k_nextcheck] += pmo;
 | 
						|
						pncd++;
 | 
						|
					}
 | 
						|
					if (mo->health == players[i].starpostnum && (!mo->movecount || mo->movecount == players[i].laps+1))
 | 
						|
					{
 | 
						|
						players[i].kartstuff[k_prevcheck] += imo;
 | 
						|
						ipcd++;
 | 
						|
					}
 | 
						|
					if (mo->health == (players[i].starpostnum + 1) && (!mo->movecount || mo->movecount == players[i].laps+1))
 | 
						|
					{
 | 
						|
						players[i].kartstuff[k_nextcheck] += imo;
 | 
						|
						incd++;
 | 
						|
					}
 | 
						|
				}
 | 
						|
 | 
						|
				if (ppcd > 1) player->kartstuff[k_prevcheck] /= ppcd;
 | 
						|
				if (pncd > 1) player->kartstuff[k_nextcheck] /= pncd;
 | 
						|
				if (ipcd > 1) players[i].kartstuff[k_prevcheck] /= ipcd;
 | 
						|
				if (incd > 1) players[i].kartstuff[k_nextcheck] /= incd;
 | 
						|
 | 
						|
				if ((players[i].kartstuff[k_nextcheck] > 0 || player->kartstuff[k_nextcheck] > 0) && !player->exiting)
 | 
						|
				{
 | 
						|
					if ((players[i].kartstuff[k_nextcheck] - players[i].kartstuff[k_prevcheck]) <
 | 
						|
						(player->kartstuff[k_nextcheck] - player->kartstuff[k_prevcheck]))
 | 
						|
						position++;
 | 
						|
				}
 | 
						|
				else if (!player->exiting)
 | 
						|
				{
 | 
						|
					if (players[i].kartstuff[k_prevcheck] > player->kartstuff[k_prevcheck])
 | 
						|
						position++;
 | 
						|
				}
 | 
						|
				else
 | 
						|
				{
 | 
						|
					if (players[i].starposttime < player->starposttime)
 | 
						|
						position++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (G_BattleGametype())
 | 
						|
		{
 | 
						|
			if (player->exiting) // End of match standings
 | 
						|
			{
 | 
						|
				if (players[i].marescore > player->marescore) // Only score matters
 | 
						|
					position++;
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (players[i].kartstuff[k_bumper] == player->kartstuff[k_bumper] && players[i].marescore > player->marescore)
 | 
						|
					position++;
 | 
						|
				else if (players[i].kartstuff[k_bumper] > player->kartstuff[k_bumper])
 | 
						|
					position++;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (leveltime < starttime || oldposition == 0)
 | 
						|
		oldposition = position;
 | 
						|
 | 
						|
	if (oldposition != position) // Changed places?
 | 
						|
		player->kartstuff[k_positiondelay] = 10; // Position number growth
 | 
						|
 | 
						|
	player->kartstuff[k_position] = position;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// K_StripItems
 | 
						|
//
 | 
						|
void K_StripItems(player_t *player)
 | 
						|
{
 | 
						|
	player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
	player->kartstuff[k_itemamount] = 0;
 | 
						|
	player->kartstuff[k_itemheld] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_rocketsneakertimer] = 0;
 | 
						|
 | 
						|
	if (!player->kartstuff[k_itemroulette] || player->kartstuff[k_roulettetype] != 2)
 | 
						|
	{
 | 
						|
		player->kartstuff[k_itemroulette] = 0;
 | 
						|
		player->kartstuff[k_roulettetype] = 0;
 | 
						|
	}
 | 
						|
	player->kartstuff[k_eggmanheld] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_hyudorotimer] = 0;
 | 
						|
	player->kartstuff[k_stealingtimer] = 0;
 | 
						|
	player->kartstuff[k_stolentimer] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_curshield] = 0;
 | 
						|
	//player->kartstuff[k_thunderanim] = 0;
 | 
						|
	player->kartstuff[k_bananadrag] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_sadtimer] = 0;
 | 
						|
 | 
						|
	K_UpdateHnextList(player, true);
 | 
						|
}
 | 
						|
 | 
						|
void K_StripOther(player_t *player)
 | 
						|
{
 | 
						|
	player->kartstuff[k_itemroulette] = 0;
 | 
						|
	player->kartstuff[k_roulettetype] = 0;
 | 
						|
 | 
						|
	player->kartstuff[k_invincibilitytimer] = 0;
 | 
						|
	K_RemoveGrowShrink(player);
 | 
						|
 | 
						|
	if (player->kartstuff[k_eggmanexplode])
 | 
						|
	{
 | 
						|
		player->kartstuff[k_eggmanexplode] = 0;
 | 
						|
		player->kartstuff[k_eggmanblame] = -1;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// K_MoveKartPlayer
 | 
						|
//
 | 
						|
void K_MoveKartPlayer(player_t *player, boolean onground)
 | 
						|
{
 | 
						|
	ticcmd_t *cmd = &player->cmd;
 | 
						|
	boolean ATTACK_IS_DOWN = ((cmd->buttons & BT_ATTACK) && !(player->pflags & PF_ATTACKDOWN));
 | 
						|
	boolean HOLDING_ITEM = (player->kartstuff[k_itemheld] || player->kartstuff[k_eggmanheld]);
 | 
						|
	boolean NO_HYUDORO = (player->kartstuff[k_stolentimer] == 0 && player->kartstuff[k_stealingtimer] == 0);
 | 
						|
 | 
						|
	K_KartUpdatePosition(player);
 | 
						|
 | 
						|
	if (!player->exiting)
 | 
						|
	{
 | 
						|
		if (player->kartstuff[k_oldposition] < player->kartstuff[k_position]) // But first, if you lost a place,
 | 
						|
		{
 | 
						|
			player->kartstuff[k_oldposition] = player->kartstuff[k_position]; // then the other player taunts.
 | 
						|
			K_RegularVoiceTimers(player); // and you can't for a bit
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_oldposition] > player->kartstuff[k_position]) // Otherwise,
 | 
						|
		{
 | 
						|
			K_PlayOvertakeSound(player->mo); // Say "YOU'RE TOO SLOW!"
 | 
						|
			player->kartstuff[k_oldposition] = player->kartstuff[k_position]; // Restore the old position,
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (player->kartstuff[k_positiondelay])
 | 
						|
		player->kartstuff[k_positiondelay]--;
 | 
						|
 | 
						|
	if ((player->pflags & PF_ATTACKDOWN) && !(cmd->buttons & BT_ATTACK))
 | 
						|
		player->pflags &= ~PF_ATTACKDOWN;
 | 
						|
	else if (cmd->buttons & BT_ATTACK)
 | 
						|
		player->pflags |= PF_ATTACKDOWN;
 | 
						|
 | 
						|
	if (player && player->mo && player->mo->health > 0 && !player->spectator && !(player->exiting || mapreset)
 | 
						|
		&& player->kartstuff[k_spinouttimer] == 0 && player->kartstuff[k_squishedtimer] == 0 && player->kartstuff[k_respawn] == 0)
 | 
						|
	{
 | 
						|
		// First, the really specific, finicky items that function without the item being directly in your item slot.
 | 
						|
		// Karma item dropping
 | 
						|
		if (ATTACK_IS_DOWN && player->kartstuff[k_comebackmode] && !player->kartstuff[k_comebacktimer])
 | 
						|
		{
 | 
						|
			mobj_t *newitem;
 | 
						|
 | 
						|
			if (player->kartstuff[k_comebackmode] == 1)
 | 
						|
			{
 | 
						|
				newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_RANDOMITEM);
 | 
						|
				newitem->threshold = 69; // selected "randomly".
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				newitem = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM);
 | 
						|
				if (player->kartstuff[k_eggmanblame] >= 0
 | 
						|
				&& player->kartstuff[k_eggmanblame] < MAXPLAYERS
 | 
						|
				&& playeringame[player->kartstuff[k_eggmanblame]]
 | 
						|
				&& !players[player->kartstuff[k_eggmanblame]].spectator
 | 
						|
				&& players[player->kartstuff[k_eggmanblame]].mo)
 | 
						|
					P_SetTarget(&newitem->target, players[player->kartstuff[k_eggmanblame]].mo);
 | 
						|
				player->kartstuff[k_eggmanblame] = -1;
 | 
						|
			}
 | 
						|
 | 
						|
			newitem->flags2 = (player->mo->flags2 & MF2_OBJECTFLIP);
 | 
						|
			newitem->fuse = 15*TICRATE; // selected randomly.
 | 
						|
 | 
						|
			player->kartstuff[k_comebackmode] = 0;
 | 
						|
			player->kartstuff[k_comebacktimer] = comebacktime;
 | 
						|
			S_StartSound(player->mo, sfx_s254);
 | 
						|
		}
 | 
						|
		// Eggman Monitor exploding
 | 
						|
		else if (player->kartstuff[k_eggmanexplode])
 | 
						|
		{
 | 
						|
			if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanexplode] <= 3*TICRATE && player->kartstuff[k_eggmanexplode] > 1)
 | 
						|
				player->kartstuff[k_eggmanexplode] = 1;
 | 
						|
		}
 | 
						|
		// Eggman Monitor throwing
 | 
						|
		else if (ATTACK_IS_DOWN && player->kartstuff[k_eggmanheld])
 | 
						|
		{
 | 
						|
			K_ThrowKartItem(player, false, MT_EGGMANITEM, -1, 0);
 | 
						|
			K_PlayAttackTaunt(player->mo);
 | 
						|
			player->kartstuff[k_eggmanheld] = 0;
 | 
						|
			K_UpdateHnextList(player, true);
 | 
						|
		}
 | 
						|
		// Rocket Sneaker
 | 
						|
		else if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
 | 
						|
			&& player->kartstuff[k_rocketsneakertimer] > 1)
 | 
						|
		{
 | 
						|
			K_DoSneaker(player, 2);
 | 
						|
			K_PlayBoostTaunt(player->mo);
 | 
						|
			player->kartstuff[k_rocketsneakertimer] -= 2*TICRATE;
 | 
						|
			if (player->kartstuff[k_rocketsneakertimer] < 1)
 | 
						|
				player->kartstuff[k_rocketsneakertimer] = 1;
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_itemamount] <= 0)
 | 
						|
		{
 | 
						|
			player->kartstuff[k_itemamount] = player->kartstuff[k_itemheld] = 0;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			switch (player->kartstuff[k_itemtype])
 | 
						|
			{
 | 
						|
				case KITEM_SNEAKER:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						K_DoSneaker(player, 1);
 | 
						|
						K_PlayBoostTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_ROCKETSNEAKER:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
 | 
						|
						&& player->kartstuff[k_rocketsneakertimer] == 0)
 | 
						|
					{
 | 
						|
						INT32 moloop;
 | 
						|
						mobj_t *mo = NULL;
 | 
						|
						mobj_t *prev = player->mo;
 | 
						|
 | 
						|
						K_PlayBoostTaunt(player->mo);
 | 
						|
						//player->kartstuff[k_itemheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s3k3a);
 | 
						|
 | 
						|
						//K_DoSneaker(player, 2);
 | 
						|
 | 
						|
						player->kartstuff[k_rocketsneakertimer] = (itemtime*3);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_UpdateHnextList(player, true);
 | 
						|
 | 
						|
						for (moloop = 0; moloop < 2; moloop++)
 | 
						|
						{
 | 
						|
							mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ROCKETSNEAKER);
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->angle = player->mo->angle;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = moloop%2;
 | 
						|
							mo->movedir = mo->lastlook = moloop+1;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&mo->hprev, prev);
 | 
						|
							P_SetTarget(&prev->hnext, mo);
 | 
						|
							prev = mo;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_INVINCIBILITY:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO) // Doesn't hold your item slot hostage normally, so you're free to waste it if you have multiple
 | 
						|
					{
 | 
						|
						if (!player->kartstuff[k_invincibilitytimer])
 | 
						|
						{
 | 
						|
							mobj_t *overlay = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_INVULNFLASH);
 | 
						|
							P_SetTarget(&overlay->target, player->mo);
 | 
						|
							overlay->destscale = player->mo->scale;
 | 
						|
							P_SetScale(overlay, player->mo->scale);
 | 
						|
						}
 | 
						|
						player->kartstuff[k_invincibilitytimer] = itemtime+(2*TICRATE); // 10 seconds
 | 
						|
						P_RestoreMusic(player);
 | 
						|
						if (!P_IsLocalPlayer(player))
 | 
						|
							S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmi : sfx_kinvnc));
 | 
						|
						K_PlayPowerGloatSound(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_BANANA:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						INT32 moloop;
 | 
						|
						mobj_t *mo;
 | 
						|
						mobj_t *prev = player->mo;
 | 
						|
 | 
						|
						//K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s254);
 | 
						|
 | 
						|
						for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
 | 
						|
						{
 | 
						|
							mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_BANANA_SHIELD);
 | 
						|
							if (!mo)
 | 
						|
							{
 | 
						|
								player->kartstuff[k_itemamount] = moloop;
 | 
						|
								break;
 | 
						|
							}
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = player->kartstuff[k_itemamount];
 | 
						|
							mo->movedir = moloop+1;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&mo->hprev, prev);
 | 
						|
							P_SetTarget(&prev->hnext, mo);
 | 
						|
							prev = mo;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Banana x3 thrown
 | 
						|
					{
 | 
						|
						K_ThrowKartItem(player, false, MT_BANANA, -1, 0);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_UpdateHnextList(player, false);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_EGGMAN:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						mobj_t *mo;
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						player->kartstuff[k_eggmanheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s254);
 | 
						|
						mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_EGGMANITEM_SHIELD);
 | 
						|
						if (mo)
 | 
						|
						{
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = 1;
 | 
						|
							mo->movedir = 1;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&player->mo->hnext, mo);
 | 
						|
						}
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_ORBINAUT:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						angle_t newangle;
 | 
						|
						INT32 moloop;
 | 
						|
						mobj_t *mo = NULL;
 | 
						|
						mobj_t *prev = player->mo;
 | 
						|
 | 
						|
						//K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s3k3a);
 | 
						|
 | 
						|
						for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
 | 
						|
						{
 | 
						|
							newangle = FixedAngle(((360/player->kartstuff[k_itemamount])*moloop)*FRACUNIT) + ANGLE_90;
 | 
						|
							mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_ORBINAUT_SHIELD);
 | 
						|
							if (!mo)
 | 
						|
							{
 | 
						|
								player->kartstuff[k_itemamount] = moloop;
 | 
						|
								break;
 | 
						|
							}
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->angle = newangle;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = player->kartstuff[k_itemamount];
 | 
						|
							mo->movedir = mo->lastlook = moloop+1;
 | 
						|
							mo->color = player->skincolor;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&mo->hprev, prev);
 | 
						|
							P_SetTarget(&prev->hnext, mo);
 | 
						|
							prev = mo;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld]) // Orbinaut x3 thrown
 | 
						|
					{
 | 
						|
						K_ThrowKartItem(player, true, MT_ORBINAUT, 1, 0);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_UpdateHnextList(player, false);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_JAWZ:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						angle_t newangle;
 | 
						|
						INT32 moloop;
 | 
						|
						mobj_t *mo = NULL;
 | 
						|
						mobj_t *prev = player->mo;
 | 
						|
 | 
						|
						//K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s3k3a);
 | 
						|
 | 
						|
						for (moloop = 0; moloop < player->kartstuff[k_itemamount]; moloop++)
 | 
						|
						{
 | 
						|
							newangle = FixedAngle(((360/player->kartstuff[k_itemamount])*moloop)*FRACUNIT) + ANGLE_90;
 | 
						|
							mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_JAWZ_SHIELD);
 | 
						|
							if (!mo)
 | 
						|
							{
 | 
						|
								player->kartstuff[k_itemamount] = moloop;
 | 
						|
								break;
 | 
						|
							}
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->angle = newangle;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = player->kartstuff[k_itemamount];
 | 
						|
							mo->movedir = mo->lastlook = moloop+1;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&mo->hprev, prev);
 | 
						|
							P_SetTarget(&prev->hnext, mo);
 | 
						|
							prev = mo;
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Jawz thrown
 | 
						|
					{
 | 
						|
						if (player->kartstuff[k_throwdir] == 1 || player->kartstuff[k_throwdir] == 0)
 | 
						|
							K_ThrowKartItem(player, true, MT_JAWZ, 1, 0);
 | 
						|
						else if (player->kartstuff[k_throwdir] == -1) // Throwing backward gives you a dud that doesn't home in
 | 
						|
							K_ThrowKartItem(player, true, MT_JAWZ_DUD, -1, 0);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_UpdateHnextList(player, false);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_MINE:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						mobj_t *mo;
 | 
						|
						player->kartstuff[k_itemheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s254);
 | 
						|
						mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SSMINE_SHIELD);
 | 
						|
						if (mo)
 | 
						|
						{
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = 1;
 | 
						|
							mo->movedir = 1;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&player->mo->hnext, mo);
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else if (ATTACK_IS_DOWN && player->kartstuff[k_itemheld])
 | 
						|
					{
 | 
						|
						K_ThrowKartItem(player, false, MT_SSMINE, 1, 1);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						player->kartstuff[k_itemheld] = 0;
 | 
						|
						K_UpdateHnextList(player, true);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_BALLHOG:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_ThrowKartItem(player, true, MT_BALLHOG, 1, 0);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_SPB:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_ThrowKartItem(player, true, MT_SPB, 1, 0);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_GROW:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
 | 
						|
						&& player->kartstuff[k_growshrinktimer] <= 0) // Grow holds the item box hostage
 | 
						|
					{
 | 
						|
						K_PlayPowerGloatSound(player->mo);
 | 
						|
						player->mo->scalespeed = mapobjectscale/TICRATE;
 | 
						|
						player->mo->destscale = (3*mapobjectscale)/2;
 | 
						|
						if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
 | 
						|
							player->mo->destscale = (6*player->mo->destscale)/8;
 | 
						|
						player->kartstuff[k_growshrinktimer] = itemtime+(4*TICRATE); // 12 seconds
 | 
						|
						P_RestoreMusic(player);
 | 
						|
						if (!P_IsLocalPlayer(player))
 | 
						|
							S_StartSound(player->mo, (cv_kartinvinsfx.value ? sfx_alarmg : sfx_kgrow));
 | 
						|
						S_StartSound(player->mo, sfx_kc5a);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_SHRINK:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						K_DoShrink(player);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_PlayPowerGloatSound(player->mo);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_THUNDERSHIELD:
 | 
						|
					if (player->kartstuff[k_curshield] != 1)
 | 
						|
					{
 | 
						|
						mobj_t *shield = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_THUNDERSHIELD);
 | 
						|
						P_SetScale(shield, (shield->destscale = (5*shield->destscale)>>2));
 | 
						|
						P_SetTarget(&shield->target, player->mo);
 | 
						|
						S_StartSound(shield, sfx_s3k41);
 | 
						|
						player->kartstuff[k_curshield] = 1;
 | 
						|
					}
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						K_DoThunderShield(player);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_HYUDORO:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						K_DoHyudoroSteal(player); // yes. yes they do.
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_POGOSPRING:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && onground && NO_HYUDORO
 | 
						|
						&& !player->kartstuff[k_pogospring])
 | 
						|
					{
 | 
						|
						K_PlayBoostTaunt(player->mo);
 | 
						|
						K_DoPogoSpring(player->mo, 32<<FRACBITS, 2);
 | 
						|
						player->kartstuff[k_pogospring] = 1;
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_KITCHENSINK:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO)
 | 
						|
					{
 | 
						|
						mobj_t *mo;
 | 
						|
						player->kartstuff[k_itemheld] = 1;
 | 
						|
						S_StartSound(player->mo, sfx_s254);
 | 
						|
						mo = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, MT_SINK_SHIELD);
 | 
						|
						if (mo)
 | 
						|
						{
 | 
						|
							mo->flags |= MF_NOCLIPTHING;
 | 
						|
							mo->threshold = 10;
 | 
						|
							mo->movecount = 1;
 | 
						|
							mo->movedir = 1;
 | 
						|
							P_SetTarget(&mo->target, player->mo);
 | 
						|
							P_SetTarget(&player->mo->hnext, mo);
 | 
						|
						}
 | 
						|
					}
 | 
						|
					else if (ATTACK_IS_DOWN && HOLDING_ITEM && player->kartstuff[k_itemheld]) // Sink thrown
 | 
						|
					{
 | 
						|
						K_ThrowKartItem(player, false, MT_SINK, 1, 2);
 | 
						|
						K_PlayAttackTaunt(player->mo);
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
						player->kartstuff[k_itemheld] = 0;
 | 
						|
						K_UpdateHnextList(player, true);
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				case KITEM_SAD:
 | 
						|
					if (ATTACK_IS_DOWN && !HOLDING_ITEM && NO_HYUDORO
 | 
						|
						&& !player->kartstuff[k_sadtimer])
 | 
						|
					{
 | 
						|
						player->kartstuff[k_sadtimer] = stealtime;
 | 
						|
						player->kartstuff[k_itemamount]--;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		// No more!
 | 
						|
		if (!player->kartstuff[k_itemamount])
 | 
						|
		{
 | 
						|
			player->kartstuff[k_itemheld] = 0;
 | 
						|
			player->kartstuff[k_itemtype] = KITEM_NONE;
 | 
						|
		}
 | 
						|
 | 
						|
		if (player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD)
 | 
						|
			player->kartstuff[k_curshield] = 0;
 | 
						|
 | 
						|
		if (player->kartstuff[k_itemtype] == KITEM_SPB
 | 
						|
			|| player->kartstuff[k_itemtype] == KITEM_SHRINK
 | 
						|
			|| player->kartstuff[k_growshrinktimer] < 0)
 | 
						|
			indirectitemcooldown = 20*TICRATE;
 | 
						|
 | 
						|
		if (player->kartstuff[k_hyudorotimer] > 0)
 | 
						|
		{
 | 
						|
			if (splitscreen)
 | 
						|
			{
 | 
						|
				if (leveltime & 1)
 | 
						|
					player->mo->flags2 |= MF2_DONTDRAW;
 | 
						|
				else
 | 
						|
					player->mo->flags2 &= ~MF2_DONTDRAW;
 | 
						|
 | 
						|
				if (player->kartstuff[k_hyudorotimer] >= (1*TICRATE/2) && player->kartstuff[k_hyudorotimer] <= hyudorotime-(1*TICRATE/2))
 | 
						|
				{
 | 
						|
					if (player == &players[secondarydisplayplayer])
 | 
						|
						player->mo->eflags |= MFE_DRAWONLYFORP2;
 | 
						|
					else if (player == &players[thirddisplayplayer] && splitscreen > 1)
 | 
						|
						player->mo->eflags |= MFE_DRAWONLYFORP3;
 | 
						|
					else if (player == &players[fourthdisplayplayer] && splitscreen > 2)
 | 
						|
						player->mo->eflags |= MFE_DRAWONLYFORP4;
 | 
						|
					else if (player == &players[consoleplayer])
 | 
						|
						player->mo->eflags |= MFE_DRAWONLYFORP1;
 | 
						|
					else
 | 
						|
						player->mo->flags2 |= MF2_DONTDRAW;
 | 
						|
				}
 | 
						|
				else
 | 
						|
					player->mo->eflags &= ~(MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				if (player == &players[displayplayer]
 | 
						|
					|| (player != &players[displayplayer] && (player->kartstuff[k_hyudorotimer] < (1*TICRATE/2) || player->kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2))))
 | 
						|
				{
 | 
						|
					if (leveltime & 1)
 | 
						|
						player->mo->flags2 |= MF2_DONTDRAW;
 | 
						|
					else
 | 
						|
						player->mo->flags2 &= ~MF2_DONTDRAW;
 | 
						|
				}
 | 
						|
				else
 | 
						|
					player->mo->flags2 |= MF2_DONTDRAW;
 | 
						|
			}
 | 
						|
 | 
						|
			player->powers[pw_flashing] = player->kartstuff[k_hyudorotimer]; // We'll do this for now, let's people know about the invisible people through subtle hints
 | 
						|
		}
 | 
						|
		else if (player->kartstuff[k_hyudorotimer] == 0)
 | 
						|
		{
 | 
						|
			player->mo->flags2 &= ~MF2_DONTDRAW;
 | 
						|
			player->mo->eflags &= ~(MFE_DRAWONLYFORP1|MFE_DRAWONLYFORP2|MFE_DRAWONLYFORP3|MFE_DRAWONLYFORP4);
 | 
						|
		}
 | 
						|
 | 
						|
		if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0) // dead in match? you da bomb
 | 
						|
		{
 | 
						|
			K_DropItems(player); //K_StripItems(player);
 | 
						|
			K_StripOther(player);
 | 
						|
			player->mo->flags2 |= MF2_SHADOW;
 | 
						|
			player->powers[pw_flashing] = player->kartstuff[k_comebacktimer];
 | 
						|
		}
 | 
						|
		else if (G_RaceGametype() || player->kartstuff[k_bumper] > 0)
 | 
						|
		{
 | 
						|
			player->mo->flags2 &= ~MF2_SHADOW;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Friction
 | 
						|
	if (player->speed > 0 && cmd->forwardmove == 0 && player->mo->friction == 59392)
 | 
						|
		player->mo->friction += 4608;
 | 
						|
	if (player->speed > 0 && cmd->forwardmove < 0 && player->mo->friction == 59392)
 | 
						|
		player->mo->friction += 1608;
 | 
						|
	if (G_BattleGametype() && player->kartstuff[k_bumper] <= 0)
 | 
						|
	{
 | 
						|
		player->mo->friction += 1228;
 | 
						|
 | 
						|
		if (player->mo->friction > FRACUNIT)
 | 
						|
			player->mo->friction = FRACUNIT;
 | 
						|
		if (player->mo->friction < 0)
 | 
						|
			player->mo->friction = 0;
 | 
						|
 | 
						|
		player->mo->movefactor = FixedDiv(ORIG_FRICTION, player->mo->friction);
 | 
						|
 | 
						|
		if (player->mo->movefactor < FRACUNIT)
 | 
						|
			player->mo->movefactor = 19*player->mo->movefactor - 18*FRACUNIT;
 | 
						|
		else
 | 
						|
			player->mo->movefactor = FRACUNIT; //player->mo->movefactor = ((player->mo->friction - 0xDB34)*(0xA))/0x80;
 | 
						|
 | 
						|
		if (player->mo->movefactor < 32)
 | 
						|
			player->mo->movefactor = 32;
 | 
						|
	}
 | 
						|
	if (player->kartstuff[k_spinouttimer] && player->kartstuff[k_wipeoutslow])
 | 
						|
	{
 | 
						|
		player->mo->friction -= FixedMul(1228, player->kartstuff[k_offroad]);
 | 
						|
		if (player->kartstuff[k_wipeoutslow] == 1)
 | 
						|
			player->mo->friction -= 4912;
 | 
						|
	}
 | 
						|
 | 
						|
	K_KartDrift(player, onground);
 | 
						|
 | 
						|
	// Quick Turning
 | 
						|
	// You can't turn your kart when you're not moving.
 | 
						|
	// So now it's time to burn some rubber!
 | 
						|
	if (player->speed < 2 && leveltime > starttime && cmd->buttons & BT_ACCELERATE && cmd->buttons & BT_BRAKE && cmd->driftturn != 0)
 | 
						|
	{
 | 
						|
		if (leveltime % 8 == 0)
 | 
						|
			S_StartSound(player->mo, sfx_s224);
 | 
						|
	}
 | 
						|
 | 
						|
	// Squishing
 | 
						|
	// If a Grow player or a sector crushes you, get flattened instead of being killed.
 | 
						|
 | 
						|
	if (player->kartstuff[k_squishedtimer] <= 0)
 | 
						|
	{
 | 
						|
		player->mo->flags &= ~MF_NOCLIP;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		player->mo->flags |= MF_NOCLIP;
 | 
						|
		player->mo->momx = 0;
 | 
						|
		player->mo->momy = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	// Play the starting countdown sounds
 | 
						|
	if (player == &players[displayplayer]) // Don't play louder in splitscreen
 | 
						|
	{
 | 
						|
		if ((leveltime == starttime-(3*TICRATE)) || (leveltime == starttime-(2*TICRATE)) || (leveltime == starttime-TICRATE))
 | 
						|
			S_StartSound(NULL, sfx_s3ka7);
 | 
						|
		if (leveltime == starttime)
 | 
						|
		{
 | 
						|
			S_StartSound(NULL, sfx_s3kad);
 | 
						|
			S_StopMusic(); // The GO! sound stops the level start ambience
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Start charging once you're given the opportunity.
 | 
						|
	if (leveltime >= starttime-(2*TICRATE) && leveltime <= starttime)
 | 
						|
	{
 | 
						|
		if (cmd->buttons & BT_ACCELERATE)
 | 
						|
			player->kartstuff[k_boostcharge]++;
 | 
						|
		else
 | 
						|
			player->kartstuff[k_boostcharge] = 0;
 | 
						|
	}
 | 
						|
 | 
						|
	// Increase your size while charging your engine.
 | 
						|
	if (leveltime < starttime+10)
 | 
						|
	{
 | 
						|
		player->mo->scalespeed = mapobjectscale/12;
 | 
						|
		player->mo->destscale = mapobjectscale + (player->kartstuff[k_boostcharge]*131);
 | 
						|
		if (cv_kartdebugshrink.value && !modeattacking && !player->bot)
 | 
						|
			player->mo->destscale = (6*player->mo->destscale)/8;
 | 
						|
	}
 | 
						|
 | 
						|
	// Determine the outcome of your charge.
 | 
						|
	if (leveltime > starttime && player->kartstuff[k_boostcharge])
 | 
						|
	{
 | 
						|
		// Not even trying?
 | 
						|
		if (player->kartstuff[k_boostcharge] < 35)
 | 
						|
		{
 | 
						|
			if (player->kartstuff[k_boostcharge] > 17)
 | 
						|
				S_StartSound(player->mo, sfx_cdfm00); // chosen instead of a conventional skid because it's more engine-like
 | 
						|
		}
 | 
						|
		// Get an instant boost!
 | 
						|
		else if (player->kartstuff[k_boostcharge] <= 50)
 | 
						|
		{
 | 
						|
			player->kartstuff[k_startboost] = (50-player->kartstuff[k_boostcharge])+20;
 | 
						|
 | 
						|
			if (player->kartstuff[k_boostcharge] <= 36)
 | 
						|
			{
 | 
						|
				player->kartstuff[k_startboost] = 0;
 | 
						|
				K_DoSneaker(player, 0);
 | 
						|
				player->kartstuff[k_sneakertimer] = 70; // PERFECT BOOST!!
 | 
						|
 | 
						|
				if (!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) // Let everyone hear this one
 | 
						|
					S_StartSound(player->mo, sfx_s25f);
 | 
						|
			}
 | 
						|
			else
 | 
						|
			{
 | 
						|
				K_SpawnDashDustRelease(player); // already handled for perfect boosts by K_DoSneaker
 | 
						|
				if ((!player->kartstuff[k_floorboost] || player->kartstuff[k_floorboost] == 3) && P_IsLocalPlayer(player))
 | 
						|
				{
 | 
						|
					if (player->kartstuff[k_boostcharge] <= 40)
 | 
						|
						S_StartSound(player->mo, sfx_cdfm01); // You were almost there!
 | 
						|
					else
 | 
						|
						S_StartSound(player->mo, sfx_s23c); // Nope, better luck next time.
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
		// You overcharged your engine? Those things are expensive!!!
 | 
						|
		else if (player->kartstuff[k_boostcharge] > 50)
 | 
						|
		{
 | 
						|
			player->powers[pw_nocontrol] = 40;
 | 
						|
			//S_StartSound(player->mo, sfx_kc34);
 | 
						|
			S_StartSound(player->mo, sfx_s3k83);
 | 
						|
			player->pflags |= PF_SKIDDOWN; // cheeky pflag reuse
 | 
						|
		}
 | 
						|
 | 
						|
		player->kartstuff[k_boostcharge] = 0;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void K_CalculateBattleWanted(void)
 | 
						|
{
 | 
						|
	UINT8 numingame = 0, numplaying = 0, numwanted = 0;
 | 
						|
	SINT8 bestbumperplayer = -1, bestbumper = -1;
 | 
						|
	SINT8 camppos[MAXPLAYERS]; // who is the biggest camper
 | 
						|
	UINT8 ties = 0, nextcamppos = 0;
 | 
						|
	boolean setbumper = false;
 | 
						|
	UINT8 i, j;
 | 
						|
 | 
						|
	if (!G_BattleGametype())
 | 
						|
	{
 | 
						|
		for (i = 0; i < 4; i++)
 | 
						|
			battlewanted[i] = -1;
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	wantedcalcdelay = wantedfrequency;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
		camppos[i] = -1; // initialize
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		UINT8 position = 1;
 | 
						|
 | 
						|
		if (!playeringame[i] || players[i].spectator) // Not playing
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (players[i].exiting) // We're done, don't calculate.
 | 
						|
			return;
 | 
						|
 | 
						|
		numplaying++;
 | 
						|
 | 
						|
		if (players[i].kartstuff[k_bumper] <= 0) // Not alive, so don't do anything else
 | 
						|
			continue;
 | 
						|
 | 
						|
		numingame++;
 | 
						|
 | 
						|
		if (bestbumper == -1 || players[i].kartstuff[k_bumper] > bestbumper)
 | 
						|
		{
 | 
						|
			bestbumper = players[i].kartstuff[k_bumper];
 | 
						|
			bestbumperplayer = i;
 | 
						|
		}
 | 
						|
		else if (players[i].kartstuff[k_bumper] == bestbumper)
 | 
						|
			bestbumperplayer = -1; // Tie, no one has best bumper.
 | 
						|
 | 
						|
		for (j = 0; j < MAXPLAYERS; j++)
 | 
						|
		{
 | 
						|
			if (!playeringame[j] || players[j].spectator)
 | 
						|
				continue;
 | 
						|
			if (players[j].kartstuff[k_bumper] <= 0)
 | 
						|
				continue;
 | 
						|
			if (j == i)
 | 
						|
				continue;
 | 
						|
			if (players[j].kartstuff[k_wanted] == players[i].kartstuff[k_wanted] && players[j].marescore > players[i].marescore)
 | 
						|
				position++;
 | 
						|
			else if (players[j].kartstuff[k_wanted] > players[i].kartstuff[k_wanted])
 | 
						|
				position++;
 | 
						|
		}
 | 
						|
 | 
						|
		position--; // Make zero based
 | 
						|
 | 
						|
		while (camppos[position] != -1) // Port priority!
 | 
						|
			position++;
 | 
						|
 | 
						|
		camppos[position] = i;
 | 
						|
	}
 | 
						|
 | 
						|
	if (numplaying <= 2 || (numingame <= 2 && bestbumper == 1)) // In 1v1s then there's no need for WANTED. In bigger netgames, don't show anyone as WANTED when they're equally matched.
 | 
						|
		numwanted = 0;
 | 
						|
	else
 | 
						|
		numwanted = min(4, 1 + ((numingame-2) / 4));
 | 
						|
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		if (i+1 > numwanted) // Not enough players for this slot to be wanted!
 | 
						|
			battlewanted[i] = -1;
 | 
						|
		else if (bestbumperplayer != -1 && !setbumper) // If there's a player who has an untied bumper lead over everyone else, they are the first to be wanted.
 | 
						|
		{
 | 
						|
			battlewanted[i] = bestbumperplayer;
 | 
						|
			setbumper = true; // Don't set twice
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			// Don't accidentally set the same player, if the bestbumperplayer is also a huge camper.
 | 
						|
			while (bestbumperplayer != -1 && camppos[nextcamppos] != -1
 | 
						|
				&& bestbumperplayer == camppos[nextcamppos])
 | 
						|
				nextcamppos++;
 | 
						|
 | 
						|
			// Do not add *any* more people if there's too many times that are tied with others.
 | 
						|
			// This could theoretically happen very easily if people don't hit each other for a while after the start of a match.
 | 
						|
			// (I will be sincerely impressed if more than 2 people tie after people start hitting each other though)
 | 
						|
 | 
						|
			if (camppos[nextcamppos] == -1 // Out of entries
 | 
						|
				|| ties >= (numwanted-i)) // Already counted ties
 | 
						|
			{
 | 
						|
				battlewanted[i] = -1;
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			if (ties < (numwanted-i))
 | 
						|
			{
 | 
						|
				ties = 0; // Reset
 | 
						|
				for (j = 0; j < 2; j++)
 | 
						|
				{
 | 
						|
					if (camppos[nextcamppos+(j+1)] == -1) // Nothing beyond, cancel
 | 
						|
						break;
 | 
						|
					if (players[camppos[nextcamppos]].kartstuff[k_wanted] == players[camppos[nextcamppos+(j+1)]].kartstuff[k_wanted])
 | 
						|
						ties++;
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (ties < (numwanted-i)) // Is it still low enough after counting?
 | 
						|
			{
 | 
						|
				battlewanted[i] = camppos[nextcamppos];
 | 
						|
				nextcamppos++;
 | 
						|
			}
 | 
						|
			else
 | 
						|
				battlewanted[i] = -1;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void K_CheckBumpers(void)
 | 
						|
{
 | 
						|
	UINT8 i;
 | 
						|
	UINT8 numingame = 0;
 | 
						|
	SINT8 winnernum = -1;
 | 
						|
	INT32 winnerscoreadd = 0;
 | 
						|
 | 
						|
	if (!multiplayer)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (!G_BattleGametype())
 | 
						|
		return;
 | 
						|
 | 
						|
	if (gameaction == ga_completed)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator) // not even in-game
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (players[i].exiting) // we're already exiting! stop!
 | 
						|
			return;
 | 
						|
 | 
						|
		numingame++;
 | 
						|
		winnerscoreadd += players[i].marescore;
 | 
						|
 | 
						|
		if (players[i].kartstuff[k_bumper] <= 0) // if you don't have any bumpers, you're probably not a winner
 | 
						|
			continue;
 | 
						|
		else if (winnernum > -1) // TWO winners? that's dumb :V
 | 
						|
			return;
 | 
						|
 | 
						|
		winnernum = i;
 | 
						|
		winnerscoreadd -= players[i].marescore;
 | 
						|
	}
 | 
						|
 | 
						|
	if (numingame <= 1)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (winnernum > -1 && playeringame[winnernum])
 | 
						|
	{
 | 
						|
		players[winnernum].marescore += winnerscoreadd;
 | 
						|
		CONS_Printf(M_GetText("%s recieved %d point%s for winning!\n"), player_names[winnernum], winnerscoreadd, (winnerscoreadd == 1 ? "" : "s"));
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++) // This can't go in the earlier loop because winning adds points
 | 
						|
		K_KartUpdatePosition(&players[i]);
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++) // and it can't be merged with this loop because it needs to be all updated before exiting... multi-loops suck...
 | 
						|
		P_DoPlayerExit(&players[i]);
 | 
						|
}
 | 
						|
 | 
						|
void K_CheckSpectateStatus(void)
 | 
						|
{
 | 
						|
	UINT8 respawnlist[MAXPLAYERS];
 | 
						|
	UINT8 i, numingame = 0, numjoiners = 0;
 | 
						|
 | 
						|
	if (!cv_allowteamchange.value) return;
 | 
						|
 | 
						|
	// Get the number of players in game, and the players to be de-spectated.
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i])
 | 
						|
			continue;
 | 
						|
 | 
						|
		if (!players[i].spectator)
 | 
						|
		{
 | 
						|
			numingame++;
 | 
						|
			if (gamestate != GS_LEVEL) // Allow if you're not in a level
 | 
						|
                continue;
 | 
						|
			if (players[i].exiting) // DON'T allow if anyone's exiting
 | 
						|
				return;
 | 
						|
			if (numingame < 2 || leveltime < starttime || mapreset) // Allow if the match hasn't started yet
 | 
						|
                continue;
 | 
						|
			if (leveltime > (starttime + 20*TICRATE)) // DON'T allow if the match is 20 seconds in
 | 
						|
                return;
 | 
						|
            if (G_RaceGametype() && players[i].laps) // DON'T allow if the race is at 2 laps
 | 
						|
                return;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		else if (!(players[i].pflags & PF_WANTSTOJOIN))
 | 
						|
			continue;
 | 
						|
 | 
						|
		respawnlist[numjoiners++] = i;
 | 
						|
	}
 | 
						|
 | 
						|
	// literally zero point in going any further if nobody is joining
 | 
						|
	if (!numjoiners)
 | 
						|
		return;
 | 
						|
 | 
						|
	// Reset the match if you're in an empty server
 | 
						|
	if (!mapreset && gamestate == GS_LEVEL && leveltime >= starttime && (numingame < 2 && numingame+numjoiners >= 2))
 | 
						|
	{
 | 
						|
		S_ChangeMusicInternal("chalng", false); // COME ON
 | 
						|
		mapreset = 3*TICRATE; // Even though only the server uses this for game logic, set for everyone for HUD in the future
 | 
						|
	}
 | 
						|
 | 
						|
	// Finally, we can de-spectate everyone!
 | 
						|
	for (i = 0; i < numjoiners; i++)
 | 
						|
		P_SpectatorJoinGame(&players[respawnlist[i]]);
 | 
						|
}
 | 
						|
 | 
						|
//}
 | 
						|
 | 
						|
//{ SRB2kart HUD Code
 | 
						|
 | 
						|
#define NUMPOSNUMS 10
 | 
						|
#define NUMPOSFRAMES 7 // White, three blues, three reds
 | 
						|
#define NUMWINFRAMES 6 // Red, yellow, green, cyan, blue, purple
 | 
						|
 | 
						|
//{ 	Patch Definitions
 | 
						|
static patch_t *kp_nodraw;
 | 
						|
 | 
						|
static patch_t *kp_timesticker;
 | 
						|
static patch_t *kp_timestickerwide;
 | 
						|
static patch_t *kp_lapsticker;
 | 
						|
static patch_t *kp_lapstickerwide;
 | 
						|
static patch_t *kp_lapstickernarrow;
 | 
						|
static patch_t *kp_splitlapflag;
 | 
						|
static patch_t *kp_bumpersticker;
 | 
						|
static patch_t *kp_bumperstickerwide;
 | 
						|
static patch_t *kp_karmasticker;
 | 
						|
static patch_t *kp_splitkarmabomb;
 | 
						|
static patch_t *kp_timeoutsticker;
 | 
						|
 | 
						|
static patch_t *kp_startcountdown[16];
 | 
						|
static patch_t *kp_racefinish[6];
 | 
						|
 | 
						|
static patch_t *kp_positionnum[NUMPOSNUMS][NUMPOSFRAMES];
 | 
						|
static patch_t *kp_winnernum[NUMPOSFRAMES];
 | 
						|
 | 
						|
static patch_t *kp_facenum[MAXPLAYERS+1];
 | 
						|
static patch_t *kp_facehighlight[8];
 | 
						|
 | 
						|
static patch_t *kp_rankbumper;
 | 
						|
static patch_t *kp_tinybumper[2];
 | 
						|
static patch_t *kp_ranknobumpers;
 | 
						|
 | 
						|
static patch_t *kp_battlewin;
 | 
						|
static patch_t *kp_battlecool;
 | 
						|
static patch_t *kp_battlelose;
 | 
						|
static patch_t *kp_battlewait;
 | 
						|
static patch_t *kp_battleinfo;
 | 
						|
static patch_t *kp_wanted;
 | 
						|
 | 
						|
static patch_t *kp_itembg[4];
 | 
						|
static patch_t *kp_itemtimer[2];
 | 
						|
static patch_t *kp_itemmulsticker[2];
 | 
						|
static patch_t *kp_itemx;
 | 
						|
 | 
						|
static patch_t *kp_sneaker[2];
 | 
						|
static patch_t *kp_rocketsneaker[2];
 | 
						|
static patch_t *kp_invincibility[13];
 | 
						|
static patch_t *kp_banana[2];
 | 
						|
static patch_t *kp_eggman[2];
 | 
						|
static patch_t *kp_orbinaut[5];
 | 
						|
static patch_t *kp_jawz[2];
 | 
						|
static patch_t *kp_mine[2];
 | 
						|
static patch_t *kp_ballhog[2];
 | 
						|
static patch_t *kp_selfpropelledbomb[2];
 | 
						|
static patch_t *kp_grow[2];
 | 
						|
static patch_t *kp_shrink[2];
 | 
						|
static patch_t *kp_thundershield[2];
 | 
						|
static patch_t *kp_hyudoro[2];
 | 
						|
static patch_t *kp_pogospring[2];
 | 
						|
static patch_t *kp_kitchensink[2];
 | 
						|
static patch_t *kp_sadface[2];
 | 
						|
 | 
						|
static patch_t *kp_check[6];
 | 
						|
 | 
						|
static patch_t *kp_eggnum[4];
 | 
						|
 | 
						|
static patch_t *kp_fpview[3];
 | 
						|
static patch_t *kp_inputwheel[5];
 | 
						|
 | 
						|
static patch_t *kp_challenger[25];
 | 
						|
 | 
						|
static patch_t *kp_lapanim_lap[7];
 | 
						|
static patch_t *kp_lapanim_final[11];
 | 
						|
static patch_t *kp_lapanim_number[10][3];
 | 
						|
static patch_t *kp_lapanim_emblem[2];
 | 
						|
static patch_t *kp_lapanim_hand[3];
 | 
						|
 | 
						|
static patch_t *kp_yougotem;
 | 
						|
 | 
						|
void K_LoadKartHUDGraphics(void)
 | 
						|
{
 | 
						|
	INT32 i, j;
 | 
						|
	char buffer[9];
 | 
						|
 | 
						|
	// Null Stuff
 | 
						|
	kp_nodraw = 				W_CachePatchName("K_TRNULL", PU_HUDGFX);
 | 
						|
 | 
						|
	// Stickers
 | 
						|
	kp_timesticker = 			W_CachePatchName("K_STTIME", PU_HUDGFX);
 | 
						|
	kp_timestickerwide = 		W_CachePatchName("K_STTIMW", PU_HUDGFX);
 | 
						|
	kp_lapsticker = 			W_CachePatchName("K_STLAPS", PU_HUDGFX);
 | 
						|
	kp_lapstickerwide = 		W_CachePatchName("K_STLAPW", PU_HUDGFX);
 | 
						|
	kp_lapstickernarrow = 		W_CachePatchName("K_STLAPN", PU_HUDGFX);
 | 
						|
	kp_splitlapflag = 			W_CachePatchName("K_SPTLAP", PU_HUDGFX);
 | 
						|
	kp_bumpersticker = 			W_CachePatchName("K_STBALN", PU_HUDGFX);
 | 
						|
	kp_bumperstickerwide = 		W_CachePatchName("K_STBALW", PU_HUDGFX);
 | 
						|
	kp_karmasticker = 			W_CachePatchName("K_STKARM", PU_HUDGFX);
 | 
						|
	kp_splitkarmabomb = 		W_CachePatchName("K_SPTKRM", PU_HUDGFX);
 | 
						|
	kp_timeoutsticker = 		W_CachePatchName("K_STTOUT", PU_HUDGFX);
 | 
						|
 | 
						|
	// Starting countdown
 | 
						|
	kp_startcountdown[0] = 		W_CachePatchName("K_CNT3A", PU_HUDGFX);
 | 
						|
	kp_startcountdown[1] = 		W_CachePatchName("K_CNT2A", PU_HUDGFX);
 | 
						|
	kp_startcountdown[2] = 		W_CachePatchName("K_CNT1A", PU_HUDGFX);
 | 
						|
	kp_startcountdown[3] = 		W_CachePatchName("K_CNTGOA", PU_HUDGFX);
 | 
						|
	kp_startcountdown[4] = 		W_CachePatchName("K_CNT3B", PU_HUDGFX);
 | 
						|
	kp_startcountdown[5] = 		W_CachePatchName("K_CNT2B", PU_HUDGFX);
 | 
						|
	kp_startcountdown[6] = 		W_CachePatchName("K_CNT1B", PU_HUDGFX);
 | 
						|
	kp_startcountdown[7] = 		W_CachePatchName("K_CNTGOB", PU_HUDGFX);
 | 
						|
	// Splitscreen
 | 
						|
	kp_startcountdown[8] = 		W_CachePatchName("K_SMC3A", PU_HUDGFX);
 | 
						|
	kp_startcountdown[9] = 		W_CachePatchName("K_SMC2A", PU_HUDGFX);
 | 
						|
	kp_startcountdown[10] = 	W_CachePatchName("K_SMC1A", PU_HUDGFX);
 | 
						|
	kp_startcountdown[11] = 	W_CachePatchName("K_SMCGOA", PU_HUDGFX);
 | 
						|
	kp_startcountdown[12] = 	W_CachePatchName("K_SMC3B", PU_HUDGFX);
 | 
						|
	kp_startcountdown[13] = 	W_CachePatchName("K_SMC2B", PU_HUDGFX);
 | 
						|
	kp_startcountdown[14] = 	W_CachePatchName("K_SMC1B", PU_HUDGFX);
 | 
						|
	kp_startcountdown[15] = 	W_CachePatchName("K_SMCGOB", PU_HUDGFX);
 | 
						|
 | 
						|
	// Finish
 | 
						|
	kp_racefinish[0] = 			W_CachePatchName("K_FINA", PU_HUDGFX);
 | 
						|
	kp_racefinish[1] = 			W_CachePatchName("K_FINB", PU_HUDGFX);
 | 
						|
	// Splitscreen
 | 
						|
	kp_racefinish[2] = 			W_CachePatchName("K_SMFINA", PU_HUDGFX);
 | 
						|
	kp_racefinish[3] = 			W_CachePatchName("K_SMFINB", PU_HUDGFX);
 | 
						|
	// 2P splitscreen
 | 
						|
	kp_racefinish[4] = 			W_CachePatchName("K_2PFINA", PU_HUDGFX);
 | 
						|
	kp_racefinish[5] = 			W_CachePatchName("K_2PFINB", PU_HUDGFX);
 | 
						|
 | 
						|
	// Position numbers
 | 
						|
	sprintf(buffer, "K_POSNxx");
 | 
						|
	for (i = 0; i < NUMPOSNUMS; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+i;
 | 
						|
		for (j = 0; j < NUMPOSFRAMES; j++)
 | 
						|
		{
 | 
						|
			//sprintf(buffer, "K_POSN%d%d", i, j);
 | 
						|
			buffer[7] = '0'+j;
 | 
						|
			kp_positionnum[i][j] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "K_POSNWx");
 | 
						|
	for (i = 0; i < NUMWINFRAMES; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '0'+i;
 | 
						|
		kp_winnernum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "OPPRNKxx");
 | 
						|
	for (i = 0; i <= MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+(i/10);
 | 
						|
		buffer[7] = '0'+(i%10);
 | 
						|
		kp_facenum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "K_CHILIx");
 | 
						|
	for (i = 0; i < 8; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '0'+(i+1);
 | 
						|
		kp_facehighlight[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	// Extra ranking icons
 | 
						|
	kp_rankbumper =				W_CachePatchName("K_BLNICO", PU_HUDGFX);
 | 
						|
	kp_tinybumper[0] =			W_CachePatchName("K_BLNA", PU_HUDGFX);
 | 
						|
	kp_tinybumper[1] =			W_CachePatchName("K_BLNB", PU_HUDGFX);
 | 
						|
	kp_ranknobumpers =			W_CachePatchName("K_NOBLNS", PU_HUDGFX);
 | 
						|
 | 
						|
	// Battle graphics
 | 
						|
	kp_battlewin = 				W_CachePatchName("K_BWIN", PU_HUDGFX);
 | 
						|
	kp_battlecool = 			W_CachePatchName("K_BCOOL", PU_HUDGFX);
 | 
						|
	kp_battlelose = 			W_CachePatchName("K_BLOSE", PU_HUDGFX);
 | 
						|
	kp_battlewait = 			W_CachePatchName("K_BWAIT", PU_HUDGFX);
 | 
						|
	kp_battleinfo = 			W_CachePatchName("K_BINFO", PU_HUDGFX);
 | 
						|
	kp_wanted = 				W_CachePatchName("K_WANTED", PU_HUDGFX);
 | 
						|
 | 
						|
	// Kart Item Windows
 | 
						|
	kp_itembg[0] = 				W_CachePatchName("K_ITBG", PU_HUDGFX);
 | 
						|
	kp_itembg[1] = 				W_CachePatchName("K_ITBGD", PU_HUDGFX);
 | 
						|
	kp_itemtimer[0] = 			W_CachePatchName("K_ITIMER", PU_HUDGFX);
 | 
						|
	kp_itemmulsticker[0] = 		W_CachePatchName("K_ITMUL", PU_HUDGFX);
 | 
						|
	kp_itemx = 					W_CachePatchName("K_ITX", PU_HUDGFX);
 | 
						|
 | 
						|
	kp_sneaker[0] =				W_CachePatchName("K_ITSHOE", PU_HUDGFX);
 | 
						|
	kp_rocketsneaker[0] =		W_CachePatchName("K_ITRSHE", PU_HUDGFX);
 | 
						|
 | 
						|
	sprintf(buffer, "K_ITINVx");
 | 
						|
	for (i = 0; i < 7; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '1'+i;
 | 
						|
		kp_invincibility[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
	kp_banana[0] =				W_CachePatchName("K_ITBANA", PU_HUDGFX);
 | 
						|
	kp_eggman[0] =				W_CachePatchName("K_ITEGGM", PU_HUDGFX);
 | 
						|
	sprintf(buffer, "K_ITORBx");
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '1'+i;
 | 
						|
		kp_orbinaut[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
	kp_jawz[0] =				W_CachePatchName("K_ITJAWZ", PU_HUDGFX);
 | 
						|
	kp_mine[0] =				W_CachePatchName("K_ITMINE", PU_HUDGFX);
 | 
						|
	kp_ballhog[0] =				W_CachePatchName("K_ITBHOG", PU_HUDGFX);
 | 
						|
	kp_selfpropelledbomb[0] =	W_CachePatchName("K_ITSPB", PU_HUDGFX);
 | 
						|
	kp_grow[0] =				W_CachePatchName("K_ITGROW", PU_HUDGFX);
 | 
						|
	kp_shrink[0] =				W_CachePatchName("K_ITSHRK", PU_HUDGFX);
 | 
						|
	kp_thundershield[0] =		W_CachePatchName("K_ITTHNS", PU_HUDGFX);
 | 
						|
	kp_hyudoro[0] = 			W_CachePatchName("K_ITHYUD", PU_HUDGFX);
 | 
						|
	kp_pogospring[0] = 			W_CachePatchName("K_ITPOGO", PU_HUDGFX);
 | 
						|
	kp_kitchensink[0] = 		W_CachePatchName("K_ITSINK", PU_HUDGFX);
 | 
						|
	kp_sadface[0] = 			W_CachePatchName("K_ITSAD", PU_HUDGFX);
 | 
						|
 | 
						|
	// Splitscreen
 | 
						|
	kp_itembg[2] = 				W_CachePatchName("K_ISBG", PU_HUDGFX);
 | 
						|
	kp_itembg[3] = 				W_CachePatchName("K_ISBGD", PU_HUDGFX);
 | 
						|
	kp_itemtimer[1] = 			W_CachePatchName("K_ISIMER", PU_HUDGFX);
 | 
						|
	kp_itemmulsticker[1] = 		W_CachePatchName("K_ISMUL", PU_HUDGFX);
 | 
						|
 | 
						|
	kp_sneaker[1] =				W_CachePatchName("K_ISSHOE", PU_HUDGFX);
 | 
						|
	kp_rocketsneaker[1] =		W_CachePatchName("K_ISRSHE", PU_HUDGFX);
 | 
						|
	sprintf(buffer, "K_ISINVx");
 | 
						|
	for (i = 0; i < 6; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '1'+i;
 | 
						|
		kp_invincibility[i+7] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
	kp_banana[1] =				W_CachePatchName("K_ISBANA", PU_HUDGFX);
 | 
						|
	kp_eggman[1] =				W_CachePatchName("K_ISEGGM", PU_HUDGFX);
 | 
						|
	kp_orbinaut[4] =			W_CachePatchName("K_ISORBN", PU_HUDGFX);
 | 
						|
	kp_jawz[1] =				W_CachePatchName("K_ISJAWZ", PU_HUDGFX);
 | 
						|
	kp_mine[1] =				W_CachePatchName("K_ISMINE", PU_HUDGFX);
 | 
						|
	kp_ballhog[1] =				W_CachePatchName("K_ISBHOG", PU_HUDGFX);
 | 
						|
	kp_selfpropelledbomb[1] =	W_CachePatchName("K_ISSPB", PU_HUDGFX);
 | 
						|
	kp_grow[1] =				W_CachePatchName("K_ISGROW", PU_HUDGFX);
 | 
						|
	kp_shrink[1] =				W_CachePatchName("K_ISSHRK", PU_HUDGFX);
 | 
						|
	kp_thundershield[1] =		W_CachePatchName("K_ISTHNS", PU_HUDGFX);
 | 
						|
	kp_hyudoro[1] = 			W_CachePatchName("K_ISHYUD", PU_HUDGFX);
 | 
						|
	kp_pogospring[1] = 			W_CachePatchName("K_ISPOGO", PU_HUDGFX);
 | 
						|
	kp_kitchensink[1] = 		W_CachePatchName("K_ISSINK", PU_HUDGFX);
 | 
						|
	kp_sadface[1] = 			W_CachePatchName("K_ISSAD", PU_HUDGFX);
 | 
						|
 | 
						|
	// CHECK indicators
 | 
						|
	sprintf(buffer, "K_CHECKx");
 | 
						|
	for (i = 0; i < 6; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '1'+i;
 | 
						|
		kp_check[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	// Eggman warning numbers
 | 
						|
	sprintf(buffer, "K_EGGNx");
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+i;
 | 
						|
		kp_eggnum[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	// First person mode
 | 
						|
	kp_fpview[0] = 				W_CachePatchName("VIEWA0", PU_HUDGFX);
 | 
						|
	kp_fpview[1] =				W_CachePatchName("VIEWB0D0", PU_HUDGFX);
 | 
						|
	kp_fpview[2] = 				W_CachePatchName("VIEWC0E0", PU_HUDGFX);
 | 
						|
 | 
						|
	// Input UI Wheel
 | 
						|
	sprintf(buffer, "K_WHEELx");
 | 
						|
	for (i = 0; i < 5; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '0'+i;
 | 
						|
		kp_inputwheel[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	// HERE COMES A NEW CHALLENGER
 | 
						|
	sprintf(buffer, "K_CHALxx");
 | 
						|
	for (i = 0; i < 25; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+((i+1)/10);
 | 
						|
		buffer[7] = '0'+((i+1)%10);
 | 
						|
		kp_challenger[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	// Lap start animation
 | 
						|
	sprintf(buffer, "K_LAP0x");
 | 
						|
	for (i = 0; i < 7; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+(i+1);
 | 
						|
		kp_lapanim_lap[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "K_LAPFxx");
 | 
						|
	for (i = 0; i < 11; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+((i+1)/10);
 | 
						|
		buffer[7] = '0'+((i+1)%10);
 | 
						|
		kp_lapanim_final[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "K_LAPNxx");
 | 
						|
	for (i = 0; i < 10; i++)
 | 
						|
	{
 | 
						|
		buffer[6] = '0'+i;
 | 
						|
		for (j = 0; j < 3; j++)
 | 
						|
		{
 | 
						|
			buffer[7] = '0'+(j+1);
 | 
						|
			kp_lapanim_number[i][j] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "K_LAPE0x");
 | 
						|
	for (i = 0; i < 2; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '0'+(i+1);
 | 
						|
		kp_lapanim_emblem[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	sprintf(buffer, "K_LAPH0x");
 | 
						|
	for (i = 0; i < 3; i++)
 | 
						|
	{
 | 
						|
		buffer[7] = '0'+(i+1);
 | 
						|
		kp_lapanim_hand[i] = (patch_t *) W_CachePatchName(buffer, PU_HUDGFX);
 | 
						|
	}
 | 
						|
 | 
						|
	kp_yougotem = (patch_t *) W_CachePatchName("YOUGOTEM", PU_HUDGFX);
 | 
						|
}
 | 
						|
 | 
						|
// For the item toggle menu
 | 
						|
const char *K_GetItemPatch(UINT8 item, boolean tiny)
 | 
						|
{
 | 
						|
	switch (item)
 | 
						|
	{
 | 
						|
		case KITEM_SNEAKER:
 | 
						|
		case KRITEM_TRIPLESNEAKER:
 | 
						|
			return (tiny ? "K_ISSHOE" : "K_ITSHOE");
 | 
						|
		case KITEM_ROCKETSNEAKER:
 | 
						|
			return (tiny ? "K_ISRSHE" : "K_ITRSHE");
 | 
						|
		case KITEM_INVINCIBILITY:
 | 
						|
			return (tiny ? "K_ISINV1" : "K_ITINV1");
 | 
						|
		case KITEM_BANANA:
 | 
						|
		case KRITEM_TRIPLEBANANA:
 | 
						|
		case KRITEM_TENFOLDBANANA:
 | 
						|
			return (tiny ? "K_ISBANA" : "K_ITBANA");
 | 
						|
		case KITEM_EGGMAN:
 | 
						|
			return (tiny ? "K_ISEGGM" : "K_ITEGGM");
 | 
						|
		case KITEM_ORBINAUT:
 | 
						|
			return (tiny ? "K_ISORBN" : "K_ITORB1");
 | 
						|
		case KITEM_JAWZ:
 | 
						|
		case KRITEM_DUALJAWZ:
 | 
						|
			return (tiny ? "K_ISJAWZ" : "K_ITJAWZ");
 | 
						|
		case KITEM_MINE:
 | 
						|
			return (tiny ? "K_ISMINE" : "K_ITMINE");
 | 
						|
		case KITEM_BALLHOG:
 | 
						|
			return (tiny ? "K_ISBHOG" : "K_ITBHOG");
 | 
						|
		case KITEM_SPB:
 | 
						|
			return (tiny ? "K_ISSPB" : "K_ITSPB");
 | 
						|
		case KITEM_GROW:
 | 
						|
			return (tiny ? "K_ISGROW" : "K_ITGROW");
 | 
						|
		case KITEM_SHRINK:
 | 
						|
			return (tiny ? "K_ISSHRK" : "K_ITSHRK");
 | 
						|
		case KITEM_THUNDERSHIELD:
 | 
						|
			return (tiny ? "K_ISTHNS" : "K_ITTHNS");
 | 
						|
		case KITEM_HYUDORO:
 | 
						|
			return (tiny ? "K_ISHYUD" : "K_ITHYUD");
 | 
						|
		case KITEM_POGOSPRING:
 | 
						|
			return (tiny ? "K_ISPOGO" : "K_ITPOGO");
 | 
						|
		case KITEM_KITCHENSINK:
 | 
						|
			return (tiny ? "K_ISSINK" : "K_ITSINK");
 | 
						|
		case KRITEM_TRIPLEORBINAUT:
 | 
						|
			return (tiny ? "K_ISORBN" : "K_ITORB3");
 | 
						|
		case KRITEM_QUADORBINAUT:
 | 
						|
			return (tiny ? "K_ISORBN" : "K_ITORB4");
 | 
						|
		default:
 | 
						|
			return (tiny ? "K_ISSAD" : "K_ITSAD");
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//}
 | 
						|
 | 
						|
INT32 ITEM_X, ITEM_Y;	// Item Window
 | 
						|
INT32 TIME_X, TIME_Y;	// Time Sticker
 | 
						|
INT32 LAPS_X, LAPS_Y;	// Lap Sticker
 | 
						|
INT32 SPDM_X, SPDM_Y;	// Speedometer
 | 
						|
INT32 POSI_X, POSI_Y;	// Position Number
 | 
						|
INT32 FACE_X, FACE_Y;	// Top-four Faces
 | 
						|
INT32 STCD_X, STCD_Y;	// Starting countdown
 | 
						|
INT32 CHEK_Y;			// CHECK graphic
 | 
						|
INT32 MINI_X, MINI_Y;	// Minimap
 | 
						|
INT32 WANT_X, WANT_Y;	// Battle WANTED poster
 | 
						|
 | 
						|
static void K_initKartHUD(void)
 | 
						|
{
 | 
						|
	/*
 | 
						|
		BASEVIDWIDTH  = 320
 | 
						|
		BASEVIDHEIGHT = 200
 | 
						|
 | 
						|
		Item window graphic is 41 x 33
 | 
						|
 | 
						|
		Time Sticker graphic is 116 x 11
 | 
						|
		Time Font is a solid block of (8 x [12) x 14], equal to 96 x 14
 | 
						|
		Therefore, timestamp is 116 x 14 altogether
 | 
						|
 | 
						|
		Lap Sticker is 80 x 11
 | 
						|
		Lap flag is 22 x 20
 | 
						|
		Lap Font is a solid block of (3 x [12) x 14], equal to 36 x 14
 | 
						|
		Therefore, lapstamp is 80 x 20 altogether
 | 
						|
 | 
						|
		Position numbers are 43 x 53
 | 
						|
 | 
						|
		Faces are 32 x 32
 | 
						|
		Faces draw downscaled at 16 x 16
 | 
						|
		Therefore, the allocated space for them is 16 x 67 altogether
 | 
						|
 | 
						|
		----
 | 
						|
 | 
						|
		ORIGINAL CZ64 SPLITSCREEN:
 | 
						|
 | 
						|
		Item window:
 | 
						|
		if (!splitscreen) 	{ ICONX = 139; 				ICONY = 20; }
 | 
						|
		else 				{ ICONX = BASEVIDWIDTH-315; ICONY = 60; }
 | 
						|
 | 
						|
		Time: 			   236, STRINGY(			   12)
 | 
						|
		Lap:  BASEVIDWIDTH-304, STRINGY(BASEVIDHEIGHT-189)
 | 
						|
 | 
						|
	*/
 | 
						|
 | 
						|
	// Single Screen (defaults)
 | 
						|
	// Item Window
 | 
						|
	ITEM_X = 5;						//   5
 | 
						|
	ITEM_Y = 5;						//   5
 | 
						|
	// Level Timer
 | 
						|
	TIME_X = BASEVIDWIDTH - 148;	// 172
 | 
						|
	TIME_Y = 9;						//   9
 | 
						|
	// Level Laps
 | 
						|
	LAPS_X = 9;						//   9
 | 
						|
	LAPS_Y = BASEVIDHEIGHT - 29;	// 171
 | 
						|
	// Speedometer
 | 
						|
	SPDM_X = 9;						//   9
 | 
						|
	SPDM_Y = BASEVIDHEIGHT - 45;	// 155
 | 
						|
	// Position Number
 | 
						|
	POSI_X = BASEVIDWIDTH  - 9;		// 268
 | 
						|
	POSI_Y = BASEVIDHEIGHT - 9;		// 138
 | 
						|
	// Top-Four Faces
 | 
						|
	FACE_X = 9;						//   9
 | 
						|
	FACE_Y = 92;					//  92
 | 
						|
	// Starting countdown
 | 
						|
	STCD_X = BASEVIDWIDTH/2;		//   9
 | 
						|
	STCD_Y = BASEVIDHEIGHT/2;		//  92
 | 
						|
	// CHECK graphic
 | 
						|
	CHEK_Y = BASEVIDHEIGHT;			// 200
 | 
						|
	// Minimap
 | 
						|
	MINI_X = BASEVIDWIDTH - 50;		// 270
 | 
						|
	MINI_Y = (BASEVIDHEIGHT/2)-16; //  84
 | 
						|
	// Battle WANTED poster
 | 
						|
	WANT_X = BASEVIDWIDTH - 55;		// 270
 | 
						|
	WANT_Y = BASEVIDHEIGHT- 71;		// 176
 | 
						|
 | 
						|
	if (splitscreen)	// Splitscreen
 | 
						|
	{
 | 
						|
		ITEM_X = 5;
 | 
						|
		ITEM_Y = 3;
 | 
						|
 | 
						|
		LAPS_Y = (BASEVIDHEIGHT/2)-24;
 | 
						|
 | 
						|
		POSI_Y = (BASEVIDHEIGHT/2)- 2;
 | 
						|
 | 
						|
		STCD_Y = BASEVIDHEIGHT/4;
 | 
						|
 | 
						|
		MINI_Y = (BASEVIDHEIGHT/2);
 | 
						|
 | 
						|
		WANT_X = BASEVIDWIDTH-8;
 | 
						|
		WANT_Y = (BASEVIDHEIGHT/2)-12;
 | 
						|
 | 
						|
		if (splitscreen > 1)	// 3P/4P Small Splitscreen
 | 
						|
		{
 | 
						|
			ITEM_X = -9;
 | 
						|
			ITEM_Y = -8;
 | 
						|
 | 
						|
			LAPS_X = 3;
 | 
						|
			LAPS_Y = (BASEVIDHEIGHT/2)-13;
 | 
						|
 | 
						|
			POSI_X = (BASEVIDWIDTH/2)-3;
 | 
						|
 | 
						|
			STCD_X = BASEVIDWIDTH/4;
 | 
						|
 | 
						|
			MINI_X = (3*BASEVIDWIDTH/4);
 | 
						|
			MINI_Y = (3*BASEVIDHEIGHT/4);
 | 
						|
 | 
						|
			WANT_X = (BASEVIDWIDTH/2)-8;
 | 
						|
 | 
						|
			if (splitscreen > 2) // 4P-only
 | 
						|
			{
 | 
						|
				MINI_X = (BASEVIDWIDTH/2);
 | 
						|
				MINI_Y = (BASEVIDHEIGHT/2);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (timeinmap > 113)
 | 
						|
		hudtrans = cv_translucenthud.value;
 | 
						|
	else if (timeinmap > 105)
 | 
						|
		hudtrans = ((((INT32)timeinmap) - 105)*cv_translucenthud.value)/(113-105);
 | 
						|
	else
 | 
						|
		hudtrans = 0;
 | 
						|
}
 | 
						|
 | 
						|
INT32 K_calcSplitFlags(INT32 snapflags)
 | 
						|
{
 | 
						|
	INT32 splitflags = 0;
 | 
						|
 | 
						|
	if (splitscreen == 0)
 | 
						|
		return snapflags;
 | 
						|
 | 
						|
	if (stplyr != &players[displayplayer])
 | 
						|
	{
 | 
						|
		if (splitscreen == 1 && stplyr == &players[secondarydisplayplayer])
 | 
						|
		{
 | 
						|
			splitflags |= V_SPLITSCREEN;
 | 
						|
		}
 | 
						|
		else if (splitscreen > 1)
 | 
						|
		{
 | 
						|
			if (stplyr == &players[thirddisplayplayer] || stplyr == &players[fourthdisplayplayer])
 | 
						|
				splitflags |= V_SPLITSCREEN;
 | 
						|
			if (stplyr == &players[secondarydisplayplayer] || stplyr == &players[fourthdisplayplayer])
 | 
						|
				splitflags |= V_HORZSCREEN;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (splitflags & V_SPLITSCREEN)
 | 
						|
		snapflags &= ~V_SNAPTOTOP;
 | 
						|
	else
 | 
						|
		snapflags &= ~V_SNAPTOBOTTOM;
 | 
						|
 | 
						|
	if (splitscreen > 1)
 | 
						|
	{
 | 
						|
		if (splitflags & V_HORZSCREEN)
 | 
						|
			snapflags &= ~V_SNAPTOLEFT;
 | 
						|
		else
 | 
						|
			snapflags &= ~V_SNAPTORIGHT;
 | 
						|
	}
 | 
						|
 | 
						|
	return (splitflags|snapflags);
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartItem(void)
 | 
						|
{
 | 
						|
	// ITEM_X = BASEVIDWIDTH-50;	// 270
 | 
						|
	// ITEM_Y = 24;					//  24
 | 
						|
 | 
						|
	// Why write V_DrawScaledPatch calls over and over when they're all the same?
 | 
						|
	// Set to 'no item' just in case.
 | 
						|
	const UINT8 offset = ((splitscreen > 1) ? 1 : 0);
 | 
						|
	patch_t *localpatch = kp_nodraw;
 | 
						|
	patch_t *localbg = ((offset) ? kp_itembg[2] : kp_itembg[0]);
 | 
						|
	patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]);
 | 
						|
	INT32 splitflags = K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTOLEFT);
 | 
						|
	const INT32 numberdisplaymin = ((!offset && stplyr->kartstuff[k_itemtype] == KITEM_ORBINAUT) ? 5 : 2);
 | 
						|
	INT32 itembar = 0;
 | 
						|
	UINT8 localcolor = SKINCOLOR_NONE;
 | 
						|
	SINT8 colormode = TC_RAINBOW;
 | 
						|
	UINT8 *colmap = NULL;
 | 
						|
 | 
						|
	if (stplyr->kartstuff[k_itemroulette])
 | 
						|
	{
 | 
						|
		if (stplyr->skincolor)
 | 
						|
			localcolor = stplyr->skincolor;
 | 
						|
 | 
						|
		switch((stplyr->kartstuff[k_itemroulette] % (14*3)) / 3)
 | 
						|
		{
 | 
						|
			// Each case is handled in threes, to give three frames of in-game time to see the item on the roulette
 | 
						|
			case 0: // Sneaker
 | 
						|
				localpatch = kp_sneaker[offset];
 | 
						|
				//localcolor = SKINCOLOR_RASPBERRY;
 | 
						|
				break;
 | 
						|
			case 1: // Banana
 | 
						|
				localpatch = kp_banana[offset];
 | 
						|
				//localcolor = SKINCOLOR_YELLOW;
 | 
						|
				break;
 | 
						|
			case 2: // Orbinaut
 | 
						|
				localpatch = kp_orbinaut[3+offset];
 | 
						|
				//localcolor = SKINCOLOR_STEEL;
 | 
						|
				break;
 | 
						|
			case 3: // Mine
 | 
						|
				localpatch = kp_mine[offset];
 | 
						|
				//localcolor = SKINCOLOR_JET;
 | 
						|
				break;
 | 
						|
			case 4: // Grow
 | 
						|
				localpatch = kp_grow[offset];
 | 
						|
				//localcolor = SKINCOLOR_TEAL;
 | 
						|
				break;
 | 
						|
			case 5: // Hyudoro
 | 
						|
				localpatch = kp_hyudoro[offset];
 | 
						|
				//localcolor = SKINCOLOR_STEEL;
 | 
						|
				break;
 | 
						|
			case 6: // Rocket Sneaker
 | 
						|
				localpatch = kp_rocketsneaker[offset];
 | 
						|
				//localcolor = SKINCOLOR_TANGERINE;
 | 
						|
				break;
 | 
						|
			case 7: // Jawz
 | 
						|
				localpatch = kp_jawz[offset];
 | 
						|
				//localcolor = SKINCOLOR_JAWZ;
 | 
						|
				break;
 | 
						|
			case 8: // Self-Propelled Bomb
 | 
						|
				localpatch = kp_selfpropelledbomb[offset];
 | 
						|
				//localcolor = SKINCOLOR_JET;
 | 
						|
				break;
 | 
						|
			case 9: // Shrink
 | 
						|
				localpatch = kp_shrink[offset];
 | 
						|
				//localcolor = SKINCOLOR_ORANGE;
 | 
						|
				break;
 | 
						|
			case 10: // Invincibility
 | 
						|
				localpatch = localinv;
 | 
						|
				//localcolor = SKINCOLOR_GREY;
 | 
						|
				break;
 | 
						|
			case 11: // Eggman Monitor
 | 
						|
				localpatch = kp_eggman[offset];
 | 
						|
				//localcolor = SKINCOLOR_ROSE;
 | 
						|
				break;
 | 
						|
			case 12: // Ballhog
 | 
						|
				localpatch = kp_ballhog[offset];
 | 
						|
				//localcolor = SKINCOLOR_LILAC;
 | 
						|
				break;
 | 
						|
			case 13: // Thunder Shield
 | 
						|
				localpatch = kp_thundershield[offset];
 | 
						|
				//localcolor = SKINCOLOR_CYAN;
 | 
						|
				break;
 | 
						|
			/*case 14: // Pogo Spring
 | 
						|
				localpatch = kp_pogospring[offset];
 | 
						|
				localcolor = SKINCOLOR_TANGERINE;
 | 
						|
				break;
 | 
						|
			case 15: // Kitchen Sink
 | 
						|
				localpatch = kp_kitchensink[offset];
 | 
						|
				localcolor = SKINCOLOR_STEEL;
 | 
						|
				break;*/
 | 
						|
			default:
 | 
						|
				break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		// I'm doing this a little weird and drawing mostly in reverse order
 | 
						|
		// The only actual reason is to make sneakers line up this way in the code below
 | 
						|
		// This shouldn't have any actual baring over how it functions
 | 
						|
		// Hyudoro is first, because we're drawing it on top of the player's current item
 | 
						|
		if (stplyr->kartstuff[k_stolentimer] > 0)
 | 
						|
		{
 | 
						|
			if (leveltime & 2)
 | 
						|
				localpatch = kp_hyudoro[offset];
 | 
						|
			else
 | 
						|
				localpatch = kp_nodraw;
 | 
						|
		}
 | 
						|
		else if ((stplyr->kartstuff[k_stealingtimer] > 0) && (leveltime & 2))
 | 
						|
		{
 | 
						|
			localpatch = kp_hyudoro[offset];
 | 
						|
		}
 | 
						|
		else if (stplyr->kartstuff[k_eggmanexplode] > 1)
 | 
						|
		{
 | 
						|
			if (leveltime & 1)
 | 
						|
				localpatch = kp_eggman[offset];
 | 
						|
			else
 | 
						|
				localpatch = kp_nodraw;
 | 
						|
		}
 | 
						|
		else if (stplyr->kartstuff[k_rocketsneakertimer] > 1)
 | 
						|
		{
 | 
						|
			itembar = stplyr->kartstuff[k_rocketsneakertimer];
 | 
						|
			if (leveltime & 1)
 | 
						|
				localpatch = kp_rocketsneaker[offset];
 | 
						|
			else
 | 
						|
				localpatch = kp_nodraw;
 | 
						|
		}
 | 
						|
		else if (stplyr->kartstuff[k_growshrinktimer] > 0)
 | 
						|
		{
 | 
						|
			if (leveltime & 1)
 | 
						|
				localpatch = kp_grow[offset];
 | 
						|
			else
 | 
						|
				localpatch = kp_nodraw;
 | 
						|
		}
 | 
						|
		else if (stplyr->kartstuff[k_sadtimer] > 0)
 | 
						|
		{
 | 
						|
			if (leveltime & 2)
 | 
						|
				localpatch = kp_sadface[offset];
 | 
						|
			else
 | 
						|
				localpatch = kp_nodraw;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (stplyr->kartstuff[k_itemamount] <= 0)
 | 
						|
				return;
 | 
						|
 | 
						|
			switch(stplyr->kartstuff[k_itemtype])
 | 
						|
			{
 | 
						|
				case KITEM_SNEAKER:
 | 
						|
					localpatch = kp_sneaker[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_ROCKETSNEAKER:
 | 
						|
					localpatch = kp_rocketsneaker[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_INVINCIBILITY:
 | 
						|
					localpatch = localinv;
 | 
						|
					localbg = kp_itembg[offset+1];
 | 
						|
					break;
 | 
						|
				case KITEM_BANANA:
 | 
						|
					localpatch = kp_banana[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_EGGMAN:
 | 
						|
					localpatch = kp_eggman[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_ORBINAUT:
 | 
						|
					localpatch = kp_orbinaut[(offset ? 4 : min(stplyr->kartstuff[k_itemamount]-1, 3))];
 | 
						|
					break;
 | 
						|
				case KITEM_JAWZ:
 | 
						|
					localpatch = kp_jawz[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_MINE:
 | 
						|
					localpatch = kp_mine[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_BALLHOG:
 | 
						|
					localpatch = kp_ballhog[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_SPB:
 | 
						|
					localpatch = kp_selfpropelledbomb[offset];
 | 
						|
					localbg = kp_itembg[offset+1];
 | 
						|
					break;
 | 
						|
				case KITEM_GROW:
 | 
						|
					localpatch = kp_grow[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_SHRINK:
 | 
						|
					localpatch = kp_shrink[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_THUNDERSHIELD:
 | 
						|
					localpatch = kp_thundershield[offset];
 | 
						|
					localbg = kp_itembg[offset+1];
 | 
						|
					break;
 | 
						|
				case KITEM_HYUDORO:
 | 
						|
					localpatch = kp_hyudoro[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_POGOSPRING:
 | 
						|
					localpatch = kp_pogospring[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_KITCHENSINK:
 | 
						|
					localpatch = kp_kitchensink[offset];
 | 
						|
					break;
 | 
						|
				case KITEM_SAD:
 | 
						|
					localpatch = kp_sadface[offset];
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					return;
 | 
						|
			}
 | 
						|
 | 
						|
			if (stplyr->kartstuff[k_itemheld] && !(leveltime & 1))
 | 
						|
				localpatch = kp_nodraw;
 | 
						|
		}
 | 
						|
 | 
						|
		if (stplyr->kartstuff[k_itemblink] && (leveltime & 1))
 | 
						|
		{
 | 
						|
			colormode = TC_BLINK;
 | 
						|
 | 
						|
			switch (stplyr->kartstuff[k_itemblinkmode])
 | 
						|
			{
 | 
						|
				case 2:
 | 
						|
					localcolor = (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1)));
 | 
						|
					break;
 | 
						|
				case 1:
 | 
						|
					localcolor = SKINCOLOR_RED;
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					localcolor = SKINCOLOR_WHITE;
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (localcolor != SKINCOLOR_NONE)
 | 
						|
		colmap = R_GetTranslationColormap(colormode, localcolor, 0);
 | 
						|
 | 
						|
	V_DrawScaledPatch(ITEM_X, ITEM_Y, V_HUDTRANS|splitflags, localbg);
 | 
						|
 | 
						|
	// Then, the numbers:
 | 
						|
	if (stplyr->kartstuff[k_itemamount] >= numberdisplaymin && !stplyr->kartstuff[k_itemroulette])
 | 
						|
	{
 | 
						|
		V_DrawScaledPatch(ITEM_X, ITEM_Y, V_HUDTRANS|splitflags, kp_itemmulsticker[offset]);
 | 
						|
		V_DrawFixedPatch(ITEM_X<<FRACBITS, ITEM_Y<<FRACBITS, FRACUNIT, V_HUDTRANS|splitflags, localpatch, colmap);
 | 
						|
		if (offset)
 | 
						|
			V_DrawString(ITEM_X+24, ITEM_Y+31, V_ALLOWLOWERCASE|V_HUDTRANS|splitflags, va("x%d", stplyr->kartstuff[k_itemamount]));
 | 
						|
		else
 | 
						|
		{
 | 
						|
			V_DrawScaledPatch(ITEM_X+28, ITEM_Y+41, V_HUDTRANS|splitflags, kp_itemx);
 | 
						|
			V_DrawKartString(ITEM_X+38, ITEM_Y+36, V_HUDTRANS|splitflags, va("%d", stplyr->kartstuff[k_itemamount]));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
		V_DrawFixedPatch(ITEM_X<<FRACBITS, ITEM_Y<<FRACBITS, FRACUNIT, V_HUDTRANS|splitflags, localpatch, colmap);
 | 
						|
 | 
						|
	// Extensible meter, currently only used for rocket sneaker...
 | 
						|
	if (itembar && hudtrans)
 | 
						|
	{
 | 
						|
		const INT32 barlength = (splitscreen > 1 ? 12 : 26);
 | 
						|
		const INT32 maxl = (itemtime*3) - barlength; // timer's normal highest value
 | 
						|
		const INT32 fill = ((itembar*barlength)/maxl);
 | 
						|
		const INT32 length = min(barlength, fill);
 | 
						|
		const INT32 height = (offset ? 1 : 2);
 | 
						|
		const INT32 x = (offset ? 17 : 11), y = (offset ? 27 : 35);
 | 
						|
 | 
						|
		V_DrawScaledPatch(ITEM_X+x, ITEM_Y+y, V_HUDTRANS|splitflags, kp_itemtimer[offset]);
 | 
						|
		// The left dark "AA" edge
 | 
						|
		V_DrawFill(ITEM_X+x+1, ITEM_Y+y+1, (length == 2 ? 2 : 1), height, 12|splitflags);
 | 
						|
		// The bar itself
 | 
						|
		if (length > 2)
 | 
						|
		{
 | 
						|
			V_DrawFill(ITEM_X+x+length, ITEM_Y+y+1, 1, height, 12|splitflags); // the right one
 | 
						|
			if (height == 2)
 | 
						|
				V_DrawFill(ITEM_X+x+2, ITEM_Y+y+2, length-2, 1, 8|splitflags); // the dulled underside
 | 
						|
			V_DrawFill(ITEM_X+x+2, ITEM_Y+y+1, length-2, 1, 120|splitflags); // the shine
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Quick Eggman numbers
 | 
						|
	if (stplyr->kartstuff[k_eggmanexplode] > 1 /*&& stplyr->kartstuff[k_eggmanexplode] <= 3*TICRATE*/)
 | 
						|
		V_DrawScaledPatch(ITEM_X+17, ITEM_Y+13-offset, V_HUDTRANS|splitflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->kartstuff[k_eggmanexplode]))]);
 | 
						|
}
 | 
						|
 | 
						|
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode)
 | 
						|
{
 | 
						|
	// TIME_X = BASEVIDWIDTH-124;	// 196
 | 
						|
	// TIME_Y = 6;					//   6
 | 
						|
 | 
						|
	tic_t worktime;
 | 
						|
 | 
						|
	INT32 splitflags = 0;
 | 
						|
	if (!mode)
 | 
						|
	{
 | 
						|
		splitflags = V_HUDTRANS|K_calcSplitFlags(V_SNAPTOTOP|V_SNAPTORIGHT);
 | 
						|
		if (cv_timelimit.value && timelimitintics > 0)
 | 
						|
		{
 | 
						|
			if (drawtime >= timelimitintics)
 | 
						|
				drawtime = 0;
 | 
						|
			else
 | 
						|
				drawtime = timelimitintics - drawtime;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	V_DrawScaledPatch(TX, TY, splitflags, ((mode == 2) ? kp_lapstickerwide : kp_timestickerwide));
 | 
						|
 | 
						|
	TX += 33;
 | 
						|
 | 
						|
	worktime = drawtime/(60*TICRATE);
 | 
						|
 | 
						|
	if (mode && !drawtime)
 | 
						|
		V_DrawKartString(TX, TY+3, splitflags, va("--'--\"--"));
 | 
						|
	else if (worktime < 100) // 99:99:99 only
 | 
						|
	{
 | 
						|
		// zero minute
 | 
						|
		if (worktime < 10)
 | 
						|
		{
 | 
						|
			V_DrawKartString(TX, TY+3, splitflags, va("0"));
 | 
						|
			// minutes time       0 __ __
 | 
						|
			V_DrawKartString(TX+12, TY+3, splitflags, va("%d", worktime));
 | 
						|
		}
 | 
						|
		// minutes time       0 __ __
 | 
						|
		else
 | 
						|
			V_DrawKartString(TX, TY+3, splitflags, va("%d", worktime));
 | 
						|
 | 
						|
		// apostrophe location     _'__ __
 | 
						|
		V_DrawKartString(TX+24, TY+3, splitflags, va("'"));
 | 
						|
 | 
						|
		worktime = (drawtime/TICRATE % 60);
 | 
						|
 | 
						|
		// zero second        _ 0_ __
 | 
						|
		if (worktime < 10)
 | 
						|
		{
 | 
						|
			V_DrawKartString(TX+36, TY+3, splitflags, va("0"));
 | 
						|
		// seconds time       _ _0 __
 | 
						|
			V_DrawKartString(TX+48, TY+3, splitflags, va("%d", worktime));
 | 
						|
		}
 | 
						|
		// zero second        _ 00 __
 | 
						|
		else
 | 
						|
			V_DrawKartString(TX+36, TY+3, splitflags, va("%d", worktime));
 | 
						|
 | 
						|
		// quotation mark location    _ __"__
 | 
						|
		V_DrawKartString(TX+60, TY+3, splitflags, va("\""));
 | 
						|
 | 
						|
		worktime = G_TicsToCentiseconds(drawtime);
 | 
						|
 | 
						|
		// zero tick          _ __ 0_
 | 
						|
		if (worktime < 10)
 | 
						|
		{
 | 
						|
			V_DrawKartString(TX+72, TY+3, splitflags, va("0"));
 | 
						|
		// tics               _ __ _0
 | 
						|
			V_DrawKartString(TX+84, TY+3, splitflags, va("%d", worktime));
 | 
						|
		}
 | 
						|
		// zero tick          _ __ 00
 | 
						|
		else
 | 
						|
			V_DrawKartString(TX+72, TY+3, splitflags, va("%d", worktime));
 | 
						|
	}
 | 
						|
	else if ((drawtime/TICRATE) & 1)
 | 
						|
		V_DrawKartString(TX, TY+3, splitflags, va("99'59\"99"));
 | 
						|
 | 
						|
	if (emblemmap && (modeattacking || (mode == 1)) && !demoplayback) // emblem time!
 | 
						|
	{
 | 
						|
		INT32 workx = TX + 96, worky = TY+18;
 | 
						|
		SINT8 curemb = 0;
 | 
						|
		patch_t *emblempic[3] = {NULL, NULL, NULL};
 | 
						|
		UINT8 *emblemcol[3] = {NULL, NULL, NULL};
 | 
						|
 | 
						|
		emblem_t *emblem = M_GetLevelEmblems(emblemmap);
 | 
						|
		while (emblem)
 | 
						|
		{
 | 
						|
			char targettext[9];
 | 
						|
 | 
						|
			switch (emblem->type)
 | 
						|
			{
 | 
						|
				case ET_TIME:
 | 
						|
					{
 | 
						|
						static boolean canplaysound = true;
 | 
						|
						tic_t timetoreach = emblem->var;
 | 
						|
 | 
						|
						if (emblem->collected)
 | 
						|
						{
 | 
						|
							emblempic[curemb] = W_CachePatchName(M_GetEmblemPatch(emblem), PU_CACHE);
 | 
						|
							emblemcol[curemb] = R_GetTranslationColormap(TC_DEFAULT, M_GetEmblemColor(emblem), GTC_CACHE);
 | 
						|
							if (++curemb == 3)
 | 
						|
								break;
 | 
						|
							goto bademblem;
 | 
						|
						}
 | 
						|
 | 
						|
						snprintf(targettext, 9, "%i'%02i\"%02i",
 | 
						|
							G_TicsToMinutes(timetoreach, false),
 | 
						|
							G_TicsToSeconds(timetoreach),
 | 
						|
							G_TicsToCentiseconds(timetoreach));
 | 
						|
 | 
						|
						if (!mode)
 | 
						|
						{
 | 
						|
							if (stplyr->realtime > timetoreach)
 | 
						|
							{
 | 
						|
								splitflags = (splitflags &~ V_HUDTRANS)|V_HUDTRANSHALF;
 | 
						|
								if (canplaysound)
 | 
						|
								{
 | 
						|
									S_StartSound(NULL, sfx_s3k72); //sfx_s26d); -- you STOLE fizzy lifting drinks
 | 
						|
									canplaysound = false;
 | 
						|
								}
 | 
						|
							}
 | 
						|
							else if (!canplaysound)
 | 
						|
								canplaysound = true;
 | 
						|
						}
 | 
						|
 | 
						|
						targettext[8] = 0;
 | 
						|
					}
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					goto bademblem;
 | 
						|
			}
 | 
						|
 | 
						|
			V_DrawRightAlignedString(workx, worky, splitflags, targettext);
 | 
						|
			workx -= 67;
 | 
						|
			V_DrawSmallScaledPatch(workx + 4, worky, splitflags, W_CachePatchName("NEEDIT", PU_CACHE));
 | 
						|
 | 
						|
			break;
 | 
						|
 | 
						|
			bademblem:
 | 
						|
			emblem = M_GetLevelEmblems(-1);
 | 
						|
		}
 | 
						|
 | 
						|
		if (!mode)
 | 
						|
			splitflags = (splitflags &~ V_HUDTRANSHALF)|V_HUDTRANS;
 | 
						|
		while (curemb--)
 | 
						|
		{
 | 
						|
			workx -= 12;
 | 
						|
			V_DrawSmallMappedPatch(workx + 4, worky, splitflags, emblempic[curemb], emblemcol[curemb]);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_DrawKartPositionNum(INT32 num)
 | 
						|
{
 | 
						|
	// POSI_X = BASEVIDWIDTH - 51;	// 269
 | 
						|
	// POSI_Y = BASEVIDHEIGHT- 64;	// 136
 | 
						|
 | 
						|
	boolean win = (stplyr->exiting && num == 1);
 | 
						|
	INT32 X = POSI_X;
 | 
						|
	INT32 W = SHORT(kp_positionnum[0][0]->width);
 | 
						|
	fixed_t scale = FRACUNIT;
 | 
						|
	patch_t *localpatch = kp_positionnum[0][0];
 | 
						|
	INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTORIGHT);
 | 
						|
 | 
						|
	if (stplyr->kartstuff[k_positiondelay] || stplyr->exiting)
 | 
						|
		scale *= 2;
 | 
						|
	if (splitscreen)
 | 
						|
		scale /= 2;
 | 
						|
 | 
						|
	W = FixedMul(W<<FRACBITS, scale)>>FRACBITS;
 | 
						|
 | 
						|
	// Special case for 0
 | 
						|
	if (!num)
 | 
						|
	{
 | 
						|
		V_DrawFixedPatch(X<<FRACBITS, POSI_Y<<FRACBITS, scale, V_HUDTRANSHALF|splitflags, kp_positionnum[0][0], NULL);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	I_Assert(num >= 0); // This function does not draw negative numbers
 | 
						|
 | 
						|
	// Draw the number
 | 
						|
	while (num)
 | 
						|
	{
 | 
						|
		if (win) // 1st place winner? You get rainbows!!
 | 
						|
			localpatch = kp_winnernum[(leveltime % (NUMWINFRAMES*3)) / 3];
 | 
						|
		else if (stplyr->laps+1 >= cv_numlaps.value || stplyr->exiting) // Check for the final lap, or won
 | 
						|
		{
 | 
						|
			// Alternate frame every three frames
 | 
						|
			switch (leveltime % 9)
 | 
						|
			{
 | 
						|
				case 1: case 2: case 3:
 | 
						|
					if (K_IsPlayerLosing(stplyr))
 | 
						|
						localpatch = kp_positionnum[num % 10][4];
 | 
						|
					else
 | 
						|
						localpatch = kp_positionnum[num % 10][1];
 | 
						|
					break;
 | 
						|
				case 4: case 5: case 6:
 | 
						|
					if (K_IsPlayerLosing(stplyr))
 | 
						|
						localpatch = kp_positionnum[num % 10][5];
 | 
						|
					else
 | 
						|
						localpatch = kp_positionnum[num % 10][2];
 | 
						|
					break;
 | 
						|
				case 7: case 8: case 9:
 | 
						|
					if (K_IsPlayerLosing(stplyr))
 | 
						|
						localpatch = kp_positionnum[num % 10][6];
 | 
						|
					else
 | 
						|
						localpatch = kp_positionnum[num % 10][3];
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					localpatch = kp_positionnum[num % 10][0];
 | 
						|
					break;
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else
 | 
						|
			localpatch = kp_positionnum[num % 10][0];
 | 
						|
 | 
						|
		V_DrawFixedPatch(X<<FRACBITS, POSI_Y<<FRACBITS, scale, V_HUDTRANSHALF|splitflags, localpatch, NULL);
 | 
						|
 | 
						|
		X -= W;
 | 
						|
		num /= 10;
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static boolean K_drawKartPositionFaces(void)
 | 
						|
{
 | 
						|
	// FACE_X = 15;				//  15
 | 
						|
	// FACE_Y = 72;				//  72
 | 
						|
 | 
						|
	INT32 Y = FACE_Y+9; // +9 to offset where it's being drawn if there are more than one
 | 
						|
	INT32 i, j, ranklines, strank = -1;
 | 
						|
	boolean completed[MAXPLAYERS];
 | 
						|
	INT32 rankplayer[MAXPLAYERS];
 | 
						|
	INT32 bumperx, numplayersingame = 0;
 | 
						|
	UINT8 *colormap;
 | 
						|
 | 
						|
	ranklines = 0;
 | 
						|
	memset(completed, 0, sizeof (completed));
 | 
						|
	memset(rankplayer, 0, sizeof (rankplayer));
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		rankplayer[i] = -1;
 | 
						|
 | 
						|
		if (!playeringame[i] || players[i].spectator || !players[i].mo)
 | 
						|
			continue;
 | 
						|
 | 
						|
		numplayersingame++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (numplayersingame <= 1)
 | 
						|
		return true;
 | 
						|
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
	if (!LUA_HudEnabled(hud_minirankings))
 | 
						|
		return false;	// Don't proceed but still return true for free play above if HUD is disabled.
 | 
						|
#endif
 | 
						|
 | 
						|
	for (j = 0; j < numplayersingame; j++)
 | 
						|
	{
 | 
						|
		UINT8 lowestposition = MAXPLAYERS+1;
 | 
						|
		for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
		{
 | 
						|
			if (completed[i] || !playeringame[i] || players[i].spectator || !players[i].mo)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (players[i].kartstuff[k_position] >= lowestposition)
 | 
						|
				continue;
 | 
						|
 | 
						|
			rankplayer[ranklines] = i;
 | 
						|
			lowestposition = players[i].kartstuff[k_position];
 | 
						|
		}
 | 
						|
 | 
						|
		i = rankplayer[ranklines];
 | 
						|
 | 
						|
		completed[i] = true;
 | 
						|
 | 
						|
		if (players+i == stplyr)
 | 
						|
			strank = ranklines;
 | 
						|
 | 
						|
		//if (ranklines == 5)
 | 
						|
			//break; // Only draw the top 5 players -- we do this a different way now...
 | 
						|
 | 
						|
		ranklines++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (ranklines < 5)
 | 
						|
		Y -= (9*ranklines);
 | 
						|
	else
 | 
						|
		Y -= (9*5);
 | 
						|
 | 
						|
	if (G_BattleGametype() || strank <= 2) // too close to the top, or playing battle, or a spectator? would have had (strank == -1) called out, but already caught by (strank <= 2)
 | 
						|
	{
 | 
						|
		i = 0;
 | 
						|
		if (ranklines > 5) // could be both...
 | 
						|
			ranklines = 5;
 | 
						|
	}
 | 
						|
	else if (strank+3 > ranklines) // too close to the bottom?
 | 
						|
	{
 | 
						|
		i = ranklines - 5;
 | 
						|
		if (i < 0)
 | 
						|
			i = 0;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		i = strank-2;
 | 
						|
		ranklines = strank+3;
 | 
						|
	}
 | 
						|
 | 
						|
	for (; i < ranklines; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[rankplayer[i]]) continue;
 | 
						|
		if (players[rankplayer[i]].spectator) continue;
 | 
						|
		if (!players[rankplayer[i]].mo) continue;
 | 
						|
 | 
						|
		bumperx = FACE_X+19;
 | 
						|
 | 
						|
		if (players[rankplayer[i]].mo->color)
 | 
						|
		{
 | 
						|
			colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE);
 | 
						|
			if (players[rankplayer[i]].mo->colorized)
 | 
						|
				colormap = R_GetTranslationColormap(TC_RAINBOW, players[rankplayer[i]].mo->color, GTC_CACHE);
 | 
						|
			else
 | 
						|
				colormap = R_GetTranslationColormap(players[rankplayer[i]].skin, players[rankplayer[i]].mo->color, GTC_CACHE);
 | 
						|
 | 
						|
			V_DrawMappedPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, facerankprefix[players[rankplayer[i]].skin], colormap);
 | 
						|
			if (G_BattleGametype() && players[rankplayer[i]].kartstuff[k_bumper] > 0)
 | 
						|
			{
 | 
						|
				V_DrawMappedPatch(bumperx-2, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumper[0], colormap);
 | 
						|
				for (j = 1; j < players[rankplayer[i]].kartstuff[k_bumper]; j++)
 | 
						|
				{
 | 
						|
					bumperx += 5;
 | 
						|
					V_DrawMappedPatch(bumperx, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_tinybumper[1], colormap);
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
 | 
						|
		if (i == strank)
 | 
						|
			V_DrawScaledPatch(FACE_X, Y, V_HUDTRANS|V_SNAPTOLEFT, kp_facehighlight[(leveltime / 4) % 8]);
 | 
						|
 | 
						|
		if (G_BattleGametype() && players[rankplayer[i]].kartstuff[k_bumper] <= 0)
 | 
						|
			V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SNAPTOLEFT, kp_ranknobumpers);
 | 
						|
		else
 | 
						|
		{
 | 
						|
			INT32 pos = players[rankplayer[i]].kartstuff[k_position];
 | 
						|
			if (pos < 0 || pos > MAXPLAYERS)
 | 
						|
				pos = 0;
 | 
						|
			// Draws the little number over the face
 | 
						|
			V_DrawScaledPatch(FACE_X-5, Y+10, V_HUDTRANS|V_SNAPTOLEFT, kp_facenum[pos]);
 | 
						|
		}
 | 
						|
 | 
						|
		Y += 18;
 | 
						|
	}
 | 
						|
 | 
						|
	return false;
 | 
						|
}
 | 
						|
 | 
						|
//
 | 
						|
// HU_DrawTabRankings -- moved here to take advantage of kart stuff!
 | 
						|
//
 | 
						|
void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, INT32 whiteplayer, INT32 hilicol)
 | 
						|
{
 | 
						|
	INT32 i, rightoffset = 240;
 | 
						|
	const UINT8 *colormap;
 | 
						|
	INT32 dupadjust = (vid.width/vid.dupx), duptweak = (dupadjust - BASEVIDWIDTH)/2;
 | 
						|
 | 
						|
	//this function is designed for 9 or less score lines only
 | 
						|
	//I_Assert(scorelines <= 9); -- not today bitch, kart fixed it up
 | 
						|
 | 
						|
	V_DrawFill(1-duptweak, 26, dupadjust-2, 1, 0); // Draw a horizontal line because it looks nice!
 | 
						|
	if (scorelines > 8)
 | 
						|
	{
 | 
						|
		V_DrawFill(160, 26, 1, 147, 0); // Draw a vertical line to separate the two sides.
 | 
						|
		V_DrawFill(1-duptweak, 173, dupadjust-2, 1, 0); // And a horizontal line near the bottom.
 | 
						|
		rightoffset = (BASEVIDWIDTH/2) - 4 - x;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < scorelines; i++)
 | 
						|
	{
 | 
						|
		char strtime[MAXPLAYERNAME+1];
 | 
						|
 | 
						|
		if (players[tab[i].num].spectator || !players[tab[i].num].mo)
 | 
						|
			continue; //ignore them.
 | 
						|
 | 
						|
		if (netgame // don't draw it offline
 | 
						|
        && tab[i].num != serverplayer)
 | 
						|
			HU_drawPing(x + ((i < 8) ? -19 : rightoffset + 13), y+2, playerpingtable[tab[i].num], false);
 | 
						|
 | 
						|
		if (scorelines > 8)
 | 
						|
			strlcpy(strtime, tab[i].name, 6);
 | 
						|
		else
 | 
						|
			STRBUFCPY(strtime, tab[i].name);
 | 
						|
 | 
						|
		V_DrawString(x + 20, y,
 | 
						|
			((tab[i].num == whiteplayer)
 | 
						|
				? hilicol|V_ALLOWLOWERCASE
 | 
						|
				: V_ALLOWLOWERCASE),
 | 
						|
			strtime);
 | 
						|
 | 
						|
		if (players[tab[i].num].mo->color)
 | 
						|
		{
 | 
						|
			colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE);
 | 
						|
			if (players[tab[i].num].mo->colorized)
 | 
						|
				colormap = R_GetTranslationColormap(TC_RAINBOW, players[tab[i].num].mo->color, GTC_CACHE);
 | 
						|
			else
 | 
						|
				colormap = R_GetTranslationColormap(players[tab[i].num].skin, players[tab[i].num].mo->color, GTC_CACHE);
 | 
						|
 | 
						|
			V_DrawMappedPatch(x, y-4, 0, facerankprefix[players[tab[i].num].skin], colormap);
 | 
						|
			/*if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] > 0) -- not enough space for this
 | 
						|
			{
 | 
						|
				INT32 bumperx = x+19;
 | 
						|
				V_DrawMappedPatch(bumperx-2, y-4, 0, kp_tinybumper[0], colormap);
 | 
						|
				for (j = 1; j < players[tab[i].num].kartstuff[k_bumper]; j++)
 | 
						|
				{
 | 
						|
					bumperx += 5;
 | 
						|
					V_DrawMappedPatch(bumperx, y-4, 0, kp_tinybumper[1], colormap);
 | 
						|
				}
 | 
						|
			}*/
 | 
						|
		}
 | 
						|
 | 
						|
		if (tab[i].num == whiteplayer)
 | 
						|
			V_DrawScaledPatch(x, y-4, 0, kp_facehighlight[(leveltime / 4) % 8]);
 | 
						|
 | 
						|
		if (G_BattleGametype() && players[tab[i].num].kartstuff[k_bumper] <= 0)
 | 
						|
			V_DrawScaledPatch(x-4, y-7, 0, kp_ranknobumpers);
 | 
						|
		else
 | 
						|
		{
 | 
						|
			INT32 pos = players[tab[i].num].kartstuff[k_position];
 | 
						|
			if (pos < 0 || pos > MAXPLAYERS)
 | 
						|
				pos = 0;
 | 
						|
			// Draws the little number over the face
 | 
						|
			V_DrawScaledPatch(x-5, y+6, 0, kp_facenum[pos]);
 | 
						|
		}
 | 
						|
 | 
						|
		if (G_RaceGametype())
 | 
						|
		{
 | 
						|
#define timestring(time) va("%i'%02i\"%02i", G_TicsToMinutes(time, true), G_TicsToSeconds(time), G_TicsToCentiseconds(time))
 | 
						|
			if (players[tab[i].num].exiting)
 | 
						|
				V_DrawRightAlignedString(x+rightoffset, y, hilicol, timestring(players[tab[i].num].realtime));
 | 
						|
			else if (players[tab[i].num].pflags & PF_TIMEOVER)
 | 
						|
				V_DrawRightAlignedThinString(x+rightoffset, y-1, 0, "NO CONTEST.");
 | 
						|
			else if (circuitmap)
 | 
						|
				V_DrawRightAlignedString(x+rightoffset, y, 0, va("Lap %d", tab[i].count));
 | 
						|
#undef timestring
 | 
						|
		}
 | 
						|
		else
 | 
						|
			V_DrawRightAlignedString(x+rightoffset, y, 0, va("%u", tab[i].count));
 | 
						|
 | 
						|
		y += 18;
 | 
						|
		if (i == 7)
 | 
						|
		{
 | 
						|
			y = 33;
 | 
						|
			x = (BASEVIDWIDTH/2) + 4;
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartLaps(void)
 | 
						|
{
 | 
						|
	INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT);
 | 
						|
 | 
						|
	if (splitscreen > 1)
 | 
						|
	{
 | 
						|
		V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_splitlapflag);
 | 
						|
 | 
						|
		if (stplyr->exiting)
 | 
						|
			V_DrawString(LAPS_X+13, LAPS_Y+1, V_HUDTRANS|splitflags, "FIN");
 | 
						|
		else
 | 
						|
			V_DrawString(LAPS_X+13, LAPS_Y+1, V_HUDTRANS|splitflags, va("%d/%d", stplyr->laps+1, cv_numlaps.value));
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		V_DrawScaledPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_lapsticker);
 | 
						|
 | 
						|
		if (stplyr->exiting)
 | 
						|
			V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, "FIN");
 | 
						|
		else
 | 
						|
			V_DrawKartString(LAPS_X+33, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->laps+1, cv_numlaps.value));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartSpeedometer(void)
 | 
						|
{
 | 
						|
	fixed_t convSpeed;
 | 
						|
	INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT);
 | 
						|
 | 
						|
	if (cv_kartspeedometer.value == 1) // Kilometers
 | 
						|
	{
 | 
						|
		convSpeed = FixedDiv(FixedMul(stplyr->speed, 142371), mapobjectscale)/FRACUNIT; // 2.172409058
 | 
						|
		V_DrawKartString(SPDM_X, SPDM_Y, V_HUDTRANS|splitflags, va("%3d km/h", convSpeed));
 | 
						|
	}
 | 
						|
	else if (cv_kartspeedometer.value == 2) // Miles
 | 
						|
	{
 | 
						|
		convSpeed = FixedDiv(FixedMul(stplyr->speed, 88465), mapobjectscale)/FRACUNIT; // 1.349868774
 | 
						|
		V_DrawKartString(SPDM_X, SPDM_Y, V_HUDTRANS|splitflags, va("%3d mph", convSpeed));
 | 
						|
	}
 | 
						|
	else if (cv_kartspeedometer.value == 3) // Fracunits
 | 
						|
	{
 | 
						|
		convSpeed = FixedDiv(stplyr->speed, mapobjectscale)/FRACUNIT;
 | 
						|
		V_DrawKartString(SPDM_X, SPDM_Y, V_HUDTRANS|splitflags, va("%3d fu/t", convSpeed));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartBumpersOrKarma(void)
 | 
						|
{
 | 
						|
	UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, 0);
 | 
						|
	INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTOLEFT);
 | 
						|
 | 
						|
	if (splitscreen > 1)
 | 
						|
	{
 | 
						|
		if (stplyr->kartstuff[k_bumper] <= 0)
 | 
						|
		{
 | 
						|
			V_DrawMappedPatch(LAPS_X, LAPS_Y-1, V_HUDTRANS|splitflags, kp_splitkarmabomb, colormap);
 | 
						|
			V_DrawString(LAPS_X+13, LAPS_Y+1, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints]));
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			V_DrawMappedPatch(LAPS_X, LAPS_Y-1, V_HUDTRANS|splitflags, kp_rankbumper, colormap);
 | 
						|
			V_DrawString(LAPS_X+13, LAPS_Y+1, V_HUDTRANS|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value));
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		if (stplyr->kartstuff[k_bumper] <= 0)
 | 
						|
		{
 | 
						|
			V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_karmasticker, colormap);
 | 
						|
			V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/2", stplyr->kartstuff[k_comebackpoints]));
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (stplyr->kartstuff[k_bumper] > 9 && cv_kartbumpers.value > 9)
 | 
						|
				V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumperstickerwide, colormap);
 | 
						|
			else
 | 
						|
				V_DrawMappedPatch(LAPS_X, LAPS_Y, V_HUDTRANS|splitflags, kp_bumpersticker, colormap);
 | 
						|
			V_DrawKartString(LAPS_X+47, LAPS_Y+3, V_HUDTRANS|splitflags, va("%d/%d", stplyr->kartstuff[k_bumper], cv_kartbumpers.value));
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static fixed_t K_FindCheckX(fixed_t px, fixed_t py, angle_t ang, fixed_t mx, fixed_t my)
 | 
						|
{
 | 
						|
	fixed_t dist, x;
 | 
						|
	fixed_t range = RING_DIST/3;
 | 
						|
	angle_t diff;
 | 
						|
 | 
						|
	range *= gamespeed+1;
 | 
						|
 | 
						|
	dist = abs(R_PointToDist2(px, py, mx, my));
 | 
						|
	if (dist > range)
 | 
						|
		return -320;
 | 
						|
 | 
						|
	diff = R_PointToAngle2(px, py, mx, my) - ang;
 | 
						|
 | 
						|
	if (diff < ANGLE_90 || diff > ANGLE_270)
 | 
						|
		return -320;
 | 
						|
	else
 | 
						|
		x = (FixedMul(FINETANGENT(((diff+ANGLE_90)>>ANGLETOFINESHIFT) & 4095), 160<<FRACBITS) + (160<<FRACBITS))>>FRACBITS;
 | 
						|
 | 
						|
	if (encoremode)
 | 
						|
		x = 320-x;
 | 
						|
 | 
						|
	if (splitscreen > 1)
 | 
						|
		x /= 2;
 | 
						|
 | 
						|
	return x;
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartWanted(void)
 | 
						|
{
 | 
						|
	UINT8 i, numwanted = 0;
 | 
						|
	UINT8 *colormap = NULL;
 | 
						|
 | 
						|
	if (splitscreen) // Can't fit the poster on screen, sadly
 | 
						|
	{
 | 
						|
		if (K_IsPlayerWanted(stplyr) && leveltime % 10 > 3)
 | 
						|
			V_DrawRightAlignedString(WANT_X, WANT_Y, K_calcSplitFlags(V_SNAPTOBOTTOM|V_SNAPTORIGHT|V_HUDTRANS|V_ORANGEMAP), "WANTED");
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	for (i = 0; i < 4; i++)
 | 
						|
	{
 | 
						|
		if (battlewanted[i] == -1)
 | 
						|
			break;
 | 
						|
		numwanted++;
 | 
						|
	}
 | 
						|
 | 
						|
	if (numwanted <= 0)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (battlewanted[0] != -1)
 | 
						|
		colormap = R_GetTranslationColormap(0, players[battlewanted[0]].skincolor, GTC_CACHE);
 | 
						|
	V_DrawFixedPatch(WANT_X<<FRACBITS, WANT_Y<<FRACBITS, FRACUNIT, V_HUDTRANS|V_SNAPTORIGHT|V_SNAPTOBOTTOM, kp_wanted, colormap);
 | 
						|
 | 
						|
	for (i = 0; i < numwanted; i++)
 | 
						|
	{
 | 
						|
		INT32 x = WANT_X+8, y = WANT_Y+21;
 | 
						|
		fixed_t scale = FRACUNIT/2;
 | 
						|
		player_t *p = &players[battlewanted[i]];
 | 
						|
 | 
						|
		if (battlewanted[i] == -1)
 | 
						|
			break;
 | 
						|
 | 
						|
		if (numwanted == 1)
 | 
						|
			scale = FRACUNIT;
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (i & 1)
 | 
						|
				x += 16;
 | 
						|
			if (i > 1)
 | 
						|
				y += 16;
 | 
						|
		}
 | 
						|
 | 
						|
		if (players[battlewanted[i]].skincolor)
 | 
						|
		{
 | 
						|
			colormap = R_GetTranslationColormap(TC_RAINBOW, p->skincolor, GTC_CACHE);
 | 
						|
			V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, V_HUDTRANS|V_SNAPTORIGHT|V_SNAPTOBOTTOM, (scale == FRACUNIT ? facewantprefix[p->skin] : facerankprefix[p->skin]), colormap);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartPlayerCheck(void)
 | 
						|
{
 | 
						|
	INT32 i;
 | 
						|
	UINT8 *colormap;
 | 
						|
	INT32 x;
 | 
						|
 | 
						|
	INT32 splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM);
 | 
						|
 | 
						|
	if (!stplyr->mo || stplyr->spectator)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (stplyr->awayviewtics)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (camspin)
 | 
						|
		return;
 | 
						|
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		UINT8 pnum = 0;
 | 
						|
 | 
						|
		if (&players[i] == stplyr)
 | 
						|
			continue;
 | 
						|
		if (!playeringame[i] || players[i].spectator)
 | 
						|
			continue;
 | 
						|
		if (!players[i].mo)
 | 
						|
			continue;
 | 
						|
 | 
						|
		if ((players[i].kartstuff[k_invincibilitytimer] <= 0) && (leveltime & 2))
 | 
						|
			pnum++; // white frames
 | 
						|
 | 
						|
		if (players[i].kartstuff[k_itemtype] == KITEM_GROW || players[i].kartstuff[k_growshrinktimer] > 0)
 | 
						|
			pnum += 4;
 | 
						|
		else if (players[i].kartstuff[k_itemtype] == KITEM_INVINCIBILITY || players[i].kartstuff[k_invincibilitytimer])
 | 
						|
			pnum += 2;
 | 
						|
 | 
						|
		x = K_FindCheckX(stplyr->mo->x, stplyr->mo->y, stplyr->mo->angle, players[i].mo->x, players[i].mo->y);
 | 
						|
		if (x <= 320 && x >= 0)
 | 
						|
		{
 | 
						|
			if (x < 14)
 | 
						|
				x = 14;
 | 
						|
			else if (x > 306)
 | 
						|
				x = 306;
 | 
						|
 | 
						|
			colormap = R_GetTranslationColormap(TC_DEFAULT, players[i].mo->color, 0);
 | 
						|
			V_DrawMappedPatch(x, CHEK_Y, V_HUDTRANS|splitflags, kp_check[pnum], colormap);
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartMinimapHead(mobj_t *mo, INT32 x, INT32 y, INT32 flags, patch_t *AutomapPic)
 | 
						|
{
 | 
						|
	// amnum xpos & ypos are the icon's speed around the HUD.
 | 
						|
	// The number being divided by is for how fast it moves.
 | 
						|
	// The higher the number, the slower it moves.
 | 
						|
 | 
						|
	// am xpos & ypos are the icon's starting position. Withouht
 | 
						|
	// it, they wouldn't 'spawn' on the top-right side of the HUD.
 | 
						|
 | 
						|
	UINT8 skin = 0;
 | 
						|
 | 
						|
	fixed_t amnumxpos, amnumypos;
 | 
						|
	INT32 amxpos, amypos;
 | 
						|
 | 
						|
	node_t *bsp = &nodes[numnodes-1];
 | 
						|
	fixed_t maxx, minx, maxy, miny;
 | 
						|
 | 
						|
	fixed_t mapwidth, mapheight;
 | 
						|
	fixed_t xoffset, yoffset;
 | 
						|
	fixed_t xscale, yscale, zoom;
 | 
						|
 | 
						|
	if (mo->skin)
 | 
						|
		skin = ((skin_t*)mo->skin)-skins;
 | 
						|
 | 
						|
	maxx = maxy = INT32_MAX;
 | 
						|
	minx = miny = INT32_MIN;
 | 
						|
	minx = bsp->bbox[0][BOXLEFT];
 | 
						|
	maxx = bsp->bbox[0][BOXRIGHT];
 | 
						|
	miny = bsp->bbox[0][BOXBOTTOM];
 | 
						|
	maxy = bsp->bbox[0][BOXTOP];
 | 
						|
 | 
						|
	if (bsp->bbox[1][BOXLEFT] < minx)
 | 
						|
		minx = bsp->bbox[1][BOXLEFT];
 | 
						|
	if (bsp->bbox[1][BOXRIGHT] > maxx)
 | 
						|
		maxx = bsp->bbox[1][BOXRIGHT];
 | 
						|
	if (bsp->bbox[1][BOXBOTTOM] < miny)
 | 
						|
		miny = bsp->bbox[1][BOXBOTTOM];
 | 
						|
	if (bsp->bbox[1][BOXTOP] > maxy)
 | 
						|
		maxy = bsp->bbox[1][BOXTOP];
 | 
						|
 | 
						|
	// You might be wondering why these are being bitshift here
 | 
						|
	// it's because mapwidth and height would otherwise overflow for maps larger than half the size possible...
 | 
						|
	// map boundaries and sizes will ALWAYS be whole numbers thankfully
 | 
						|
	// later calculations take into consideration that these are actually not in terms of FRACUNIT though
 | 
						|
	minx >>= FRACBITS;
 | 
						|
	maxx >>= FRACBITS;
 | 
						|
	miny >>= FRACBITS;
 | 
						|
	maxy >>= FRACBITS;
 | 
						|
 | 
						|
	mapwidth = maxx - minx;
 | 
						|
	mapheight = maxy - miny;
 | 
						|
 | 
						|
	// These should always be small enough to be bitshift back right now
 | 
						|
	xoffset = (minx + mapwidth/2)<<FRACBITS;
 | 
						|
	yoffset = (miny + mapheight/2)<<FRACBITS;
 | 
						|
 | 
						|
	xscale = FixedDiv(AutomapPic->width, mapwidth);
 | 
						|
	yscale = FixedDiv(AutomapPic->height, mapheight);
 | 
						|
	zoom = FixedMul(min(xscale, yscale), FRACUNIT-FRACUNIT/20);
 | 
						|
 | 
						|
	amnumxpos = (FixedMul(mo->x, zoom) - FixedMul(xoffset, zoom));
 | 
						|
	amnumypos = -(FixedMul(mo->y, zoom) - FixedMul(yoffset, zoom));
 | 
						|
 | 
						|
	if (encoremode)
 | 
						|
		amnumxpos = -amnumxpos;
 | 
						|
 | 
						|
	amxpos = amnumxpos + ((x + AutomapPic->width/2 - (facemmapprefix[skin]->width/2))<<FRACBITS);
 | 
						|
	amypos = amnumypos + ((y + AutomapPic->height/2 - (facemmapprefix[skin]->height/2))<<FRACBITS);
 | 
						|
 | 
						|
	// do we want this? it feels unnecessary. easier to just modify the amnumxpos?
 | 
						|
	/*if (encoremode)
 | 
						|
	{
 | 
						|
		flags |= V_FLIP;
 | 
						|
		amxpos = -amnumxpos + ((x + AutomapPic->width/2 + (facemmapprefix[skin]->width/2))<<FRACBITS);
 | 
						|
	}*/
 | 
						|
 | 
						|
	if (!mo->color) // 'default' color
 | 
						|
		V_DrawSciencePatch(amxpos, amypos, flags, facemmapprefix[skin], FRACUNIT);
 | 
						|
	else
 | 
						|
	{
 | 
						|
		UINT8 *colormap;
 | 
						|
		if (mo->colorized)
 | 
						|
			colormap = R_GetTranslationColormap(TC_RAINBOW, mo->color, GTC_CACHE);
 | 
						|
		else
 | 
						|
			colormap = R_GetTranslationColormap(skin, mo->color, GTC_CACHE);
 | 
						|
		V_DrawFixedPatch(amxpos, amypos, FRACUNIT, flags, facemmapprefix[skin], colormap);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartMinimap(void)
 | 
						|
{
 | 
						|
	INT32 lumpnum;
 | 
						|
	patch_t *AutomapPic;
 | 
						|
	INT32 i = 0;
 | 
						|
	INT32 x, y;
 | 
						|
	INT32 minimaptrans, splitflags = (splitscreen ? 0 : V_SNAPTORIGHT);
 | 
						|
	boolean dop1later = false;
 | 
						|
 | 
						|
	// Draw the HUD only when playing in a level.
 | 
						|
	// hu_stuff needs this, unlike st_stuff.
 | 
						|
	if (gamestate != GS_LEVEL)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (stplyr != &players[displayplayer])
 | 
						|
		return;
 | 
						|
 | 
						|
	lumpnum = W_CheckNumForName(va("%sR", G_BuildMapName(gamemap)));
 | 
						|
 | 
						|
	if (lumpnum != -1)
 | 
						|
		AutomapPic = W_CachePatchName(va("%sR", G_BuildMapName(gamemap)), PU_HUDGFX);
 | 
						|
	else
 | 
						|
		return; // no pic, just get outta here
 | 
						|
 | 
						|
	x = MINI_X - (AutomapPic->width/2);
 | 
						|
	y = MINI_Y - (AutomapPic->height/2);
 | 
						|
 | 
						|
	if (timeinmap > 105)
 | 
						|
	{
 | 
						|
		minimaptrans = (splitscreen ? 10 : cv_kartminimap.value);
 | 
						|
		if (timeinmap <= 113)
 | 
						|
			minimaptrans = ((((INT32)timeinmap) - 105)*minimaptrans)/(113-105);
 | 
						|
		if (!minimaptrans)
 | 
						|
			return;
 | 
						|
	}
 | 
						|
	else
 | 
						|
		return;
 | 
						|
 | 
						|
	minimaptrans = ((10-minimaptrans)<<FF_TRANSSHIFT);
 | 
						|
	splitflags |= minimaptrans;
 | 
						|
 | 
						|
	if (encoremode)
 | 
						|
		V_DrawScaledPatch(x+(AutomapPic->width), y, splitflags|V_FLIP, AutomapPic);
 | 
						|
	else
 | 
						|
		V_DrawScaledPatch(x, y, splitflags, AutomapPic);
 | 
						|
 | 
						|
	if (!splitscreen)
 | 
						|
	{
 | 
						|
		splitflags &= ~minimaptrans;
 | 
						|
		splitflags |= V_HUDTRANSHALF;
 | 
						|
	}
 | 
						|
 | 
						|
	// let offsets transfer to the heads, too!
 | 
						|
	if (encoremode)
 | 
						|
		x += SHORT(AutomapPic->leftoffset);
 | 
						|
	else
 | 
						|
		x -= SHORT(AutomapPic->leftoffset);
 | 
						|
	y -= SHORT(AutomapPic->topoffset);
 | 
						|
 | 
						|
	// Player's tiny icons on the Automap. (drawn opposite direction so player 1 is drawn last in splitscreen)
 | 
						|
	if (ghosts)
 | 
						|
	{
 | 
						|
		demoghost *g = ghosts;
 | 
						|
		while (g)
 | 
						|
		{
 | 
						|
			K_drawKartMinimapHead(g->mo, x, y, splitflags, AutomapPic);
 | 
						|
			g = g->next;
 | 
						|
		}
 | 
						|
		if (!stplyr->mo || stplyr->spectator) // do we need the latter..?
 | 
						|
			return;
 | 
						|
		dop1later = true;
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		for (i = MAXPLAYERS-1; i >= 0; i--)
 | 
						|
		{
 | 
						|
			if (!playeringame[i])
 | 
						|
				continue;
 | 
						|
			if (!players[i].mo || players[i].spectator)
 | 
						|
				continue;
 | 
						|
 | 
						|
			if (!splitscreen && i == displayplayer)
 | 
						|
			{
 | 
						|
				dop1later = true; // Do displayplayer later
 | 
						|
				continue;
 | 
						|
			}
 | 
						|
 | 
						|
			if (G_BattleGametype() && players[i].kartstuff[k_bumper] <= 0)
 | 
						|
				continue;
 | 
						|
			if (players[i].kartstuff[k_hyudorotimer] > 0)
 | 
						|
			{
 | 
						|
				if (!((players[i].kartstuff[k_hyudorotimer] < 1*TICRATE/2
 | 
						|
					|| players[i].kartstuff[k_hyudorotimer] > hyudorotime-(1*TICRATE/2))
 | 
						|
					&& !(leveltime & 1)))
 | 
						|
					continue;
 | 
						|
			}
 | 
						|
 | 
						|
			K_drawKartMinimapHead(players[i].mo, x, y, splitflags, AutomapPic);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!dop1later)
 | 
						|
		return; // Don't need this
 | 
						|
 | 
						|
	splitflags &= ~V_HUDTRANSHALF;
 | 
						|
	splitflags |= V_HUDTRANS;
 | 
						|
	K_drawKartMinimapHead(stplyr->mo, x, y, splitflags, AutomapPic);
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartStartCountdown(void)
 | 
						|
{
 | 
						|
	INT32 pnum = 0, splitflags = K_calcSplitFlags(0); // 3
 | 
						|
 | 
						|
	if (leveltime >= starttime-(2*TICRATE)) // 2
 | 
						|
		pnum++;
 | 
						|
	if (leveltime >= starttime-TICRATE) // 1
 | 
						|
		pnum++;
 | 
						|
	if (leveltime >= starttime) // GO!
 | 
						|
		pnum++;
 | 
						|
	if ((leveltime % (2*5)) / 5) // blink
 | 
						|
		pnum += 4;
 | 
						|
	if (splitscreen) // splitscreen
 | 
						|
		pnum += 8;
 | 
						|
 | 
						|
	V_DrawScaledPatch(STCD_X - (SHORT(kp_startcountdown[pnum]->width)/2), STCD_Y - (SHORT(kp_startcountdown[pnum]->height)/2), splitflags, kp_startcountdown[pnum]);
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartFinish(void)
 | 
						|
{
 | 
						|
	INT32 pnum = 0, splitflags = K_calcSplitFlags(0);
 | 
						|
 | 
						|
	if (!stplyr->kartstuff[k_cardanimation] || stplyr->kartstuff[k_cardanimation] >= 2*TICRATE)
 | 
						|
		return;
 | 
						|
 | 
						|
	if ((stplyr->kartstuff[k_cardanimation] % (2*5)) / 5) // blink
 | 
						|
		pnum = 1;
 | 
						|
 | 
						|
	if (splitscreen > 1) // 3/4p, stationary FIN
 | 
						|
	{
 | 
						|
		pnum += 2;
 | 
						|
		V_DrawScaledPatch(STCD_X - (SHORT(kp_racefinish[pnum]->width)/2), STCD_Y - (SHORT(kp_racefinish[pnum]->height)/2), splitflags, kp_racefinish[pnum]);
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	//else -- 1/2p, scrolling FINISH
 | 
						|
	{
 | 
						|
		INT32 x, xval;
 | 
						|
 | 
						|
		if (splitscreen) // wide splitscreen
 | 
						|
			pnum += 4;
 | 
						|
 | 
						|
		x = ((vid.width<<FRACBITS)/vid.dupx);
 | 
						|
		xval = (SHORT(kp_racefinish[pnum]->width)<<FRACBITS);
 | 
						|
		x = ((TICRATE - stplyr->kartstuff[k_cardanimation])*(xval > x ? xval : x))/TICRATE;
 | 
						|
 | 
						|
		if (splitscreen && stplyr == &players[secondarydisplayplayer])
 | 
						|
			x = -x;
 | 
						|
 | 
						|
		V_DrawFixedPatch(x + (STCD_X<<FRACBITS) - (xval>>1),
 | 
						|
			(STCD_Y<<FRACBITS) - (SHORT(kp_racefinish[pnum]->height)<<(FRACBITS-1)),
 | 
						|
			FRACUNIT,
 | 
						|
			splitflags, kp_racefinish[pnum], NULL);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawBattleFullscreen(void)
 | 
						|
{
 | 
						|
	INT32 x = BASEVIDWIDTH/2;
 | 
						|
	INT32 y = -64+(stplyr->kartstuff[k_cardanimation]); // card animation goes from 0 to 164, 164 is the middle of the screen
 | 
						|
	INT32 splitflags = V_SNAPTOTOP; // I don't feel like properly supporting non-green resolutions, so you can have a misuse of SNAPTO instead
 | 
						|
	fixed_t scale = FRACUNIT;
 | 
						|
 | 
						|
	if (splitscreen)
 | 
						|
	{
 | 
						|
		if ((splitscreen == 1 && stplyr == &players[secondarydisplayplayer])
 | 
						|
			|| (splitscreen > 1 && (stplyr == &players[thirddisplayplayer]
 | 
						|
			|| (stplyr == &players[fourthdisplayplayer] && splitscreen > 2))))
 | 
						|
		{
 | 
						|
			y = 232-(stplyr->kartstuff[k_cardanimation]/2);
 | 
						|
			splitflags = V_SNAPTOBOTTOM;
 | 
						|
		}
 | 
						|
		else
 | 
						|
			y = -32+(stplyr->kartstuff[k_cardanimation]/2);
 | 
						|
 | 
						|
		if (splitscreen > 1)
 | 
						|
		{
 | 
						|
			scale /= 2;
 | 
						|
 | 
						|
			if (stplyr == &players[secondarydisplayplayer]
 | 
						|
				|| (stplyr == &players[fourthdisplayplayer] && splitscreen > 2))
 | 
						|
				x = 3*BASEVIDWIDTH/4;
 | 
						|
			else
 | 
						|
				x = BASEVIDWIDTH/4;
 | 
						|
		}
 | 
						|
		else
 | 
						|
		{
 | 
						|
			if (stplyr->exiting)
 | 
						|
			{
 | 
						|
				if (stplyr == &players[secondarydisplayplayer])
 | 
						|
					x = BASEVIDWIDTH-96;
 | 
						|
				else
 | 
						|
					x = 96;
 | 
						|
			}
 | 
						|
			else
 | 
						|
				scale /= 2;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (stplyr->exiting)
 | 
						|
	{
 | 
						|
		if (stplyr == &players[displayplayer])
 | 
						|
			V_DrawFadeScreen(0xFF00, 16);
 | 
						|
		if (stplyr->exiting < 6*TICRATE)
 | 
						|
		{
 | 
						|
			if (stplyr->kartstuff[k_position] == 1)
 | 
						|
				V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, kp_battlewin, NULL);
 | 
						|
			else
 | 
						|
				V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, (K_IsPlayerLosing(stplyr) ? kp_battlelose : kp_battlecool), NULL);
 | 
						|
		}
 | 
						|
		else
 | 
						|
			K_drawKartFinish();
 | 
						|
	}
 | 
						|
	else if (stplyr->kartstuff[k_bumper] <= 0 && stplyr->kartstuff[k_comebacktimer] && comeback && !stplyr->spectator)
 | 
						|
	{
 | 
						|
		UINT16 t = stplyr->kartstuff[k_comebacktimer]/(10*TICRATE);
 | 
						|
		INT32 txoff, adjust = (splitscreen > 1) ? 4 : 6; // normal string is 8, kart string is 12, half of that for ease
 | 
						|
		INT32 ty = (BASEVIDHEIGHT/2)+66;
 | 
						|
 | 
						|
		txoff = adjust;
 | 
						|
 | 
						|
		while (t)
 | 
						|
		{
 | 
						|
			txoff += adjust;
 | 
						|
			t /= 10;
 | 
						|
		}
 | 
						|
 | 
						|
		if (splitscreen)
 | 
						|
		{
 | 
						|
			if (splitscreen > 1)
 | 
						|
				ty = (BASEVIDHEIGHT/4)+33;
 | 
						|
			if ((splitscreen == 1 && stplyr == &players[secondarydisplayplayer])
 | 
						|
				|| (stplyr == &players[thirddisplayplayer] && splitscreen > 1)
 | 
						|
				|| (stplyr == &players[fourthdisplayplayer] && splitscreen > 2))
 | 
						|
				ty += (BASEVIDHEIGHT/2);
 | 
						|
		}
 | 
						|
		else
 | 
						|
			V_DrawFadeScreen(0xFF00, 16);
 | 
						|
 | 
						|
		if (!comebackshowninfo)
 | 
						|
			V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, kp_battleinfo, NULL);
 | 
						|
		else
 | 
						|
			V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, scale, splitflags, kp_battlewait, NULL);
 | 
						|
 | 
						|
		if (splitscreen > 1)
 | 
						|
			V_DrawString(x-txoff, ty, 0, va("%d", stplyr->kartstuff[k_comebacktimer]/TICRATE));
 | 
						|
		else
 | 
						|
		{
 | 
						|
			V_DrawFixedPatch(x<<FRACBITS, ty<<FRACBITS, scale, 0, kp_timeoutsticker, NULL);
 | 
						|
			V_DrawKartString(x-txoff, ty, 0, va("%d", stplyr->kartstuff[k_comebacktimer]/TICRATE));
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (netgame && !stplyr->spectator && timeinmap > 113) // FREE PLAY?
 | 
						|
	{
 | 
						|
		UINT8 i;
 | 
						|
 | 
						|
		// check to see if there's anyone else at all
 | 
						|
		for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
		{
 | 
						|
			if (i == displayplayer)
 | 
						|
				continue;
 | 
						|
			if (playeringame[i] && !stplyr->spectator)
 | 
						|
				return;
 | 
						|
		}
 | 
						|
 | 
						|
		K_drawKartFreePlay(leveltime);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawKartFirstPerson(void)
 | 
						|
{
 | 
						|
	static INT32 pnum[4], turn[4], drift[4];
 | 
						|
	INT32 pn = 0, tn = 0, dr = 0;
 | 
						|
	INT32 target = 0, splitflags = K_calcSplitFlags(V_SNAPTOBOTTOM);
 | 
						|
	INT32 x = BASEVIDWIDTH/2, y = BASEVIDHEIGHT;
 | 
						|
	fixed_t scale;
 | 
						|
	UINT8 *colmap = NULL;
 | 
						|
	ticcmd_t *cmd = &stplyr->cmd;
 | 
						|
 | 
						|
	if (stplyr->spectator || !stplyr->mo || (stplyr->mo->flags2 & MF2_DONTDRAW))
 | 
						|
		return;
 | 
						|
 | 
						|
	if (stplyr == &players[secondarydisplayplayer] && splitscreen)
 | 
						|
		{ pn = pnum[1]; tn = turn[1]; dr = drift[1]; }
 | 
						|
	else if (stplyr == &players[thirddisplayplayer] && splitscreen > 1)
 | 
						|
		{ pn = pnum[2]; tn = turn[2]; dr = drift[2]; }
 | 
						|
	else if (stplyr == &players[fourthdisplayplayer] && splitscreen > 2)
 | 
						|
		{ pn = pnum[3]; tn = turn[3]; dr = drift[3]; }
 | 
						|
	else
 | 
						|
		{ pn = pnum[0]; tn = turn[0]; dr = drift[0]; }
 | 
						|
 | 
						|
	if (splitscreen)
 | 
						|
	{
 | 
						|
		y >>= 1;
 | 
						|
		if (splitscreen > 1)
 | 
						|
			x >>= 1;
 | 
						|
	}
 | 
						|
 | 
						|
	{
 | 
						|
		if (stplyr->speed < FixedMul(stplyr->runspeed, stplyr->mo->scale) && (leveltime & 1) && !splitscreen)
 | 
						|
			y++;
 | 
						|
		// the following isn't EXPLICITLY right, it just gets the result we want, but i'm too lazy to look up the right way to do it
 | 
						|
		if (stplyr->mo->flags2 & MF2_SHADOW)
 | 
						|
			splitflags |= FF_TRANS80;
 | 
						|
		else if (stplyr->mo->frame & FF_TRANSMASK)
 | 
						|
			splitflags |= (stplyr->mo->frame & FF_TRANSMASK);
 | 
						|
	}
 | 
						|
 | 
						|
	if (cmd->driftturn > 400) // strong left turn
 | 
						|
		target = 2;
 | 
						|
	else if (cmd->driftturn < -400) // strong right turn
 | 
						|
		target = -2;
 | 
						|
	else if (cmd->driftturn > 0) // weak left turn
 | 
						|
		target = 1;
 | 
						|
	else if (cmd->driftturn < 0) // weak right turn
 | 
						|
		target = -1;
 | 
						|
	else // forward
 | 
						|
		target = 0;
 | 
						|
 | 
						|
	if (encoremode)
 | 
						|
		target = -target;
 | 
						|
 | 
						|
	if (pn < target)
 | 
						|
		pn++;
 | 
						|
	else if (pn > target)
 | 
						|
		pn--;
 | 
						|
 | 
						|
	if (pn < 0)
 | 
						|
		splitflags |= V_FLIP; // right turn
 | 
						|
 | 
						|
	target = abs(pn);
 | 
						|
	if (target > 2)
 | 
						|
		target = 2;
 | 
						|
 | 
						|
	x <<= FRACBITS;
 | 
						|
	y <<= FRACBITS;
 | 
						|
 | 
						|
	if (tn != cmd->driftturn/50)
 | 
						|
		tn -= (tn - (cmd->driftturn/50))/8;
 | 
						|
 | 
						|
	if (dr != stplyr->kartstuff[k_drift]*16)
 | 
						|
		dr -= (dr - (stplyr->kartstuff[k_drift]*16))/8;
 | 
						|
 | 
						|
	if (splitscreen == 1)
 | 
						|
	{
 | 
						|
		scale = (2*FRACUNIT)/3;
 | 
						|
		y += FRACUNIT/(vid.dupx < vid.dupy ? vid.dupx : vid.dupy); // correct a one-pixel gap on the screen view (not the basevid view)
 | 
						|
	}
 | 
						|
	else if (splitscreen)
 | 
						|
		scale = FRACUNIT/2;
 | 
						|
	else
 | 
						|
		scale = FRACUNIT;
 | 
						|
 | 
						|
	if (stplyr->mo)
 | 
						|
	{
 | 
						|
		INT32 dsone = K_GetKartDriftSparkValue(stplyr);
 | 
						|
		INT32 dstwo = dsone*2;
 | 
						|
		INT32 dsthree = dstwo*2;
 | 
						|
 | 
						|
#ifndef DONTLIKETOASTERSFPTWEAKS
 | 
						|
		{
 | 
						|
			const angle_t ang = R_PointToAngle2(0, 0, stplyr->rmomx, stplyr->rmomy) - stplyr->frameangle;
 | 
						|
			// yes, the following is correct. no, you do not need to swap the x and y.
 | 
						|
			fixed_t xoffs = -P_ReturnThrustY(stplyr->mo, ang, (BASEVIDWIDTH<<(FRACBITS-2))/2);
 | 
						|
			fixed_t yoffs = -(P_ReturnThrustX(stplyr->mo, ang, 4*FRACUNIT) - 4*FRACUNIT);
 | 
						|
 | 
						|
			if (splitscreen)
 | 
						|
				xoffs = FixedMul(xoffs, scale);
 | 
						|
 | 
						|
			xoffs -= (tn)*scale;
 | 
						|
			xoffs -= (dr)*scale;
 | 
						|
 | 
						|
			if (stplyr->frameangle == stplyr->mo->angle)
 | 
						|
			{
 | 
						|
				const fixed_t mag = FixedDiv(stplyr->speed, 10*stplyr->mo->scale);
 | 
						|
 | 
						|
				if (mag < FRACUNIT)
 | 
						|
				{
 | 
						|
					xoffs = FixedMul(xoffs, mag);
 | 
						|
					if (!splitscreen)
 | 
						|
						yoffs = FixedMul(yoffs, mag);
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (stplyr->mo->momz > 0) // TO-DO: Draw more of the kart so we can remove this if!
 | 
						|
				yoffs += stplyr->mo->momz/3;
 | 
						|
 | 
						|
			if (encoremode)
 | 
						|
				x -= xoffs;
 | 
						|
			else
 | 
						|
				x += xoffs;
 | 
						|
			if (!splitscreen)
 | 
						|
				y += yoffs;
 | 
						|
		}
 | 
						|
 | 
						|
		// drift sparks!
 | 
						|
		if ((leveltime & 1) && (stplyr->kartstuff[k_driftcharge] >= dsthree))
 | 
						|
			colmap = R_GetTranslationColormap(TC_RAINBOW, (UINT8)(1 + (leveltime % (MAXSKINCOLORS-1))), 0);
 | 
						|
		else if ((leveltime & 1) && (stplyr->kartstuff[k_driftcharge] >= dstwo))
 | 
						|
			colmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_KETCHUP, 0);
 | 
						|
		else if ((leveltime & 1) && (stplyr->kartstuff[k_driftcharge] >= dsone))
 | 
						|
			colmap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SAPPHIRE, 0);
 | 
						|
		else
 | 
						|
#endif
 | 
						|
		// invincibility/grow/shrink!
 | 
						|
		if (stplyr->mo->colorized && stplyr->mo->color)
 | 
						|
			colmap = R_GetTranslationColormap(TC_RAINBOW, stplyr->mo->color, 0);
 | 
						|
	}
 | 
						|
 | 
						|
	V_DrawFixedPatch(x, y, scale, splitflags, kp_fpview[target], colmap);
 | 
						|
 | 
						|
	if (stplyr == &players[secondarydisplayplayer] && splitscreen)
 | 
						|
		{ pnum[1] = pn; turn[1] = tn; drift[1] = dr; }
 | 
						|
	else if (stplyr == &players[thirddisplayplayer] && splitscreen > 1)
 | 
						|
		{ pnum[2] = pn; turn[2] = tn; drift[2] = dr; }
 | 
						|
	else if (stplyr == &players[fourthdisplayplayer] && splitscreen > 2)
 | 
						|
		{ pnum[3] = pn; turn[3] = tn; drift[3] = dr; }
 | 
						|
	else
 | 
						|
		{ pnum[0] = pn; turn[0] = tn; drift[0] = dr; }
 | 
						|
}
 | 
						|
 | 
						|
// doesn't need to ever support 4p
 | 
						|
static void K_drawInput(void)
 | 
						|
{
 | 
						|
	static INT32 pn = 0;
 | 
						|
	INT32 target = 0, splitflags = (V_SNAPTOBOTTOM|V_SNAPTORIGHT);
 | 
						|
	INT32 x = BASEVIDWIDTH - 32, y = BASEVIDHEIGHT-24, offs, col;
 | 
						|
	const INT32 accent1 = splitflags|colortranslations[stplyr->skincolor][5];
 | 
						|
	const INT32 accent2 = splitflags|colortranslations[stplyr->skincolor][9];
 | 
						|
	ticcmd_t *cmd = &stplyr->cmd;
 | 
						|
 | 
						|
	if (timeinmap <= 105)
 | 
						|
		return;
 | 
						|
 | 
						|
	if (timeinmap < 113)
 | 
						|
	{
 | 
						|
		INT32 count = ((INT32)(timeinmap) - 105);
 | 
						|
		offs = (titledemo ? 128 : 64);
 | 
						|
		while (count-- > 0)
 | 
						|
			offs >>= 1;
 | 
						|
		x += offs;
 | 
						|
	}
 | 
						|
 | 
						|
	if (titledemo)
 | 
						|
	{
 | 
						|
		V_DrawTinyScaledPatch(x-54, 128, splitflags, W_CachePatchName("TTKBANNR", PU_CACHE));
 | 
						|
		V_DrawTinyScaledPatch(x-54, 128+25, splitflags, W_CachePatchName("TTKART", PU_CACHE));
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
#define BUTTW 8
 | 
						|
#define BUTTH 11
 | 
						|
 | 
						|
#define drawbutt(xoffs, butt, symb)\
 | 
						|
	if (stplyr->cmd.buttons & butt)\
 | 
						|
	{\
 | 
						|
		offs = 2;\
 | 
						|
		col = accent1;\
 | 
						|
	}\
 | 
						|
	else\
 | 
						|
	{\
 | 
						|
		offs = 0;\
 | 
						|
		col = accent2;\
 | 
						|
		V_DrawFill(x+(xoffs), y+BUTTH, BUTTW-1, 2, splitflags|31);\
 | 
						|
	}\
 | 
						|
	V_DrawFill(x+(xoffs), y+offs, BUTTW-1, BUTTH, col);\
 | 
						|
	V_DrawFixedPatch((x+1+(xoffs))<<FRACBITS, (y+offs+1)<<FRACBITS, FRACUNIT, splitflags, tny_font[symb-HU_FONTSTART], NULL)
 | 
						|
 | 
						|
	drawbutt(-2*BUTTW, BT_ACCELERATE, 'A');
 | 
						|
	drawbutt(  -BUTTW, BT_BRAKE,      'B');
 | 
						|
	drawbutt(       0, BT_DRIFT,      'D');
 | 
						|
	drawbutt(   BUTTW, BT_ATTACK,     'I');
 | 
						|
 | 
						|
#undef drawbutt
 | 
						|
 | 
						|
#undef BUTTW
 | 
						|
#undef BUTTH
 | 
						|
 | 
						|
	y -= 1;
 | 
						|
 | 
						|
	if (!cmd->driftturn) // no turn
 | 
						|
		target = 0;
 | 
						|
	else // turning of multiple strengths!
 | 
						|
	{
 | 
						|
		target = ((abs(cmd->driftturn) - 1)/125)+1;
 | 
						|
		if (target > 4)
 | 
						|
			target = 4;
 | 
						|
		if (cmd->driftturn < 0)
 | 
						|
			target = -target;
 | 
						|
	}
 | 
						|
 | 
						|
	if (pn != target)
 | 
						|
	{
 | 
						|
		if (abs(pn - target) == 1)
 | 
						|
			pn = target;
 | 
						|
		else if (pn < target)
 | 
						|
			pn += 2;
 | 
						|
		else //if (pn > target)
 | 
						|
			pn -= 2;
 | 
						|
	}
 | 
						|
 | 
						|
	if (pn < 0)
 | 
						|
	{
 | 
						|
		splitflags |= V_FLIP; // right turn
 | 
						|
		x--;
 | 
						|
	}
 | 
						|
 | 
						|
	target = abs(pn);
 | 
						|
	if (target > 4)
 | 
						|
		target = 4;
 | 
						|
 | 
						|
	if (!stplyr->skincolor)
 | 
						|
		V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, splitflags, kp_inputwheel[target], NULL);
 | 
						|
	else
 | 
						|
	{
 | 
						|
		UINT8 *colormap;
 | 
						|
		colormap = R_GetTranslationColormap(0, stplyr->skincolor, 0);
 | 
						|
		V_DrawFixedPatch(x<<FRACBITS, y<<FRACBITS, FRACUNIT, splitflags, kp_inputwheel[target], colormap);
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawChallengerScreen(void)
 | 
						|
{
 | 
						|
	// This is an insanely complicated animation.
 | 
						|
	static UINT8 anim[52] = {
 | 
						|
		0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13, // frame 1-14, 2 tics: HERE COMES A NEW slides in
 | 
						|
		14,14,14,14,14,14, // frame 15, 6 tics: pause on the W
 | 
						|
		15,16,17,18, // frame 16-19, 1 tic: CHALLENGER approaches screen
 | 
						|
		19,20,19,20,19,20,19,20,19,20, // frame 20-21, 1 tic, 5 alternating: all text vibrates from impact
 | 
						|
		21,22,23,24 // frame 22-25, 1 tic: CHALLENGER turns gold
 | 
						|
	};
 | 
						|
	const UINT8 offset = min(52-1, (3*TICRATE)-mapreset);
 | 
						|
 | 
						|
	V_DrawFadeScreen(0xFF00, 16); // Fade out
 | 
						|
	V_DrawScaledPatch(0, 0, 0, kp_challenger[anim[offset]]);
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawLapStartAnim(void)
 | 
						|
{
 | 
						|
	// This is an EVEN MORE insanely complicated animation.
 | 
						|
	const UINT8 progress = 80-stplyr->kartstuff[k_lapanimation];
 | 
						|
	UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, 0);
 | 
						|
 | 
						|
	V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)))*FRACUNIT,
 | 
						|
		(48 - (32*max(0, progress-76)))*FRACUNIT,
 | 
						|
		FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
		(modeattacking ? kp_lapanim_emblem[1] : kp_lapanim_emblem[0]), colormap);
 | 
						|
 | 
						|
	if (stplyr->kartstuff[k_laphand] >= 1 && stplyr->kartstuff[k_laphand] <= 3)
 | 
						|
	{
 | 
						|
		V_DrawFixedPatch((BASEVIDWIDTH/2 + (32*max(0, stplyr->kartstuff[k_lapanimation]-76)))*FRACUNIT,
 | 
						|
			(48 - (32*max(0, progress-76))
 | 
						|
				+ 4 - abs((signed)((leveltime % 8) - 4)))*FRACUNIT,
 | 
						|
			FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
			kp_lapanim_hand[stplyr->kartstuff[k_laphand]-1], NULL);
 | 
						|
	}
 | 
						|
 | 
						|
	if (stplyr->laps == (UINT8)(cv_numlaps.value - 1))
 | 
						|
	{
 | 
						|
		V_DrawFixedPatch((62 - (32*max(0, progress-76)))*FRACUNIT, // 27
 | 
						|
			30*FRACUNIT, // 24
 | 
						|
			FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
			kp_lapanim_final[min(progress/2, 10)], NULL);
 | 
						|
 | 
						|
		if (progress/2-12 >= 0)
 | 
						|
		{
 | 
						|
			V_DrawFixedPatch((188 + (32*max(0, progress-76)))*FRACUNIT, // 194
 | 
						|
				30*FRACUNIT, // 24
 | 
						|
				FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
				kp_lapanim_lap[min(progress/2-12, 6)], NULL);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	else
 | 
						|
	{
 | 
						|
		V_DrawFixedPatch((82 - (32*max(0, progress-76)))*FRACUNIT, // 61
 | 
						|
			30*FRACUNIT, // 24
 | 
						|
			FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
			kp_lapanim_lap[min(progress/2, 6)], NULL);
 | 
						|
 | 
						|
		if (progress/2-8 >= 0)
 | 
						|
		{
 | 
						|
			V_DrawFixedPatch((188 + (32*max(0, progress-76)))*FRACUNIT, // 194
 | 
						|
				30*FRACUNIT, // 24
 | 
						|
				FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
				kp_lapanim_number[(((UINT32)stplyr->laps+1) / 10)][min(progress/2-8, 2)], NULL);
 | 
						|
 | 
						|
			if (progress/2-10 >= 0)
 | 
						|
			{
 | 
						|
				V_DrawFixedPatch((208 + (32*max(0, progress-76)))*FRACUNIT, // 221
 | 
						|
					30*FRACUNIT, // 24
 | 
						|
					FRACUNIT, V_SNAPTOTOP|V_HUDTRANS,
 | 
						|
					kp_lapanim_number[(((UINT32)stplyr->laps+1) % 10)][min(progress/2-10, 2)], NULL);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
void K_drawKartFreePlay(UINT32 flashtime)
 | 
						|
{
 | 
						|
	// no splitscreen support because it's not FREE PLAY if you have more than one player in-game
 | 
						|
 | 
						|
	if ((flashtime % TICRATE) < TICRATE/2)
 | 
						|
		return;
 | 
						|
 | 
						|
	V_DrawKartString((BASEVIDWIDTH - (LAPS_X+1)) - (12*9), // mirror the laps thingy
 | 
						|
		LAPS_Y+3, V_SNAPTOBOTTOM|V_SNAPTORIGHT, "FREE PLAY");
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawDistributionDebugger(void)
 | 
						|
{
 | 
						|
	patch_t *items[NUMKARTRESULTS] = {
 | 
						|
		kp_sadface[1],
 | 
						|
		kp_sneaker[1],
 | 
						|
		kp_rocketsneaker[1],
 | 
						|
		kp_invincibility[7],
 | 
						|
		kp_banana[1],
 | 
						|
		kp_eggman[1],
 | 
						|
		kp_orbinaut[4],
 | 
						|
		kp_jawz[1],
 | 
						|
		kp_mine[1],
 | 
						|
		kp_ballhog[1],
 | 
						|
		kp_selfpropelledbomb[1],
 | 
						|
		kp_grow[1],
 | 
						|
		kp_shrink[1],
 | 
						|
		kp_thundershield[1],
 | 
						|
		kp_hyudoro[1],
 | 
						|
		kp_pogospring[1],
 | 
						|
		kp_kitchensink[1],
 | 
						|
 | 
						|
		kp_sneaker[1],
 | 
						|
		kp_banana[1],
 | 
						|
		kp_banana[1],
 | 
						|
		kp_orbinaut[4],
 | 
						|
		kp_orbinaut[4],
 | 
						|
		kp_jawz[1]
 | 
						|
	};
 | 
						|
	INT32 useodds = 0;
 | 
						|
	INT32 pingame = 0, bestbumper = 0;
 | 
						|
	INT32 i;
 | 
						|
	INT32 x = -9, y = -9;
 | 
						|
	boolean dontforcespb = false;
 | 
						|
 | 
						|
	if (stplyr != &players[displayplayer]) // only for p1
 | 
						|
		return;
 | 
						|
 | 
						|
	// The only code duplication from the Kart, just to avoid the actual item function from calculating pingame twice
 | 
						|
	for (i = 0; i < MAXPLAYERS; i++)
 | 
						|
	{
 | 
						|
		if (!playeringame[i] || players[i].spectator)
 | 
						|
			continue;
 | 
						|
		pingame++;
 | 
						|
		if (players[i].exiting)
 | 
						|
			dontforcespb = true;
 | 
						|
		if (players[i].kartstuff[k_bumper] > bestbumper)
 | 
						|
			bestbumper = players[i].kartstuff[k_bumper];
 | 
						|
	}
 | 
						|
 | 
						|
	useodds = K_FindUseodds(stplyr, 0, pingame, bestbumper, (spbplace != -1 && stplyr->kartstuff[k_position] == spbplace+1), dontforcespb);
 | 
						|
 | 
						|
	for (i = 1; i < NUMKARTRESULTS; i++)
 | 
						|
	{
 | 
						|
		const INT32 itemodds = K_KartGetItemOdds(useodds, i, 0);
 | 
						|
		if (itemodds <= 0)
 | 
						|
			continue;
 | 
						|
 | 
						|
		V_DrawScaledPatch(x, y, V_HUDTRANS|V_SNAPTOTOP, items[i]);
 | 
						|
		V_DrawThinString(x+11, y+31, V_HUDTRANS|V_SNAPTOTOP, va("%d", itemodds));
 | 
						|
 | 
						|
		// Display amount for multi-items
 | 
						|
		if (i >= NUMKARTITEMS)
 | 
						|
		{
 | 
						|
			INT32 amount;
 | 
						|
			switch (i)
 | 
						|
			{
 | 
						|
				case KRITEM_TENFOLDBANANA:
 | 
						|
					amount = 10;
 | 
						|
					break;
 | 
						|
				case KRITEM_QUADORBINAUT:
 | 
						|
					amount = 4;
 | 
						|
					break;
 | 
						|
				case KRITEM_DUALJAWZ:
 | 
						|
					amount = 2;
 | 
						|
					break;
 | 
						|
				default:
 | 
						|
					amount = 3;
 | 
						|
					break;
 | 
						|
			}
 | 
						|
			V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOTOP, va("x%d", amount));
 | 
						|
		}
 | 
						|
 | 
						|
		x += 32;
 | 
						|
		if (x >= 297)
 | 
						|
		{
 | 
						|
			x = -9;
 | 
						|
			y += 32;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	V_DrawString(0, 0, V_HUDTRANS|V_SNAPTOTOP, va("USEODDS %d", useodds));
 | 
						|
}
 | 
						|
 | 
						|
static void K_drawCheckpointDebugger(void)
 | 
						|
{
 | 
						|
	if (stplyr != &players[displayplayer]) // only for p1
 | 
						|
		return;
 | 
						|
 | 
						|
	if (stplyr->starpostnum >= (numstarposts - (numstarposts/2)))
 | 
						|
		V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Can finish)", stplyr->starpostnum, numstarposts));
 | 
						|
	else
 | 
						|
		V_DrawString(8, 184, 0, va("Checkpoint: %d / %d (Skip: %d)", stplyr->starpostnum, numstarposts, ((numstarposts/2) + stplyr->starpostnum)));
 | 
						|
	V_DrawString(8, 192, 0, va("Waypoint dist: Prev %d, Next %d", stplyr->kartstuff[k_prevcheck], stplyr->kartstuff[k_nextcheck]));
 | 
						|
}
 | 
						|
 | 
						|
void K_drawKartHUD(void)
 | 
						|
{
 | 
						|
	boolean isfreeplay = false;
 | 
						|
 | 
						|
	// Define the X and Y for each drawn object
 | 
						|
	// This is handled by console/menu values
 | 
						|
	K_initKartHUD();
 | 
						|
 | 
						|
	// Draw that fun first person HUD! Drawn ASAP so it looks more "real".
 | 
						|
	if ((stplyr == &players[displayplayer] && !camera.chase)
 | 
						|
		|| ((splitscreen && stplyr == &players[secondarydisplayplayer]) && !camera2.chase)
 | 
						|
		|| ((splitscreen > 1 && stplyr == &players[thirddisplayplayer]) && !camera3.chase)
 | 
						|
		|| ((splitscreen > 2 && stplyr == &players[fourthdisplayplayer]) && !camera4.chase))
 | 
						|
		K_drawKartFirstPerson();
 | 
						|
 | 
						|
	if (splitscreen == 2) // Player 4 in 3P is the minimap :p
 | 
						|
	{
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
		if (LUA_HudEnabled(hud_minimap))
 | 
						|
#endif
 | 
						|
		K_drawKartMinimap();
 | 
						|
	}
 | 
						|
 | 
						|
	// Draw full screen stuff that turns off the rest of the HUD
 | 
						|
	if (mapreset && stplyr == &players[displayplayer])
 | 
						|
	{
 | 
						|
		K_drawChallengerScreen();
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((G_BattleGametype())
 | 
						|
		&& (stplyr->exiting
 | 
						|
		|| (stplyr->kartstuff[k_bumper] <= 0
 | 
						|
		&& stplyr->kartstuff[k_comebacktimer]
 | 
						|
		&& comeback
 | 
						|
		&& stplyr->playerstate == PST_LIVE)))
 | 
						|
	{
 | 
						|
		K_drawBattleFullscreen();
 | 
						|
		return;
 | 
						|
	}
 | 
						|
 | 
						|
	// Draw the CHECK indicator before the other items, so it's overlapped by everything else
 | 
						|
	if (cv_kartcheck.value && !splitscreen && !players[displayplayer].exiting)
 | 
						|
		K_drawKartPlayerCheck();
 | 
						|
 | 
						|
	if (splitscreen == 0 && cv_kartminimap.value && !titledemo)
 | 
						|
	{
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
		if (LUA_HudEnabled(hud_minimap))
 | 
						|
#endif
 | 
						|
			K_drawKartMinimap(); // 3P splitscreen is handled above
 | 
						|
 | 
						|
	}
 | 
						|
 | 
						|
	// Draw the item window
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
	if (LUA_HudEnabled(hud_item))
 | 
						|
#endif
 | 
						|
		K_drawKartItem();
 | 
						|
 | 
						|
	// Draw WANTED status
 | 
						|
	if (G_BattleGametype())
 | 
						|
	{
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
		if (LUA_HudEnabled(hud_wanted))
 | 
						|
#endif
 | 
						|
			K_drawKartWanted();
 | 
						|
	}
 | 
						|
 | 
						|
	// If not splitscreen, draw...
 | 
						|
	if (!splitscreen && !titledemo)
 | 
						|
	{
 | 
						|
		// Draw the timestamp
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
		if (LUA_HudEnabled(hud_time))
 | 
						|
#endif
 | 
						|
			K_drawKartTimestamp(stplyr->realtime, TIME_X, TIME_Y, gamemap, 0);
 | 
						|
 | 
						|
		if (!modeattacking)
 | 
						|
		{
 | 
						|
			// The top-four faces on the left
 | 
						|
			/*#ifdef HAVE_BLUA
 | 
						|
			if (LUA_HudEnabled(hud_minirankings))
 | 
						|
			#endif*/
 | 
						|
				isfreeplay = K_drawKartPositionFaces();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if (!stplyr->spectator) // Bottom of the screen elements, don't need in spectate mode
 | 
						|
	{
 | 
						|
		if (G_RaceGametype()) // Race-only elements
 | 
						|
		{
 | 
						|
			if (!titledemo)
 | 
						|
			{
 | 
						|
				// Draw the lap counter
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
				if (LUA_HudEnabled(hud_gametypeinfo))
 | 
						|
#endif
 | 
						|
					K_drawKartLaps();
 | 
						|
 | 
						|
				if (!splitscreen)
 | 
						|
				{
 | 
						|
					// Draw the speedometer
 | 
						|
					// TODO: Make a better speedometer.
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
				if (LUA_HudEnabled(hud_speedometer))
 | 
						|
#endif
 | 
						|
					K_drawKartSpeedometer();
 | 
						|
				}
 | 
						|
			}
 | 
						|
 | 
						|
			if (isfreeplay)
 | 
						|
				;
 | 
						|
			else if (!modeattacking)
 | 
						|
			{
 | 
						|
				// Draw the numerical position
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
				if (LUA_HudEnabled(hud_position))
 | 
						|
#endif
 | 
						|
					K_DrawKartPositionNum(stplyr->kartstuff[k_position]);
 | 
						|
			}
 | 
						|
			else //if (!(demoplayback && hu_showscores))
 | 
						|
			{
 | 
						|
				// Draw the input UI
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
				if (LUA_HudEnabled(hud_position))
 | 
						|
#endif
 | 
						|
					K_drawInput();
 | 
						|
			}
 | 
						|
		}
 | 
						|
		else if (G_BattleGametype()) // Battle-only
 | 
						|
		{
 | 
						|
			// Draw the hits left!
 | 
						|
#ifdef HAVE_BLUA
 | 
						|
			if (LUA_HudEnabled(hud_gametypeinfo))
 | 
						|
#endif
 | 
						|
				K_drawKartBumpersOrKarma();
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Draw the countdowns after everything else.
 | 
						|
	if (leveltime >= starttime-(3*TICRATE)
 | 
						|
		&& leveltime < starttime+TICRATE)
 | 
						|
		K_drawKartStartCountdown();
 | 
						|
	else if (countdown && (!splitscreen || !stplyr->exiting))
 | 
						|
	{
 | 
						|
		char *countstr = va("%d", countdown/TICRATE);
 | 
						|
 | 
						|
		if (splitscreen > 1)
 | 
						|
			V_DrawCenteredString(BASEVIDWIDTH/4, LAPS_Y+1, K_calcSplitFlags(0), countstr);
 | 
						|
		else
 | 
						|
		{
 | 
						|
			INT32 karlen = strlen(countstr)*6; // half of 12
 | 
						|
			V_DrawKartString((BASEVIDWIDTH/2)-karlen, LAPS_Y+3, K_calcSplitFlags(0), countstr);
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Race overlays
 | 
						|
	if (G_RaceGametype())
 | 
						|
	{
 | 
						|
		if (stplyr->exiting)
 | 
						|
			K_drawKartFinish();
 | 
						|
		else if (stplyr->kartstuff[k_lapanimation] && !splitscreen)
 | 
						|
			K_drawLapStartAnim();
 | 
						|
	}
 | 
						|
 | 
						|
	if (modeattacking) // everything after here is MP and debug only
 | 
						|
		return;
 | 
						|
 | 
						|
	if (G_BattleGametype() && !splitscreen && (stplyr->kartstuff[k_yougotem] % 2)) // * YOU GOT EM *
 | 
						|
		V_DrawScaledPatch(BASEVIDWIDTH/2 - (SHORT(kp_yougotem->width)/2), 32, V_HUDTRANS, kp_yougotem);
 | 
						|
 | 
						|
	// Draw FREE PLAY.
 | 
						|
	if (isfreeplay && !stplyr->spectator && timeinmap > 113)
 | 
						|
		K_drawKartFreePlay(leveltime);
 | 
						|
 | 
						|
	if (cv_kartdebugdistribution.value)
 | 
						|
		K_drawDistributionDebugger();
 | 
						|
 | 
						|
	if (cv_kartdebugcheckpoint.value)
 | 
						|
		K_drawCheckpointDebugger();
 | 
						|
 | 
						|
	if (cv_kartdebugnodes.value)
 | 
						|
	{
 | 
						|
		UINT8 p;
 | 
						|
		for (p = 0; p < MAXPLAYERS; p++)
 | 
						|
			V_DrawString(8, 64+(8*p), V_YELLOWMAP, va("%d - %d", p, playernode[p]));
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
//}
 |