g_game.c 129 KB
Newer Older
Alam Ed Arias committed
1 2 3 4
// SONIC ROBO BLAST 2
//-----------------------------------------------------------------------------
// Copyright (C) 1993-1996 by id Software, Inc.
// Copyright (C) 1998-2000 by DooM Legacy Team.
James R. committed
5
// Copyright (C) 1999-2020 by Sonic Team Junior.
Alam Ed Arias committed
6 7 8 9 10 11 12 13 14 15 16 17
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file  g_game.c
/// \brief game loop functions, events handling

#include "doomdef.h"
#include "console.h"
#include "d_main.h"
#include "d_player.h"
18
#include "d_clisrv.h"
Alam Ed Arias committed
19 20 21 22 23 24 25 26 27 28 29
#include "f_finale.h"
#include "p_setup.h"
#include "p_saveg.h"
#include "i_system.h"
#include "am_map.h"
#include "m_random.h"
#include "p_local.h"
#include "r_draw.h"
#include "r_main.h"
#include "s_sound.h"
#include "g_game.h"
30
#include "g_demo.h"
Alam Ed Arias committed
31 32 33 34 35 36 37 38 39 40 41
#include "m_cheat.h"
#include "m_misc.h"
#include "m_menu.h"
#include "m_argv.h"
#include "hu_stuff.h"
#include "st_stuff.h"
#include "z_zone.h"
#include "i_video.h"
#include "byteptr.h"
#include "i_joy.h"
#include "r_local.h"
42
#include "r_skins.h"
Alam Ed Arias committed
43 44 45 46 47 48
#include "y_inter.h"
#include "v_video.h"
#include "lua_hook.h"
#include "b_bot.h"
#include "m_cond.h" // condition sets

Jaime Ita Passos committed
49 50
#include "lua_hud.h"

Alam Ed Arias committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
gameaction_t gameaction;
gamestate_t gamestate = GS_NULL;
UINT8 ultimatemode = false;

boolean botingame;
UINT8 botskin;
UINT8 botcolor;

JoyType_t Joystick;
JoyType_t Joystick2;

// 1024 bytes is plenty for a savegame
#define SAVEGAMESIZE (1024)

char gamedatafilename[64] = "gamedata.dat";
char timeattackfolder[64] = "main";
char customversionstring[32] = "\0";

static void G_DoCompleted(void);
static void G_DoStartContinue(void);
static void G_DoContinued(void);
static void G_DoWorldDone(void);

74 75
char   mapmusname[7]; // Music name
UINT16 mapmusflags; // Track and reset bit
76
UINT32 mapmusposition; // Position to jump to
77

Alam Ed Arias committed
78
INT16 gamemap = 1;
79
UINT32 maptol;
Alam Ed Arias committed
80 81
UINT8 globalweather = 0;
INT32 curWeather = PRECIP_NONE;
82
INT32 cursaveslot = 0; // Auto-save 1p savegame slot
Sal committed
83
//INT16 lastmapsaved = 0; // Last map we auto-saved at
84
INT16 lastmaploaded = 0; // Last map the game loaded
Alam Ed Arias committed
85 86
boolean gamecomplete = false;

87 88 89
UINT8 numgameovers = 0; // for startinglives balance
SINT8 startinglivesbalance[maxgameovers+1] = {3, 5, 7, 9, 12, 15, 20, 25, 30, 40, 50, 75, 99, 0x7F};

Alam Ed Arias committed
90 91 92 93 94 95 96 97
UINT16 mainwads = 0;
boolean modifiedgame; // Set if homebrew PWAD stuff has been added.
boolean savemoddata = false;
UINT8 paused;
UINT8 modeattacking = ATTACKING_NONE;
boolean disableSpeedAdjust = false;
boolean imcontinuing = false;
boolean runemeraldmanager = false;
98
UINT16 emeraldspawndelay = 60*TICRATE;
Alam Ed Arias committed
99 100

// menu demo things
101
UINT8  numDemos      = 0;
Alam Ed Arias committed
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
UINT32 demoDelayTime = 15*TICRATE;
UINT32 demoIdleTime  = 3*TICRATE;

boolean netgame; // only true if packets are broadcast
boolean multiplayer;
boolean playeringame[MAXPLAYERS];
boolean addedtogame;
player_t players[MAXPLAYERS];

INT32 consoleplayer; // player taking events and displaying
INT32 displayplayer; // view being displayed
INT32 secondarydisplayplayer; // for splitscreen

tic_t gametic;
tic_t levelstarttic; // gametic at level start
toaster committed
117
UINT32 ssspheres; // old special stage
Alam Ed Arias committed
118 119 120 121
INT16 lastmap; // last level you were at (returning from special stages)
tic_t timeinmap; // Ticker for time spent in level (used for levelcard display)

INT16 spstage_start;
122
INT16 sstage_start, sstage_end, smpstage_start, smpstage_end;
Alam Ed Arias committed
123

124
INT16 titlemap = 0;
125
boolean hidetitlepics = false;
126
INT16 bootmap; //bootmap for loading a map on startup
127

128 129
INT16 tutorialmap = 0; // map to load for tutorial
boolean tutorialmode = false; // are we in a tutorial right now?
130
INT32 tutorialgcs = gcs_custom; // which control scheme is loaded?
131 132 133
INT32 tutorialusemouse = 0; // store cv_usemouse user value
INT32 tutorialfreelook = 0; // store cv_alwaysfreelook user value
INT32 tutorialmousemove = 0; // store cv_mousemove user value
134
INT32 tutorialanalog = 0; // store cv_analog[0] user value
135

Alam Ed Arias committed
136 137 138 139
boolean looptitle = false;

UINT8 skincolor_redteam = SKINCOLOR_RED;
UINT8 skincolor_blueteam = SKINCOLOR_BLUE;
140 141
UINT8 skincolor_redring = SKINCOLOR_SALMON;
UINT8 skincolor_bluering = SKINCOLOR_CORNFLOWER;
Alam Ed Arias committed
142 143 144

tic_t countdowntimer = 0;
boolean countdowntimeup = false;
145
boolean exitfadestarted = false;
Alam Ed Arias committed
146 147

cutscene_t *cutscenes[128];
148
textprompt_t *textprompts[MAX_PROMPTS];
Alam Ed Arias committed
149 150

INT16 nextmapoverride;
151
UINT8 skipstats;
Alam Ed Arias committed
152 153 154 155 156 157 158 159 160 161 162 163 164 165 166

// Pointers to each CTF flag
mobj_t *redflag;
mobj_t *blueflag;
// Pointers to CTF spawn location
mapthing_t *rflagpoint;
mapthing_t *bflagpoint;

struct quake quake;

// Map Header Information
mapheader_t* mapheaderinfo[NUMMAPS] = {NULL};

static boolean exitgame = false;
static boolean retrying = false;
Jaime Ita Passos committed
167
static boolean retryingmodeattack = false;
Alam Ed Arias committed
168 169 170 171

UINT8 stagefailed; // Used for GEMS BONUS? Also to see if you beat the stage.

UINT16 emeralds;
172
INT32 luabanks[NUM_LUABANKS];
Alam Ed Arias committed
173 174
UINT32 token; // Number of tokens collected in a level
UINT32 tokenlist; // List of tokens collected
175
boolean gottoken; // Did you get a token? Used for end of act
Alam Ed Arias committed
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
INT32 tokenbits; // Used for setting token bits

// Old Special Stage
INT32 sstimer; // Time allotted in the special stage

tic_t totalplaytime;
boolean gamedataloaded = false;

// Time attack data for levels
// These are dynamically allocated for space reasons now
recorddata_t *mainrecords[NUMMAPS]   = {NULL};
nightsdata_t *nightsrecords[NUMMAPS] = {NULL};
UINT8 mapvisited[NUMMAPS];

// Temporary holding place for nights data for the current map
nightsdata_t ntemprecords;

UINT32 bluescore, redscore; // CTF and Team Match team scores

// ring count... for PERFECT!
INT32 nummaprings = 0;

// Elminates unnecessary searching.
boolean CheckForBustableBlocks;
boolean CheckForBouncySector;
boolean CheckForQuicksand;
boolean CheckForMarioBlocks;
boolean CheckForFloatBob;
boolean CheckForReverseGravity;

// Powerup durations
UINT16 invulntics = 20*TICRATE;
UINT16 sneakertics = 20*TICRATE;
UINT16 flashingtics = 3*TICRATE;
UINT16 tailsflytics = 8*TICRATE;
UINT16 underwatertics = 30*TICRATE;
UINT16 spacetimetics = 11*TICRATE + (TICRATE/2);
UINT16 extralifetics = 4*TICRATE;
214
UINT16 nightslinktics = 2*TICRATE;
Alam Ed Arias committed
215

216
INT32 gameovertics = 11*TICRATE;
Alam Ed Arias committed
217

218 219
UINT8 ammoremovaltics = 2*TICRATE;

Alam Ed Arias committed
220 221
UINT8 use1upSound = 0;
UINT8 maxXtraLife = 2; // Max extra lives from rings
222
UINT8 useContinues = 0; // Set to 1 to enable continues outside of no-save scenarioes
Alam Ed Arias committed
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251

UINT8 introtoplay;
UINT8 creditscutscene;

// Emerald locations
mobj_t *hunt1;
mobj_t *hunt2;
mobj_t *hunt3;

UINT32 countdown, countdown2; // for racing

fixed_t gravity;

INT16 autobalance; //for CTF team balance
INT16 teamscramble; //for CTF team scramble
INT16 scrambleplayers[MAXPLAYERS]; //for CTF team scramble
INT16 scrambleteams[MAXPLAYERS]; //for CTF team scramble
INT16 scrambletotal; //for CTF team scramble
INT16 scramblecount; //for CTF team scramble

INT32 cheats; //for multiplayer cheat commands

tic_t hidetime;

// Grading
UINT32 timesBeaten;
UINT32 timesBeatenWithEmeralds;
UINT32 timesBeatenUltimate;

252 253 254 255 256 257
typedef struct joystickvector2_s
{
	INT32 xaxis;
	INT32 yaxis;
} joystickvector2_t;

Alam Ed Arias committed
258 259 260 261 262 263 264 265 266 267 268
boolean precache = true; // if true, load all graphics at start

INT16 prevmap, nextmap;

static UINT8 *savebuffer;

// Analog Control
static void UserAnalog_OnChange(void);
static void UserAnalog2_OnChange(void);
static void Analog_OnChange(void);
static void Analog2_OnChange(void);
269 270 271 272
static void DirectionChar_OnChange(void);
static void DirectionChar2_OnChange(void);
static void AutoBrake_OnChange(void);
static void AutoBrake2_OnChange(void);
Alam Ed Arias committed
273 274
void SendWeaponPref(void);
void SendWeaponPref2(void);
Alam Ed Arias committed
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292

static CV_PossibleValue_t crosshair_cons_t[] = {{0, "Off"}, {1, "Cross"}, {2, "Angle"}, {3, "Point"}, {0, NULL}};
static CV_PossibleValue_t joyaxis_cons_t[] = {{0, "None"},
{1, "X-Axis"}, {2, "Y-Axis"}, {-1, "X-Axis-"}, {-2, "Y-Axis-"},
#if JOYAXISSET > 1
{3, "Z-Axis"}, {4, "X-Rudder"}, {-3, "Z-Axis-"}, {-4, "X-Rudder-"},
#endif
#if JOYAXISSET > 2
{5, "Y-Rudder"}, {6, "Z-Rudder"}, {-5, "Y-Rudder-"}, {-6, "Z-Rudder-"},
#endif
#if JOYAXISSET > 3
{7, "U-Axis"}, {8, "V-Axis"}, {-7, "U-Axis-"}, {-8, "V-Axis-"},
#endif
 {0, NULL}};
#if JOYAXISSET > 4
"More Axis Sets"
#endif

Latapostrophe committed
293 294 295 296 297 298 299 300 301 302
// don't mind me putting these here, I was lazy to figure out where else I could put those without blowing up the compiler.

// it automatically becomes compact with 20+ players, but if you like it, I guess you can turn that on!
consvar_t cv_compactscoreboard= {"compactscoreboard", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};

// chat timer thingy
static CV_PossibleValue_t chattime_cons_t[] = {{5, "MIN"}, {999, "MAX"}, {0, NULL}};
consvar_t cv_chattime = {"chattime", "8", CV_SAVE, chattime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};

// chatwidth
303 304
static CV_PossibleValue_t chatwidth_cons_t[] = {{64, "MIN"}, {300, "MAX"}, {0, NULL}};
consvar_t cv_chatwidth = {"chatwidth", "150", CV_SAVE, chatwidth_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Latapostrophe committed
305 306 307 308 309 310 311 312 313 314 315

// chatheight
static CV_PossibleValue_t chatheight_cons_t[] = {{6, "MIN"}, {22, "MAX"}, {0, NULL}};
consvar_t cv_chatheight= {"chatheight", "8", CV_SAVE, chatheight_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};

// chat notifications (do you want to hear beeps? I'd understand if you didn't.)
consvar_t cv_chatnotifications= {"chatnotifications", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};

// chat spam protection (why would you want to disable that???)
consvar_t cv_chatspamprotection= {"chatspamprotection", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};

Latapostrophe committed
316
// minichat text background
317
consvar_t cv_chatbacktint = {"chatbacktint", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
Latapostrophe committed
318

Latapostrophe committed
319
// old shit console chat. (mostly exists for stuff like terminal, not because I cared if anyone liked the old chat.)
320 321 322
static CV_PossibleValue_t consolechat_cons_t[] = {{0, "Window"}, {1, "Console"}, {2, "Window (Hidden)"}, {0, NULL}};
consvar_t cv_consolechat = {"chatmode", "Window", CV_SAVE, consolechat_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};

323 324
// Pause game upon window losing focus
consvar_t cv_pauseifunfocused = {"pauseifunfocused", "Yes", CV_SAVE, CV_YesNo, NULL, 0, NULL, NULL, 0, 0, NULL};
Latapostrophe committed
325

Alam Ed Arias committed
326 327 328
consvar_t cv_crosshair = {"crosshair", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_crosshair2 = {"crosshair2", "Cross", CV_SAVE, crosshair_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_invertmouse = {"invertmouse", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
329
consvar_t cv_alwaysfreelook = {"alwaysmlook", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
Alam Ed Arias committed
330
consvar_t cv_invertmouse2 = {"invertmouse2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
331
consvar_t cv_alwaysfreelook2 = {"alwaysmlook2", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
332 333
consvar_t cv_chasefreelook = {"chasemlook", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_chasefreelook2 = {"chasemlook2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
toaster committed
334 335
consvar_t cv_mousemove = {"mousemove", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_mousemove2 = {"mousemove2", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
Alam Ed Arias committed
336

toaster committed
337 338
// previously "analog", "analog2", "useranalog", and "useranalog2", invalidating 2.1-era copies of config.cfg
// changed because it'd be nice to see people try out our actually good controls with gamepads now autobrake exists
339 340 341 342 343 344 345 346
consvar_t cv_analog[2] = {
	{"sessionanalog", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog_OnChange, 0, NULL, NULL, 0, 0, NULL},
	{"sessionanalog2", "Off", CV_CALL|CV_NOSHOWHELP, CV_OnOff, Analog2_OnChange, 0, NULL, NULL, 0, 0, NULL}
};
consvar_t cv_useranalog[2] = {
	{"configanalog", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog_OnChange, 0, NULL, NULL, 0, 0, NULL},
	{"configanalog2", "Off", CV_SAVE|CV_CALL|CV_NOSHOWHELP, CV_OnOff, UserAnalog2_OnChange, 0, NULL, NULL, 0, 0, NULL}
};
347 348

// deez New User eXperiences
colette committed
349
static CV_PossibleValue_t directionchar_cons_t[] = {{0, "Camera"}, {1, "Movement"}, {2, "Simple Locked"}, {0, NULL}};
350 351 352 353
consvar_t cv_directionchar[2] = {
	{"directionchar", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar_OnChange, 0, NULL, NULL, 0, 0, NULL},
	{"directionchar2", "Movement", CV_SAVE|CV_CALL, directionchar_cons_t, DirectionChar2_OnChange, 0, NULL, NULL, 0, 0, NULL}
};
354 355 356
consvar_t cv_autobrake = {"autobrake", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake_OnChange, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_autobrake2 = {"autobrake2", "On", CV_SAVE|CV_CALL, CV_OnOff, AutoBrake2_OnChange, 0, NULL, NULL, 0, 0, NULL};

357
// hi here's some new controls
358
static CV_PossibleValue_t zerotoone_cons_t[] = {{0, "MIN"}, {FRACUNIT, "MAX"}, {0, NULL}};
359 360 361 362
consvar_t cv_cam_shiftfacing[2] = {
	{"cam_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_shiftfacingchar", "0.33", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
};
363
consvar_t cv_cam_turnfacing[2] = {
364 365
	{"cam_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_turnfacingchar", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
366 367
};
consvar_t cv_cam_turnfacingability[2] = {
368 369
	{"cam_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_turnfacingability", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
370
};
371
consvar_t cv_cam_turnfacingspindash[2] = {
372 373
	{"cam_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_turnfacingspindash", "0.5", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
374
};
375
consvar_t cv_cam_turnfacinginput[2] = {
376 377
	{"cam_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_turnfacinginput", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
378
};
379

380
static CV_PossibleValue_t centertoggle_cons_t[] = {{0, "Hold"}, {1, "Toggle"}, {2, "Sticky Hold"}, {0, NULL}};
381 382 383 384
consvar_t cv_cam_centertoggle[2] = {
	{"cam_centertoggle", "Hold", CV_SAVE, centertoggle_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_centertoggle", "Hold", CV_SAVE, centertoggle_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
};
385

386
static CV_PossibleValue_t lockedinput_cons_t[] = {{0, "Strafe"}, {1, "Turn"}, {0, NULL}};
387 388 389 390 391
consvar_t cv_cam_lockedinput[2] = {
	{"cam_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_lockedinput", "Strafe", CV_SAVE, lockedinput_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
};

colette committed
392 393 394 395 396 397 398 399
static CV_PossibleValue_t lockedassist_cons_t[] = {
	{0, "Off"},
	{LOCK_BOSS, "Bosses"},
	{LOCK_BOSS|LOCK_ENEMY, "Enemies"},
	{LOCK_BOSS|LOCK_INTERESTS, "Interests"},
	{LOCK_BOSS|LOCK_ENEMY|LOCK_INTERESTS, "Full"},
	{0, NULL}
};
400
consvar_t cv_cam_lockonboss[2] = {
colette committed
401 402
	{"cam_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
	{"cam2_lockaimassist", "Bosses", CV_SAVE, lockedassist_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL},
403 404
};

Alam Ed Arias committed
405 406 407 408 409 410 411
typedef enum
{
	AXISNONE = 0,
	AXISTURN,
	AXISMOVE,
	AXISLOOK,
	AXISSTRAFE,
colette committed
412 413 414

	AXISDIGITAL, // axes below this use digital deadzone

Sal committed
415 416
	AXISJUMP,
	AXISSPIN,
Alam Ed Arias committed
417 418 419 420
	AXISFIRE,
	AXISFIRENORMAL,
} axis_input_e;

421
consvar_t cv_turnaxis = {"joyaxis_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Alam Ed Arias committed
422
consvar_t cv_moveaxis = {"joyaxis_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
423 424
consvar_t cv_sideaxis = {"joyaxis_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis = {"joyaxis_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Sal committed
425 426
consvar_t cv_jumpaxis = {"joyaxis_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_spinaxis = {"joyaxis_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
427 428
consvar_t cv_fireaxis = {"joyaxis_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis = {"joyaxis_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
429 430
consvar_t cv_deadzone = {"joy_deadzone", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_digitaldeadzone = {"joy_digdeadzone", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Alam Ed Arias committed
431

Marco Z committed
432
consvar_t cv_turnaxis2 = {"joyaxis2_turn", "X-Rudder", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Alam Ed Arias committed
433
consvar_t cv_moveaxis2 = {"joyaxis2_move", "Y-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Marco Z committed
434 435
consvar_t cv_sideaxis2 = {"joyaxis2_side", "X-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_lookaxis2 = {"joyaxis2_look", "Y-Rudder-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Sal committed
436 437
consvar_t cv_jumpaxis2 = {"joyaxis2_jump", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_spinaxis2 = {"joyaxis2_spin", "None", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
438 439
consvar_t cv_fireaxis2 = {"joyaxis2_fire", "Z-Axis-", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_firenaxis2 = {"joyaxis2_firenormal", "Z-Axis", CV_SAVE, joyaxis_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
440 441
consvar_t cv_deadzone2 = {"joy_deadzone2", "0.125", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_digitaldeadzone2 = {"joy_digdeadzone2", "0.25", CV_FLOAT|CV_SAVE, zerotoone_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
Alam Ed Arias committed
442 443 444 445 446

#ifdef SEENAMES
player_t *seenplayer; // player we're aiming at right now
#endif

447 448 449
// now automatically allocated in D_RegisterClientCommands
// so that it doesn't have to be updated depending on the value of MAXPLAYERS
char player_names[MAXPLAYERS][MAXPLAYERNAME+1];
Alam Ed Arias committed
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557

INT16 rw_maximums[NUM_WEAPONS] =
{
	800, // MAX_INFINITY
	400, // MAX_AUTOMATIC
	100, // MAX_BOUNCE
	50,  // MAX_SCATTER
	100, // MAX_GRENADE
	50,  // MAX_EXPLOSION
	50   // MAX_RAIL
};

// Allocation for time and nights data
void G_AllocMainRecordData(INT16 i)
{
	if (!mainrecords[i])
		mainrecords[i] = Z_Malloc(sizeof(recorddata_t), PU_STATIC, NULL);
	memset(mainrecords[i], 0, sizeof(recorddata_t));
}

void G_AllocNightsRecordData(INT16 i)
{
	if (!nightsrecords[i])
		nightsrecords[i] = Z_Malloc(sizeof(nightsdata_t), PU_STATIC, NULL);
	memset(nightsrecords[i], 0, sizeof(nightsdata_t));
}

// MAKE SURE YOU SAVE DATA BEFORE CALLING THIS
void G_ClearRecords(void)
{
	INT16 i;
	for (i = 0; i < NUMMAPS; ++i)
	{
		if (mainrecords[i])
		{
			Z_Free(mainrecords[i]);
			mainrecords[i] = NULL;
		}
		if (nightsrecords[i])
		{
			Z_Free(nightsrecords[i]);
			nightsrecords[i] = NULL;
		}
	}
}

// For easy retrieval of records
UINT32 G_GetBestScore(INT16 map)
{
	if (!mainrecords[map-1])
		return 0;

	return mainrecords[map-1]->score;
}

tic_t G_GetBestTime(INT16 map)
{
	if (!mainrecords[map-1] || mainrecords[map-1]->time <= 0)
		return (tic_t)UINT32_MAX;

	return mainrecords[map-1]->time;
}

UINT16 G_GetBestRings(INT16 map)
{
	if (!mainrecords[map-1])
		return 0;

	return mainrecords[map-1]->rings;
}

UINT32 G_GetBestNightsScore(INT16 map, UINT8 mare)
{
	if (!nightsrecords[map-1])
		return 0;

	return nightsrecords[map-1]->score[mare];
}

tic_t G_GetBestNightsTime(INT16 map, UINT8 mare)
{
	if (!nightsrecords[map-1] || nightsrecords[map-1]->time[mare] <= 0)
		return (tic_t)UINT32_MAX;

	return nightsrecords[map-1]->time[mare];
}

UINT8 G_GetBestNightsGrade(INT16 map, UINT8 mare)
{
	if (!nightsrecords[map-1])
		return 0;

	return nightsrecords[map-1]->grade[mare];
}

// For easy adding of NiGHTS records
void G_AddTempNightsRecords(UINT32 pscore, tic_t ptime, UINT8 mare)
{
	ntemprecords.score[mare] = pscore;
	ntemprecords.grade[mare] = P_GetGrade(pscore, gamemap, mare - 1);
	ntemprecords.time[mare] = ptime;

	// Update nummares
	// Note that mare "0" is overall, mare "1" is the first real mare
	if (ntemprecords.nummares < mare)
		ntemprecords.nummares = mare;
}

558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
//
// G_UpdateRecordReplays
//
// Update replay files/data, etc. for Record Attack
// See G_SetNightsRecords for NiGHTS Attack.
//
static void G_UpdateRecordReplays(void)
{
	const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
	char *gpath;
	char lastdemo[256], bestdemo[256];
	UINT8 earnedEmblems;

	// Record new best time
	if (!mainrecords[gamemap-1])
		G_AllocMainRecordData(gamemap-1);

	if (players[consoleplayer].score > mainrecords[gamemap-1]->score)
		mainrecords[gamemap-1]->score = players[consoleplayer].score;

	if ((mainrecords[gamemap-1]->time == 0) || (players[consoleplayer].realtime < mainrecords[gamemap-1]->time))
		mainrecords[gamemap-1]->time = players[consoleplayer].realtime;

	if ((UINT16)(players[consoleplayer].rings) > mainrecords[gamemap-1]->rings)
		mainrecords[gamemap-1]->rings = (UINT16)(players[consoleplayer].rings);

	// Save demo!
	bestdemo[255] = '\0';
	lastdemo[255] = '\0';
	G_SetDemoTime(players[consoleplayer].realtime, players[consoleplayer].score, (UINT16)(players[consoleplayer].rings));
	G_CheckDemoStatus();

	I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
	I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);

	if ((gpath = malloc(glen)) == NULL)
		I_Error("Out of memory for replay filepath\n");

	sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
	snprintf(lastdemo, 255, "%s-%s-last.lmp", gpath, skins[cv_chooseskin.value-1].name);

	if (FIL_FileExists(lastdemo))
	{
		UINT8 *buf;
		size_t len = FIL_ReadFile(lastdemo, &buf);

		snprintf(bestdemo, 255, "%s-%s-time-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
		if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
		{ // Better time, save this demo.
			if (FIL_FileExists(bestdemo))
				remove(bestdemo);
			FIL_WriteFile(bestdemo, buf, len);
			CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
		}

		snprintf(bestdemo, 255, "%s-%s-score-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
		if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
		{ // Better score, save this demo.
			if (FIL_FileExists(bestdemo))
				remove(bestdemo);
			FIL_WriteFile(bestdemo, buf, len);
			CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo);
		}

		snprintf(bestdemo, 255, "%s-%s-rings-best.lmp", gpath, skins[cv_chooseskin.value-1].name);
		if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<2)))
		{ // Better rings, save this demo.
			if (FIL_FileExists(bestdemo))
				remove(bestdemo);
			FIL_WriteFile(bestdemo, buf, len);
			CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW MOST RINGS!"), M_GetText("Saved replay as"), bestdemo);
		}

		//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);

		Z_Free(buf);
	}
	free(gpath);

	// Check emblems when level data is updated
	if ((earnedEmblems = M_CheckLevelEmblems()))
		CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for Record Attack records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");

	// Update timeattack menu's replay availability.
	Nextmap_OnChange();
}

Alam Ed Arias committed
645 646 647
void G_SetNightsRecords(void)
{
	INT32 i;
Alam Ed Arias committed
648 649
	UINT32 totalscore = 0;
	tic_t totaltime = 0;
650
	UINT8 earnedEmblems;
Alam Ed Arias committed
651 652 653 654

	const size_t glen = strlen(srb2home)+1+strlen("replay")+1+strlen(timeattackfolder)+1+strlen("MAPXX")+1;
	char *gpath;
	char lastdemo[256], bestdemo[256];
Alam Ed Arias committed
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705

	if (!ntemprecords.nummares)
		return;

	// Set overall
	{
		UINT8 totalrank = 0, realrank = 0;

		for (i = 1; i <= ntemprecords.nummares; ++i)
		{
			totalscore += ntemprecords.score[i];
			totalrank += ntemprecords.grade[i];
			totaltime += ntemprecords.time[i];
		}

		// Determine overall grade
		realrank = (UINT8)((FixedDiv((fixed_t)totalrank << FRACBITS, ntemprecords.nummares << FRACBITS) + (FRACUNIT/2)) >> FRACBITS);

		// You need ALL rainbow As to get a rainbow A overall
		if (realrank == GRADE_S && (totalrank / ntemprecords.nummares) != GRADE_S)
			realrank = GRADE_A;

		ntemprecords.score[0] = totalscore;
		ntemprecords.grade[0] = realrank;
		ntemprecords.time[0] = totaltime;
	}

	// Now take all temp records and put them in the actual records
	{
		nightsdata_t *maprecords;

		if (!nightsrecords[gamemap-1])
			G_AllocNightsRecordData(gamemap-1);
		maprecords = nightsrecords[gamemap-1];

		if (maprecords->nummares != ntemprecords.nummares)
			maprecords->nummares = ntemprecords.nummares;

		for (i = 0; i < ntemprecords.nummares + 1; ++i)
		{
			if (maprecords->score[i] < ntemprecords.score[i])
				maprecords->score[i] = ntemprecords.score[i];
			if (maprecords->grade[i] < ntemprecords.grade[i])
				maprecords->grade[i] = ntemprecords.grade[i];
			if (!maprecords->time[i] || maprecords->time[i] > ntemprecords.time[i])
				maprecords->time[i] = ntemprecords.time[i];
		}
	}

	memset(&ntemprecords, 0, sizeof(nightsdata_t));

Alam Ed Arias committed
706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749
	// Save demo!
	bestdemo[255] = '\0';
	lastdemo[255] = '\0';
	G_SetDemoTime(totaltime, totalscore, 0);
	G_CheckDemoStatus();

	I_mkdir(va("%s"PATHSEP"replay", srb2home), 0755);
	I_mkdir(va("%s"PATHSEP"replay"PATHSEP"%s", srb2home, timeattackfolder), 0755);

	if ((gpath = malloc(glen)) == NULL)
		I_Error("Out of memory for replay filepath\n");

	sprintf(gpath,"%s"PATHSEP"replay"PATHSEP"%s"PATHSEP"%s", srb2home, timeattackfolder, G_BuildMapName(gamemap));
	snprintf(lastdemo, 255, "%s-last.lmp", gpath);

	if (FIL_FileExists(lastdemo))
	{
		UINT8 *buf;
		size_t len = FIL_ReadFile(lastdemo, &buf);

		snprintf(bestdemo, 255, "%s-time-best.lmp", gpath);
		if (!FIL_FileExists(bestdemo) || G_CmpDemoTime(bestdemo, lastdemo) & 1)
		{ // Better time, save this demo.
			if (FIL_FileExists(bestdemo))
				remove(bestdemo);
			FIL_WriteFile(bestdemo, buf, len);
			CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW RECORD TIME!"), M_GetText("Saved replay as"), bestdemo);
		}

		snprintf(bestdemo, 255, "%s-score-best.lmp", gpath);
		if (!FIL_FileExists(bestdemo) || (G_CmpDemoTime(bestdemo, lastdemo) & (1<<1)))
		{ // Better score, save this demo.
			if (FIL_FileExists(bestdemo))
				remove(bestdemo);
			FIL_WriteFile(bestdemo, buf, len);
			CONS_Printf("\x83%s\x80 %s '%s'\n", M_GetText("NEW HIGH SCORE!"), M_GetText("Saved replay as"), bestdemo);
		}

		//CONS_Printf("%s '%s'\n", M_GetText("Saved replay as"), lastdemo);

		Z_Free(buf);
	}
	free(gpath);

750 751 752
	if ((earnedEmblems = M_CheckLevelEmblems()))
		CONS_Printf(M_GetText("\x82" "Earned %hu emblem%s for NiGHTS records.\n"), (UINT16)earnedEmblems, earnedEmblems > 1 ? "s" : "");

Alam Ed Arias committed
753
	// If the mare count changed, this will update the score display
754
	Nextmap_OnChange();
Alam Ed Arias committed
755 756 757 758 759 760 761 762 763 764 765 766 767
}

// for consistency among messages: this modifies the game and removes savemoddata.
void G_SetGameModified(boolean silent)
{
	if (modifiedgame && !savemoddata)
		return;

	modifiedgame = true;
	savemoddata = false;

	if (!silent)
		CONS_Alert(CONS_NOTICE, M_GetText("Game must be restarted to record statistics.\n"));
768 769 770 771

	// If in record attack recording, cancel it.
	if (modeattacking)
		M_EndModeAttackRun();
Alam Ed Arias committed
772 773 774 775 776 777 778 779 780 781 782
}

/** Builds an original game map name from a map number.
  * The complexity is due to MAPA0-MAPZZ.
  *
  * \param map Map number.
  * \return Pointer to a static buffer containing the desired map name.
  * \sa M_MapNumber
  */
const char *G_BuildMapName(INT32 map)
{
783
	static char mapname[10] = "MAPXX"; // internal map name (wad resource name)
Alam Ed Arias committed
784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858

	I_Assert(map > 0);
	I_Assert(map <= NUMMAPS);

	if (map < 100)
		sprintf(&mapname[3], "%.2d", map);
	else
	{
		mapname[3] = (char)('A' + (char)((map - 100) / 36));
		if ((map - 100) % 36 < 10)
			mapname[4] = (char)('0' + (char)((map - 100) % 36));
		else
			mapname[4] = (char)('A' + (char)((map - 100) % 36) - 10);
		mapname[5] = '\0';
	}

	return mapname;
}

/** Clips the console player's mouse aiming to the current view.
  * Used whenever the player view is changed manually.
  *
  * \param aiming Pointer to the vertical angle to clip.
  * \return Short version of the clipped angle for building a ticcmd.
  */
INT16 G_ClipAimingPitch(INT32 *aiming)
{
	INT32 limitangle;

	limitangle = ANGLE_90 - 1;

	if (*aiming > limitangle)
		*aiming = limitangle;
	else if (*aiming < -limitangle)
		*aiming = -limitangle;

	return (INT16)((*aiming)>>16);
}

INT16 G_SoftwareClipAimingPitch(INT32 *aiming)
{
	INT32 limitangle;

	// note: the current software mode implementation doesn't have true perspective
	limitangle = ANGLE_90 - ANG10; // Some viewing fun, but not too far down...

	if (*aiming > limitangle)
		*aiming = limitangle;
	else if (*aiming < -limitangle)
		*aiming = -limitangle;

	return (INT16)((*aiming)>>16);
}

static INT32 JoyAxis(axis_input_e axissel)
{
	INT32 retaxis;
	INT32 axisval;
	boolean flp = false;

	//find what axis to get
	switch (axissel)
	{
		case AXISTURN:
			axisval = cv_turnaxis.value;
			break;
		case AXISMOVE:
			axisval = cv_moveaxis.value;
			break;
		case AXISLOOK:
			axisval = cv_lookaxis.value;
			break;
		case AXISSTRAFE:
			axisval = cv_sideaxis.value;
			break;
Sal committed
859 860 861 862 863 864
		case AXISJUMP:
			axisval = cv_jumpaxis.value;
			break;
		case AXISSPIN:
			axisval = cv_spinaxis.value;
			break;
Alam Ed Arias committed
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898
		case AXISFIRE:
			axisval = cv_fireaxis.value;
			break;
		case AXISFIRENORMAL:
			axisval = cv_firenaxis.value;
			break;
		default:
			return 0;
	}

	if (axisval < 0) //odd -axises
	{
		axisval = -axisval;
		flp = true;
	}
	if (axisval > JOYAXISSET*2 || axisval == 0) //not there in array or None
		return 0;

	if (axisval%2)
	{
		axisval /= 2;
		retaxis = joyxmove[axisval];
	}
	else
	{
		axisval--;
		axisval /= 2;
		retaxis = joyymove[axisval];
	}

	if (retaxis < (-JOYAXISRANGE))
		retaxis = -JOYAXISRANGE;
	if (retaxis > (+JOYAXISRANGE))
		retaxis = +JOYAXISRANGE;
899 900

	if (!Joystick.bGamepadStyle && axissel > AXISDIGITAL)
Alam Ed Arias committed
901
	{
902
		const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone.value) >> FRACBITS;
Alam Ed Arias committed
903 904 905
		if (-jdeadzone < retaxis && retaxis < jdeadzone)
			return 0;
	}
906

Alam Ed Arias committed
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931
	if (flp) retaxis = -retaxis; //flip it around
	return retaxis;
}

static INT32 Joy2Axis(axis_input_e axissel)
{
	INT32 retaxis;
	INT32 axisval;
	boolean flp = false;

	//find what axis to get
	switch (axissel)
	{
		case AXISTURN:
			axisval = cv_turnaxis2.value;
			break;
		case AXISMOVE:
			axisval = cv_moveaxis2.value;
			break;
		case AXISLOOK:
			axisval = cv_lookaxis2.value;
			break;
		case AXISSTRAFE:
			axisval = cv_sideaxis2.value;
			break;
Sal committed
932 933 934 935 936 937
		case AXISJUMP:
			axisval = cv_jumpaxis2.value;
			break;
		case AXISSPIN:
			axisval = cv_spinaxis2.value;
			break;
Alam Ed Arias committed
938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953
		case AXISFIRE:
			axisval = cv_fireaxis2.value;
			break;
		case AXISFIRENORMAL:
			axisval = cv_firenaxis2.value;
			break;
		default:
			return 0;
	}


	if (axisval < 0) //odd -axises
	{
		axisval = -axisval;
		flp = true;
	}
954

Alam Ed Arias committed
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973
	if (axisval > JOYAXISSET*2 || axisval == 0) //not there in array or None
		return 0;

	if (axisval%2)
	{
		axisval /= 2;
		retaxis = joy2xmove[axisval];
	}
	else
	{
		axisval--;
		axisval /= 2;
		retaxis = joy2ymove[axisval];
	}

	if (retaxis < (-JOYAXISRANGE))
		retaxis = -JOYAXISRANGE;
	if (retaxis > (+JOYAXISRANGE))
		retaxis = +JOYAXISRANGE;
974 975

	if (!Joystick2.bGamepadStyle && axissel > AXISDIGITAL)
Alam Ed Arias committed
976
	{
977
		const INT32 jdeadzone = ((JOYAXISRANGE-1) * cv_digitaldeadzone2.value) >> FRACBITS;
Alam Ed Arias committed
978 979 980
		if (-jdeadzone < retaxis && retaxis < jdeadzone)
			return 0;
	}
981

Alam Ed Arias committed
982 983 984 985
	if (flp) retaxis = -retaxis; //flip it around
	return retaxis;
}

986

colette committed
987 988
#define PlayerJoyAxis(p, ax) ((p) == 1 ? JoyAxis(ax) : Joy2Axis(ax))

989 990
// Take a magnitude of two axes, and adjust it to take out the deadzone
// Will return a value between 0 and JOYAXISRANGE
991
static INT32 G_BasicDeadZoneCalculation(INT32 magnitude, fixed_t deadZone)
992
{
993
	const INT32 jdeadzone = (JOYAXISRANGE * deadZone) / FRACUNIT;
994
	INT32 deadzoneAppliedValue = 0;
995
	INT32 adjustedMagnitude = abs(magnitude);
996

997 998 999
	if (jdeadzone >= JOYAXISRANGE && adjustedMagnitude >= JOYAXISRANGE) // If the deadzone and magnitude are both 100%...
		return JOYAXISRANGE; // ...return 100% input directly, to avoid dividing by 0
	else if (adjustedMagnitude > jdeadzone) // Otherwise, calculate how much the magnitude exceeds the deadzone
1000
	{
1001
		adjustedMagnitude = min(adjustedMagnitude, JOYAXISRANGE);
1002

1003
		adjustedMagnitude -= jdeadzone;
1004

1005
		deadzoneAppliedValue = (adjustedMagnitude * JOYAXISRANGE) / (JOYAXISRANGE - jdeadzone);
1006 1007 1008 1009 1010 1011 1012 1013 1014
	}

	return deadzoneAppliedValue;
}

// Get the actual sensible radial value for a joystick axis when accounting for a deadzone
static void G_HandleAxisDeadZone(UINT8 splitnum, joystickvector2_t *joystickvector)
{
	INT32 gamepadStyle = Joystick.bGamepadStyle;
1015
	fixed_t deadZone = cv_deadzone.value;
1016 1017 1018 1019

	if (splitnum == 1)
	{
		gamepadStyle = Joystick2.bGamepadStyle;
1020
		deadZone = cv_deadzone2.value;
1021 1022 1023 1024 1025 1026 1027
	}

	// When gamepadstyle is "true" the values are just -1, 0, or 1. This is done in the interface code.
	if (!gamepadStyle)
	{
		// Get the total magnitude of the 2 axes
		INT32 magnitude = (joystickvector->xaxis * joystickvector->xaxis) + (joystickvector->yaxis * joystickvector->yaxis);
1028 1029
		INT32 normalisedXAxis;
		INT32 normalisedYAxis;
1030 1031 1032 1033 1034
		INT32 normalisedMagnitude;
		double dMagnitude = sqrt((double)magnitude);
		magnitude = (INT32)dMagnitude;

		// Get the normalised xy values from the magnitude
1035 1036
		normalisedXAxis = (joystickvector->xaxis * magnitude) / JOYAXISRANGE;
		normalisedYAxis = (joystickvector->yaxis * magnitude) / JOYAXISRANGE;
1037 1038

		// Apply the deadzone to the magnitude to give a correct value between 0 and JOYAXISRANGE
1039
		normalisedMagnitude = G_BasicDeadZoneCalculation(magnitude, deadZone);
1040 1041

		// Apply the deadzone to the xy axes
1042 1043
		joystickvector->xaxis = (normalisedXAxis * normalisedMagnitude) / JOYAXISRANGE;
		joystickvector->yaxis = (normalisedYAxis * normalisedMagnitude) / JOYAXISRANGE;
1044 1045 1046 1047 1048 1049 1050 1051 1052

		// Cap the values so they don't go above the correct maximum
		joystickvector->xaxis = min(joystickvector->xaxis, JOYAXISRANGE);
		joystickvector->xaxis = max(joystickvector->xaxis, -JOYAXISRANGE);
		joystickvector->yaxis = min(joystickvector->yaxis, JOYAXISRANGE);
		joystickvector->yaxis = max(joystickvector->yaxis, -JOYAXISRANGE);
	}
}

Alam Ed Arias committed
1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067
//
// G_BuildTiccmd
// Builds a ticcmd from all of the available inputs
// or reads it from the demo buffer.
// If recording a demo, write it out
//
// set secondaryplayer true to build player 2's ticcmd in splitscreen mode
//
INT32 localaiming, localaiming2;
angle_t localangle, localangle2;

static fixed_t forwardmove[2] = {25<<FRACBITS>>16, 50<<FRACBITS>>16};
static fixed_t sidemove[2] = {25<<FRACBITS>>16, 50<<FRACBITS>>16}; // faster!
static fixed_t angleturn[3] = {640, 1280, 320}; // + slow turn

1068
boolean ticcmd_centerviewdown[2]; // For simple controls, lock the camera behind the player
1069
mobj_t *ticcmd_ztargetfocus[2]; // Locking onto an object?
colette committed
1070
void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
Alam Ed Arias committed
1071 1072
{
	boolean forcestrafe = false;
lachwright committed
1073
	boolean forcefullinput = false;
1074
	INT32 tspeed, forward, side, axis, strafeaxis, moveaxis, turnaxis, lookaxis, i;
1075 1076 1077

	joystickvector2_t movejoystickvector, lookjoystickvector;

Alam Ed Arias committed
1078 1079
	const INT32 speed = 1;
	// these ones used for multiple conditions
Marco Z committed
1080
	boolean turnleft, turnright, strafelkey, straferkey, movefkey, movebkey, mouseaiming, analogjoystickmove, gamepadjoystickmove, thisjoyaiming;
1081
	boolean strafeisturn; // Simple controls only
colette committed
1082 1083 1084 1085 1086
	player_t *player = &players[ssplayer == 2 ? secondarydisplayplayer : consoleplayer];
	camera_t *thiscam = ((ssplayer == 1 || player->bot == 2) ? &camera : &camera2);
	angle_t *myangle = (ssplayer == 1 ? &localangle : &localangle2);
	INT32 *myaiming = (ssplayer == 1 ? &localaiming : &localaiming2);

colette committed
1087
	angle_t drawangleoffset = (player->powers[pw_carry] == CR_ROLLOUT) ? ANGLE_180 : 0;
1088
	INT32 chasecam, chasefreelook, alwaysfreelook, usejoystick, invertmouse, turnmultiplier, mousemove;
1089
	controlstyle_e controlstyle = G_ControlStyle(ssplayer);
colette committed
1090
	INT32 *mx; INT32 *my; INT32 *mly;
Alam Ed Arias committed
1091

colette committed
1092 1093
	static INT32 turnheld[2]; // for accelerative turning
	static boolean keyboard_look[2]; // true if lookup/down using keyboard
1094
	static boolean resetdown[2]; // don't cam reset every frame
colette committed
1095
	static boolean joyaiming[2]; // check the last frame's value if we need to reset the camera
1096 1097

	// simple mode vars
1098
	static boolean zchange[2]; // only switch z targets once per press
1099
	static fixed_t tta_factor[2] = {FRACUNIT, FRACUNIT}; // disables turn-to-angle when manually turning camera until movement happens
1100 1101
	boolean centerviewdown = false;

colette committed
1102
	UINT8 forplayer = ssplayer-1;
Alam Ed Arias committed
1103

colette committed
1104 1105 1106 1107 1108 1109 1110
	if (ssplayer == 1)
	{
		chasecam = cv_chasecam.value;
		chasefreelook = cv_chasefreelook.value;
		alwaysfreelook = cv_alwaysfreelook.value;
		usejoystick = cv_usejoystick.value;
		invertmouse = cv_invertmouse.value;
1111
		turnmultiplier = cv_cam_turnmultiplier.value;
colette committed
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
		mousemove = cv_mousemove.value;
		mx = &mousex;
		my = &mousey;
		mly = &mlooky;
		G_CopyTiccmd(cmd, I_BaseTiccmd(), 1); // empty, or external driver
	}
	else
	{
		chasecam = cv_chasecam2.value;
		chasefreelook = cv_chasefreelook2.value;
		alwaysfreelook = cv_alwaysfreelook2.value;
		usejoystick = cv_usejoystick2.value;
		invertmouse = cv_invertmouse2.value;
1125
		turnmultiplier = cv_cam2_turnmultiplier.value;
colette committed
1126 1127 1128 1129 1130 1131
		mousemove = cv_mousemove2.value;
		mx = &mouse2x;
		my = &mouse2y;
		mly = &mlook2y;
		G_CopyTiccmd(cmd, I_BaseTiccmd2(), 1); // empty, or external driver
	}
Alam Ed Arias committed
1132

1133
	strafeisturn = controlstyle == CS_SIMPLE && ticcmd_centerviewdown[forplayer] &&
1134
		((cv_cam_lockedinput[forplayer].value && !ticcmd_ztargetfocus[forplayer]) || (player->pflags & PF_STARTDASH)) &&
1135 1136
		!player->climbing && player->powers[pw_carry] != CR_MINECART;

Alam Ed Arias committed
1137 1138
	// why build a ticcmd if we're paused?
	// Or, for that matter, if we're being reborn.
1139
	// ...OR if we're blindfolded. No looking into the floor.
1140
	if (paused || P_AutoPause() || (gamestate == GS_LEVEL && (player->playerstate == PST_REBORN || ((gametyperules & GTR_TAG)
1141
	&& (leveltime < hidetime * TICRATE) && (player->pflags & PF_TAGIT)))))
colette committed
1142 1143 1144
	{//@TODO splitscreen player
		cmd->angleturn = (INT16)(*myangle >> 16);
		cmd->aiming = G_ClipAimingPitch(myaiming);
Alam Ed Arias committed
1145 1146 1147
		return;
	}

colette committed
1148 1149
	turnright = PLAYERINPUTDOWN(ssplayer, gc_turnright);
	turnleft = PLAYERINPUTDOWN(ssplayer, gc_turnleft);
Alam Ed Arias committed
1150

colette committed
1151 1152 1153 1154
	straferkey = PLAYERINPUTDOWN(ssplayer, gc_straferight);
	strafelkey = PLAYERINPUTDOWN(ssplayer, gc_strafeleft);
	movefkey = PLAYERINPUTDOWN(ssplayer, gc_forward);
	movebkey = PLAYERINPUTDOWN(ssplayer, gc_backward);
Alam Ed Arias committed
1155

1156 1157 1158 1159 1160 1161 1162
	if (strafeisturn)
	{
		turnright |= straferkey;
		turnleft |= strafelkey;
		straferkey = strafelkey = false;
	}

colette committed
1163 1164 1165 1166
	mouseaiming = (PLAYERINPUTDOWN(ssplayer, gc_mouseaiming)) ^
		((chasecam && !player->spectator) ? chasefreelook : alwaysfreelook);
	analogjoystickmove = usejoystick && !Joystick.bGamepadStyle;
	gamepadjoystickmove = usejoystick && Joystick.bGamepadStyle;
Alam Ed Arias committed
1167

colette committed
1168
	thisjoyaiming = (chasecam && !player->spectator) ? chasefreelook : alwaysfreelook;
1169 1170

	// Reset the vertical look if we're no longer joyaiming
colette committed
1171 1172 1173
	if (!thisjoyaiming && joyaiming[forplayer])
		*myaiming = 0;
	joyaiming[forplayer] = thisjoyaiming;
1174

colette committed
1175
	turnaxis = PlayerJoyAxis(ssplayer, AXISTURN);
1176
	if (strafeisturn)
1177 1178
		turnaxis += PlayerJoyAxis(ssplayer, AXISSTRAFE);
	lookaxis = PlayerJoyAxis(ssplayer, AXISLOOK);
1179 1180
	lookjoystickvector.xaxis = turnaxis;
	lookjoystickvector.yaxis = lookaxis;
1181
	G_HandleAxisDeadZone(forplayer, &lookjoystickvector);
1182 1183

	if (gamepadjoystickmove && lookjoystickvector.xaxis != 0)
Alam Ed Arias committed
1184
	{
1185 1186
		turnright = turnright || (lookjoystickvector.xaxis > 0);
		turnleft = turnleft || (lookjoystickvector.xaxis < 0);
Alam Ed Arias committed
1187 1188 1189 1190 1191 1192
	}
	forward = side = 0;

	// use two stage accelerative turning
	// on the keyboard and joystick
	if (turnleft || turnright)
colette committed
1193
		turnheld[forplayer] += realtics;
Alam Ed Arias committed
1194
	else
colette committed
1195
		turnheld[forplayer] = 0;
Alam Ed Arias committed
1196

colette committed
1197
	if (turnheld[forplayer] < SLOWTURNTICS)
Alam Ed Arias committed
1198 1199 1200 1201 1202
		tspeed = 2; // slow turn
	else
		tspeed = speed;

	// let movement keys cancel each other out
1203
	if (controlstyle == CS_LMAOGALOG) // Analog
Alam Ed Arias committed
1204 1205 1206 1207 1208 1209
	{
		if (turnright)
			cmd->angleturn = (INT16)(cmd->angleturn - angleturn[tspeed]);
		if (turnleft)
			cmd->angleturn = (INT16)(cmd->angleturn + angleturn[tspeed]);
	}
lachwright committed
1210 1211 1212 1213
	if (twodlevel
		|| (player->mo && (player->mo->flags2 & MF2_TWOD))
		|| (!demoplayback && (player->pflags & PF_SLIDING)))
			forcefullinput = true;
1214
	if (twodlevel
Alam Ed Arias committed
1215
		|| (player->mo && (player->mo->flags2 & MF2_TWOD))
1216
		|| (!demoplayback && ((player->powers[pw_carry] == CR_NIGHTSMODE)
1217
		|| (player->pflags & (PF_SLIDING|PF_FORCESTRAFE))))) // Analog
Alam Ed Arias committed
1218
			forcestrafe = true;
1219
	if (forcestrafe)
Alam Ed Arias committed
1220 1221 1222 1223 1224 1225
	{
		if (turnright)
			side += sidemove[speed];
		if (turnleft)
			side -= sidemove[speed];

1226
		if (analogjoystickmove && lookjoystickvector.xaxis != 0)
Alam Ed Arias committed
1227 1228
		{
			// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
1229
			side += ((lookjoystickvector.xaxis * sidemove[1]) >> 10);
Alam Ed Arias committed
1230 1231
		}
	}
1232
	else if (controlstyle == CS_LMAOGALOG) // Analog
1233 1234 1235 1236 1237 1238
	{
		if (turnright)
			cmd->buttons |= BT_CAMRIGHT;
		if (turnleft)
			cmd->buttons |= BT_CAMLEFT;
	}
Alam Ed Arias committed
1239 1240
	else
	{
1241 1242
		if (turnright && turnleft);
		else if (turnright)
1243
			cmd->angleturn = (INT16)(cmd->angleturn - ((angleturn[tspeed] * turnmultiplier)>>FRACBITS));
Alam Ed Arias committed
1244
		else if (turnleft)
1245
			cmd->angleturn = (INT16)(cmd->angleturn + ((angleturn[tspeed] * turnmultiplier)>>FRACBITS));
Alam Ed Arias committed
1246

1247
		if (analogjoystickmove && lookjoystickvector.xaxis != 0)
Alam Ed Arias committed
1248 1249
		{
			// JOYAXISRANGE should be 1023 (divide by 1024)
1250
			cmd->angleturn = (INT16)(cmd->angleturn - ((((lookjoystickvector.xaxis * angleturn[1]) >> 10) * turnmultiplier)>>FRACBITS)); // ANALOG!
Alam Ed Arias committed
1251
		}
1252

1253
		if (turnright || turnleft || abs(cmd->angleturn) > angleturn[2])
1254
			tta_factor[forplayer] = 0; // suspend turn to angle
Alam Ed Arias committed
1255 1256
	}

1257 1258
	strafeaxis = strafeisturn ? 0 : PlayerJoyAxis(ssplayer, AXISSTRAFE);
	moveaxis = PlayerJoyAxis(ssplayer, AXISMOVE);
1259 1260
	movejoystickvector.xaxis = strafeaxis;
	movejoystickvector.yaxis = moveaxis;
1261
	G_HandleAxisDeadZone(forplayer, &movejoystickvector);
1262 1263

	if (gamepadjoystickmove && movejoystickvector.xaxis != 0)
Alam Ed Arias committed
1264
	{
1265
		if (movejoystickvector.xaxis > 0)
Alam Ed Arias committed
1266
			side += sidemove[speed];
1267
		else if (movejoystickvector.xaxis < 0)
Alam Ed Arias committed
1268 1269
			side -= sidemove[speed];
	}
1270
	else if (analogjoystickmove && movejoystickvector.xaxis != 0)
Alam Ed Arias committed
1271 1272
	{
		// JOYAXISRANGE is supposed to be 1023 (divide by 1024)
1273
		side += ((movejoystickvector.xaxis * sidemove[1]) >> 10);
Alam Ed Arias committed
1274 1275 1276
	}

	// forward with key or button
1277
	if (movefkey || (gamepadjoystickmove && movejoystickvector.yaxis < 0)
Marco Z committed
1278
		|| ((player->powers[pw_carry] == CR_NIGHTSMODE)
1279
			&& (PLAYERINPUTDOWN(ssplayer, gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0))))
Alam Ed Arias committed
1280
		forward = forwardmove[speed];
1281
	if (movebkey || (gamepadjoystickmove && movejoystickvector.yaxis > 0)
Marco Z committed
1282
		|| ((player->powers[pw_carry] == CR_NIGHTSMODE)
1283
			&& (PLAYERINPUTDOWN(ssplayer, gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0))))
Alam Ed Arias committed
1284 1285
		forward -= forwardmove[speed];

1286 1287
	if (analogjoystickmove && movejoystickvector.yaxis != 0)
		forward -= ((movejoystickvector.yaxis * forwardmove[1]) >> 10); // ANALOG!
Alam Ed Arias committed
1288 1289 1290

	// some people strafe left & right with mouse buttons
	// those people are weird
1291
	if (straferkey)
Alam Ed Arias committed
1292
		side += sidemove[speed];
1293
	if (strafelkey)
Alam Ed Arias committed
1294 1295
		side -= sidemove[speed];

colette committed
1296
	if (PLAYERINPUTDOWN(ssplayer, gc_weaponnext))
Alam Ed Arias committed
1297
		cmd->buttons |= BT_WEAPONNEXT; // Next Weapon
colette committed
1298
	if (PLAYERINPUTDOWN(ssplayer, gc_weaponprev))
Alam Ed Arias committed
1299 1300 1301 1302 1303 1304 1305 1306
		cmd->buttons |= BT_WEAPONPREV; // Previous Weapon

#if NUM_WEAPONS > 10
"Add extra inputs to g_input.h/gamecontrols_e"
#endif
	//use the four avaliable bits to determine the weapon.
	cmd->buttons &= ~BT_WEAPONMASK;
	for (i = 0; i < NUM_WEAPONS; ++i)
colette committed
1307
		if (PLAYERINPUTDOWN(ssplayer, gc_wepslot1 + i))
Alam Ed Arias committed
1308 1309 1310 1311 1312 1313
		{
			cmd->buttons |= (UINT16)(i + 1);
			break;
		}

	// fire with any button/key
colette committed
1314 1315
	axis = PlayerJoyAxis(ssplayer, AXISFIRE);
	if (PLAYERINPUTDOWN(ssplayer, gc_fire) || (usejoystick && axis > 0))
Alam Ed Arias committed
1316 1317 1318
		cmd->buttons |= BT_ATTACK;

	// fire normal with any button/key
colette committed
1319 1320
	axis = PlayerJoyAxis(ssplayer, AXISFIRENORMAL);
	if (PLAYERINPUTDOWN(ssplayer, gc_firenormal) || (usejoystick && axis > 0))
Alam Ed Arias committed
1321 1322
		cmd->buttons |= BT_FIRENORMAL;

colette committed
1323
	if (PLAYERINPUTDOWN(ssplayer, gc_tossflag))
Alam Ed Arias committed
1324 1325
		cmd->buttons |= BT_TOSSFLAG;

Alam Ed Arias committed
1326
	// Lua scriptable buttons
colette committed
1327
	if (PLAYERINPUTDOWN(ssplayer, gc_custom1))
Alam Ed Arias committed
1328
		cmd->buttons |= BT_CUSTOM1;
colette committed
1329
	if (PLAYERINPUTDOWN(ssplayer, gc_custom2))
Alam Ed Arias committed
1330
		cmd->buttons |= BT_CUSTOM2;
colette committed
1331
	if (PLAYERINPUTDOWN(ssplayer, gc_custom3))
Alam Ed Arias committed
1332 1333
		cmd->buttons |= BT_CUSTOM3;

Alam Ed Arias committed
1334
	// use with any button/key
colette committed
1335 1336
	axis = PlayerJoyAxis(ssplayer, AXISSPIN);
	if (PLAYERINPUTDOWN(ssplayer, gc_use) || (usejoystick && axis > 0))
Alam Ed Arias committed
1337 1338
		cmd->buttons |= BT_USE;

1339 1340 1341 1342 1343
	// Centerview can be a toggle in simple mode!
	{
		static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior
		boolean down = PLAYERINPUTDOWN(ssplayer, gc_centerview);

1344
		if (!(controlstyle == CS_SIMPLE && cv_cam_centertoggle[forplayer].value))
1345 1346 1347 1348 1349 1350
			centerviewdown = down;
		else
		{
			if (down && !last_centerviewdown[forplayer])
				centerviewhold[forplayer] = !centerviewhold[forplayer];
			last_centerviewdown[forplayer] = down;
1351 1352 1353 1354

			if (cv_cam_centertoggle[forplayer].value == 2 && !down && !ticcmd_ztargetfocus[forplayer])
				centerviewhold[forplayer] = false;

1355 1356 1357 1358 1359
			centerviewdown = centerviewhold[forplayer];
		}
	}

	if (centerviewdown)
Alam Ed Arias committed
1360
	{
1361
		if (controlstyle == CS_SIMPLE && !ticcmd_centerviewdown[forplayer] && !G_RingSlingerGametype())
1362
		{
colette committed
1363
			CV_SetValue(&cv_directionchar[forplayer], 2);
1364 1365
			*myangle = player->mo->angle;
			*myaiming = 0;
1366 1367

			if (cv_cam_lockonboss[forplayer].value)
colette committed
1368
				P_SetTarget(&ticcmd_ztargetfocus[forplayer], P_LookForFocusTarget(player, NULL, 0, cv_cam_lockonboss[forplayer].value));
1369
		}
1370 1371

		ticcmd_centerviewdown[forplayer] = true;
Alam Ed Arias committed
1372
	}
1373
	else if (ticcmd_centerviewdown[forplayer])
1374
	{
1375
		if (controlstyle == CS_SIMPLE)
1376 1377
		{
			P_SetTarget(&ticcmd_ztargetfocus[forplayer], NULL);
1378
			CV_SetValue(&cv_directionchar[forplayer], 1);
1379
		}
Alam Ed Arias committed
1380

1381
		ticcmd_centerviewdown[forplayer] = false;
1382 1383
	}

1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394
	if (ticcmd_ztargetfocus[forplayer])
	{
		if (
			P_MobjWasRemoved(ticcmd_ztargetfocus[forplayer]) ||
			!ticcmd_ztargetfocus[forplayer]->health ||
			(ticcmd_ztargetfocus[forplayer]->flags2 & MF2_FRET) ||
			(ticcmd_ztargetfocus[forplayer]->type == MT_EGGMOBILE3 && !ticcmd_ztargetfocus[forplayer]->movecount) // Sea Egg is moving around underground and shouldn't be tracked
		)
			P_SetTarget(&ticcmd_ztargetfocus[forplayer], NULL);
		else
		{
1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414
			mobj_t *newtarget = NULL;
			if (zchange[forplayer])
			{
				if (!turnleft && !turnright && abs(cmd->angleturn) < angleturn[0])
					zchange[forplayer] = false;
			}
			else if (turnleft || cmd->angleturn > angleturn[0])
			{
				zchange[forplayer] = true;
				newtarget = P_LookForFocusTarget(player, ticcmd_ztargetfocus[forplayer], 1, cv_cam_lockonboss[forplayer].value);
			}
			else if (turnright || cmd->angleturn < -angleturn[0])
			{
				zchange[forplayer] = true;
				newtarget = P_LookForFocusTarget(player, ticcmd_ztargetfocus[forplayer], -1, cv_cam_lockonboss[forplayer].value);
			}

			if (newtarget)
				P_SetTarget(&ticcmd_ztargetfocus[forplayer], newtarget);

1415 1416 1417 1418
			// I assume this is netgame-safe because gunslinger spawns this for only the local player...... *sweats intensely*
			newtarget = P_SpawnMobj(ticcmd_ztargetfocus[forplayer]->x, ticcmd_ztargetfocus[forplayer]->y, ticcmd_ztargetfocus[forplayer]->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
			P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]);

1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437
			if (P_AproxDistance(
				player->mo->x - ticcmd_ztargetfocus[forplayer]->x,
				player->mo->y - ticcmd_ztargetfocus[forplayer]->y
			) > 50*player->mo->scale)
			{
				INT32 anglediff = R_PointToAngle2(player->mo->x, player->mo->y, ticcmd_ztargetfocus[forplayer]->x, ticcmd_ztargetfocus[forplayer]->y) - *myangle;
				const INT32 maxturn = ANG10/2;
				anglediff /= 4;

				if (anglediff > maxturn)
					anglediff = maxturn;
				else if (anglediff < -maxturn)
					anglediff = -maxturn;

				*myangle += anglediff;
			}
		}
	}

colette committed
1438 1439 1440
	if (ticcmd_centerviewdown[forplayer] && controlstyle == CS_SIMPLE)
		controlstyle = CS_LEGACY;

1441 1442
	if (PLAYERINPUTDOWN(ssplayer, gc_camreset))
	{
1443 1444
		if (thiscam->chase && !resetdown[forplayer])
			P_ResetCamera(&players[ssplayer == 1 ? displayplayer : secondarydisplayplayer], thiscam);
1445 1446 1447 1448 1449 1450 1451

		resetdown[forplayer] = true;
	}
	else
		resetdown[forplayer] = false;


Alam Ed Arias committed
1452
	// jump button
colette committed
1453 1454
	axis = PlayerJoyAxis(ssplayer, AXISJUMP);
	if (PLAYERINPUTDOWN(ssplayer, gc_jump) || (usejoystick && axis > 0))
Alam Ed Arias committed
1455 1456 1457 1458
		cmd->buttons |= BT_JUMP;

	// player aiming shit, ahhhh...
	{
colette committed
1459
		INT32 player_invert = invertmouse ? -1 : 1;
Alam Ed Arias committed
1460 1461
		INT32 screen_invert =
			(player->mo && (player->mo->eflags & MFE_VERTICALFLIP)
1462
			 && (!thiscam->chase || player->pflags & PF_FLIPCAM)) //because chasecam's not inverted
Alam Ed Arias committed
1463
			 ? -1 : 1; // set to -1 or 1 to multiply
1464
		 INT32 configlookaxis = ssplayer == 1 ? cv_lookaxis.value : cv_lookaxis2.value;
Alam Ed Arias committed
1465 1466 1467 1468

		// mouse look stuff (mouse look is not the same as mouse aim)
		if (mouseaiming)
		{
colette committed
1469
			keyboard_look[forplayer] = false;
Alam Ed Arias committed
1470 1471

			// looking up/down
colette committed
1472
			*myaiming += (*mly<<19)*player_invert*screen_invert;
Alam Ed Arias committed
1473 1474
		}

1475
		if (analogjoystickmove && joyaiming[forplayer] && lookjoystickvector.yaxis != 0 && configlookaxis != 0)
1476
			*myaiming += (lookjoystickvector.yaxis<<16) * screen_invert;
Alam Ed Arias committed
1477 1478

		// spring back if not using keyboard neither mouselookin'
1479
		if (!keyboard_look[forplayer] && configlookaxis == 0 && !joyaiming[forplayer] && !mouseaiming)
colette committed
1480
			*myaiming = 0;
Alam Ed Arias committed
1481

Marco Z committed
1482
		if (!(player->powers[pw_carry] == CR_NIGHTSMODE))
Alam Ed Arias committed
1483
		{
1484
			if (PLAYERINPUTDOWN(ssplayer, gc_lookup) || (gamepadjoystickmove && lookjoystickvector.yaxis < 0))
1485
			{
colette committed
1486 1487
				*myaiming += KB_LOOKSPEED * screen_invert;
				keyboard_look[forplayer] = true;
1488
			}
1489
			else if (PLAYERINPUTDOWN(ssplayer, gc_lookdown) || (gamepadjoystickmove && lookjoystickvector.yaxis > 0))
1490
			{
colette committed
1491 1492
				*myaiming -= KB_LOOKSPEED * screen_invert;
				keyboard_look[forplayer] = true;
1493
			}
1494
			else if (ticcmd_centerviewdown[forplayer])
colette committed
1495
				*myaiming = 0;
Alam Ed Arias committed
1496 1497 1498 1499
		}

		// accept no mlook for network games
		if (!cv_allowmlook.value)
colette committed
1500
			*myaiming = 0;
Alam Ed Arias committed
1501

colette committed
1502
		cmd->aiming = G_ClipAimingPitch(myaiming);
Alam Ed Arias committed
1503 1504
	}

colette committed
1505 1506
	if (!mouseaiming && mousemove)
		forward += *my;
Alam Ed Arias committed
1507

1508
	if ((!demoplayback && (player->pflags & PF_SLIDING))) // Analog for mouse
colette committed
1509
		side += *mx*2;
1510
	else if (controlstyle == CS_LMAOGALOG)
1511
	{
colette committed
1512
		if (*mx)
1513
		{
colette committed
1514
			if (*mx > 0)
1515 1516 1517 1518 1519
				cmd->buttons |= BT_CAMRIGHT;
			else
				cmd->buttons |= BT_CAMLEFT;
		}
	}
Alam Ed Arias committed
1520
	else
colette committed
1521
		cmd->angleturn = (INT16)(cmd->angleturn - (*mx*8));
Alam Ed Arias committed
1522

colette committed
1523
	*mx = *my = *mly = 0;
Alam Ed Arias committed
1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535

	if (forward > MAXPLMOVE)
		forward = MAXPLMOVE;
	else if (forward < -MAXPLMOVE)
		forward =