Merge branch 'next' into texture-index-255-is-transparent

This commit is contained in:
Lactozilla 2024-06-03 13:23:09 -03:00
commit 16560653a0
24 changed files with 357 additions and 115 deletions

View file

@ -387,6 +387,7 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd)
} }
// Bot AI isn't programmed in analog. // Bot AI isn't programmed in analog.
if (!dedicated)
CV_SetValue(&cv_analog[1], false); CV_SetValue(&cv_analog[1], false);
// Let Lua scripts build ticcmds // Let Lua scripts build ticcmds

View file

@ -983,7 +983,7 @@ void D_StartTitle(void)
emeralds = 0; emeralds = 0;
memset(&luabanks, 0, sizeof(luabanks)); memset(&luabanks, 0, sizeof(luabanks));
lastmaploaded = 0; lastmaploaded = 0;
pickedchar = R_SkinAvailable(cv_defaultskin.string); pickedchar = R_SkinAvailable(cv_skin.string);
// In case someone exits out at the same time they start a time attack run, // In case someone exits out at the same time they start a time attack run,
// reset modeattacking // reset modeattacking
@ -1842,17 +1842,21 @@ static boolean check_top_dir(const char **path, const char *top)
return true; return true;
} }
static int cmp_strlen_desc(const void *a, const void *b) static int cmp_strlen_desc(const void *A, const void *B)
{ {
return ((int)strlen(*(const char*const*)b) - (int)strlen(*(const char*const*)a)); const char *pA = A;
const char *pB = B;
size_t As = strlen(pA);
size_t Bs = strlen(pB);
return ((int)Bs - (int)As);
} }
boolean D_IsPathAllowed(const char *path) boolean D_IsPathAllowed(const char *path)
{ {
const char *paths[] = { char *paths[] = {
srb2home, srb2home,
srb2path, srb2path,
cv_addons_folder.string cv_addons_folder.zstring
}; };
const size_t n_paths = sizeof paths / sizeof *paths; const size_t n_paths = sizeof paths / sizeof *paths;

View file

@ -5804,6 +5804,10 @@ struct int_const_s const INT_CONST[] = {
{"MB_SCROLLUP",MB_SCROLLUP}, {"MB_SCROLLUP",MB_SCROLLUP},
{"MB_SCROLLDOWN",MB_SCROLLDOWN}, {"MB_SCROLLDOWN",MB_SCROLLDOWN},
// screen.h constants
{"BASEVIDWIDTH",BASEVIDWIDTH},
{"BASEVIDHEIGHT",BASEVIDHEIGHT},
{NULL,0} {NULL,0}
}; };

View file

@ -699,6 +699,15 @@ static void initdirpath(char *dirpath, size_t *dirpathindex, int depthleft)
dirpathindex[depthleft]--; dirpathindex[depthleft]--;
} }
//sortdir by name?
static int lumpnamecompare(const void *A, const void *B)
{
const lumpinfo_t *pA = A;
const lumpinfo_t *pB = B;
return strcmp((pA->fullname), (pB->fullname));
}
lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders) lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
{ {
DIR **dirhandle; DIR **dirhandle;
@ -889,6 +898,9 @@ lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders)
free(dirpathindex); free(dirpathindex);
free(dirhandle); free(dirhandle);
//sort files and directories
qsort (lumpinfo, numlumps, sizeof(lumpinfo_t), lumpnamecompare);
(*nlmp) = numlumps; (*nlmp) = numlumps;
return lumpinfo; return lumpinfo;
} }

View file

@ -67,6 +67,8 @@ static UINT8 *metalbuffer = NULL;
static UINT8 *metal_p; static UINT8 *metal_p;
static UINT16 metalversion; static UINT16 metalversion;
consvar_t cv_resyncdemo = CVAR_INIT("resyncdemo", "On", 0, CV_OnOff, NULL);
// extra data stuff (events registered this frame while recording) // extra data stuff (events registered this frame while recording)
static struct { static struct {
UINT8 flags; // EZT flags UINT8 flags; // EZT flags
@ -549,6 +551,9 @@ void G_ConsGhostTic(void)
testmo = players[0].mo; testmo = players[0].mo;
if (P_MobjWasRemoved(testmo))
return; // No valid mobj exists, probably because of unexpected quit
// Grab ghost data. // Grab ghost data.
ziptic = READUINT8(demo_p); ziptic = READUINT8(demo_p);
if (ziptic & GZT_XYZ) if (ziptic & GZT_XYZ)
@ -664,12 +669,15 @@ void G_ConsGhostTic(void)
CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n"));
demosynced = false; demosynced = false;
if (cv_resyncdemo.value)
{
P_UnsetThingPosition(testmo); P_UnsetThingPosition(testmo);
testmo->x = oldghost.x; testmo->x = oldghost.x;
testmo->y = oldghost.y; testmo->y = oldghost.y;
P_SetThingPosition(testmo); P_SetThingPosition(testmo);
testmo->z = oldghost.z; testmo->z = oldghost.z;
} }
}
if (*demo_p == DEMOMARKER) if (*demo_p == DEMOMARKER)
{ {

View file

@ -35,6 +35,7 @@ typedef enum
} demo_file_override_e; } demo_file_override_e;
extern demo_file_override_e demofileoverride; extern demo_file_override_e demofileoverride;
extern consvar_t cv_resyncdemo;
// Quit after playing a demo from cmdline. // Quit after playing a demo from cmdline.
extern boolean singledemo; extern boolean singledemo;

View file

@ -1386,6 +1386,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0)) if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0))
cmd->buttons |= BT_SPIN; cmd->buttons |= BT_SPIN;
if (gamestate != GS_LEVEL) // not in a level, don't build anything else
{
cmd->angleturn = ticcmd_oldangleturn[forplayer];
cmd->aiming = G_ClipAimingPitch(myaiming);
return;
}
// Centerview can be a toggle in simple mode! // Centerview can be a toggle in simple mode!
{ {
static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior static boolean last_centerviewdown[2], centerviewhold[2]; // detect taps for toggle behavior
@ -1420,7 +1427,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
ticcmd_centerviewdown[forplayer] = true; ticcmd_centerviewdown[forplayer] = true;
} }
else if (ticcmd_centerviewdown[forplayer]) else if (ticcmd_centerviewdown[forplayer] || (leveltime < 5))
{ {
if (controlstyle == CS_SIMPLE) if (controlstyle == CS_SIMPLE)
{ {
@ -1435,6 +1442,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
{ {
if ( if (
P_MobjWasRemoved(ticcmd_ztargetfocus[forplayer]) || P_MobjWasRemoved(ticcmd_ztargetfocus[forplayer]) ||
(leveltime < 5) ||
(player->playerstate != PST_LIVE) ||
player->exiting ||
!ticcmd_ztargetfocus[forplayer]->health || !ticcmd_ztargetfocus[forplayer]->health ||
(ticcmd_ztargetfocus[forplayer]->type == MT_EGGMOBILE3 && !ticcmd_ztargetfocus[forplayer]->movecount) // Sea Egg is moving around underground and shouldn't be tracked (ticcmd_ztargetfocus[forplayer]->type == MT_EGGMOBILE3 && !ticcmd_ztargetfocus[forplayer]->movecount) // Sea Egg is moving around underground and shouldn't be tracked
) )
@ -1466,7 +1476,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]); P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]);
newtarget->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating newtarget->drawonlyforplayer = player; // Hide it from the other player in splitscreen, and yourself when spectating
if (player->mo && P_AproxDistance( if (player->mo && R_PointToDist2(0, 0,
player->mo->x - ticcmd_ztargetfocus[forplayer]->x, player->mo->x - ticcmd_ztargetfocus[forplayer]->x,
player->mo->y - ticcmd_ztargetfocus[forplayer]->y player->mo->y - ticcmd_ztargetfocus[forplayer]->y
) > 50*player->mo->scale) ) > 50*player->mo->scale)
@ -1714,7 +1724,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer)
// At this point, cmd doesn't contain the final angle yet, // At this point, cmd doesn't contain the final angle yet,
// So we need to temporarily transform it so Lua scripters // So we need to temporarily transform it so Lua scripters
// don't need to handle it differently than in other hooks. // don't need to handle it differently than in other hooks.
if (addedtogame && gamestate == GS_LEVEL) if (addedtogame)
{ {
INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn; INT16 extra = ticcmd_oldangleturn[forplayer] - player->oldrelangleturn;
INT16 origangle = cmd->angleturn; INT16 origangle = cmd->angleturn;

View file

@ -5220,7 +5220,9 @@ static void HWR_SetTransformAiming(FTransform *trans, player_t *player, boolean
if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox))) if (cv_glshearing.value == 1 || (cv_glshearing.value == 2 && R_IsViewpointThirdPerson(player, skybox)))
{ {
fixed_t fixedaiming = AIMINGTODY(aimingangle); fixed_t fixedaiming = AIMINGTODY(aimingangle);
trans->viewaiming = FIXED_TO_FLOAT(fixedaiming); trans->viewaiming = FIXED_TO_FLOAT(fixedaiming) * ((float)vid.width / vid.height) / ((float)BASEVIDWIDTH / BASEVIDHEIGHT);
if (splitscreen)
trans->viewaiming *= 2.125; // splitscreen adjusts fov with 0.8, so compensate (but only halfway, since splitscreen means only half the screen is used)
trans->shearing = true; trans->shearing = true;
gl_aimingangle = 0; gl_aimingangle = 0;
} }

View file

@ -1093,19 +1093,19 @@ static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2)
return &md2->model->superspr2frames[spr2]; return &md2->model->superspr2frames[spr2];
} }
if (md2->model->spr2frames) if (md2->model->spr2frames[spr2].numframes)
return &md2->model->spr2frames[spr2]; return &md2->model->spr2frames[spr2];
return NULL; return NULL;
} }
static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player) static UINT16 HWR_GetModelSprite2Num(md2_t *md2, skin_t *skin, UINT16 spr2, player_t *player)
{ {
UINT16 super = 0; UINT16 super = 0;
UINT8 i = 0; UINT8 i = 0;
if (!md2 || !md2->model || !skin) if (!md2 || !md2->model || !skin)
return HWR_GetModelSprite2Frames(md2, 0); return 0;
while (!HWR_GetModelSprite2Frames(md2, spr2) while (!HWR_GetModelSprite2Frames(md2, spr2)
&& spr2 != SPR2_STND && spr2 != SPR2_STND
@ -1145,7 +1145,7 @@ static modelspr2frames_t *HWR_GetModelSprite2(md2_t *md2, skin_t *skin, UINT16 s
if (i >= 32) // probably an infinite loop... if (i >= 32) // probably an infinite loop...
spr2 = 0; spr2 = 0;
return HWR_GetModelSprite2Frames(md2, spr2); return spr2;
} }
// Adjust texture coords of model to fit into a patch's max_s and max_t // Adjust texture coords of model to fit into a patch's max_s and max_t
@ -1269,6 +1269,7 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj)); const UINT8 flip = (UINT8)(!(spr->mobj->eflags & MFE_VERTICALFLIP) != !R_ThingVerticallyFlipped(spr->mobj));
const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); const UINT8 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj));
spritedef_t *sprdef; spritedef_t *sprdef;
UINT16 spr2 = 0;
spriteframe_t *sprframe; spriteframe_t *sprframe;
INT32 mod; INT32 mod;
interpmobjstate_t interp; interpmobjstate_t interp;
@ -1438,13 +1439,17 @@ boolean HWR_DrawModel(gl_vissprite_t *spr)
frame = (spr->mobj->frame & FF_FRAMEMASK); frame = (spr->mobj->frame & FF_FRAMEMASK);
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
spr2frames = HWR_GetModelSprite2(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player); {
spr2 = HWR_GetModelSprite2Num(md2, spr->mobj->skin, spr->mobj->sprite2, spr->mobj->player);
spr2frames = HWR_GetModelSprite2Frames(md2, spr2);
}
if (spr2frames) if (spr2frames)
{ {
spritedef_t *defaultdef = P_GetSkinSpritedef(spr->mobj->skin, spr2);
mod = spr2frames->numframes; mod = spr2frames->numframes;
#ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod #ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod
if (mod > (INT32)sprdef->numframes) if (mod > (INT32)defaultdef->numframes)
mod = sprdef->numframes; mod = defaultdef->numframes;
#endif #endif
if (!mod) if (!mod)
mod = 1; mod = 1;

View file

@ -345,6 +345,18 @@ static int lib_reserveLuabanks(lua_State *L)
return 1; return 1;
} }
static int lib_tofixed(lua_State *L)
{
const char *arg = luaL_checkstring(L, 1);
char *end;
float f = strtof(arg, &end);
if (*end != '\0')
lua_pushnil(L);
else
lua_pushnumber(L, FLOAT_TO_FIXED(f));
return 1;
}
// M_MENU // M_MENU
////////////// //////////////
@ -4333,6 +4345,7 @@ static luaL_Reg lib[] = {
{"userdataMetatable", lib_userdataMetatable}, {"userdataMetatable", lib_userdataMetatable},
{"IsPlayerAdmin", lib_isPlayerAdmin}, {"IsPlayerAdmin", lib_isPlayerAdmin},
{"reserveLuabanks", lib_reserveLuabanks}, {"reserveLuabanks", lib_reserveLuabanks},
{"tofixed", lib_tofixed},
// m_menu // m_menu
{"M_MoveColorAfter",lib_pMoveColorAfter}, {"M_MoveColorAfter",lib_pMoveColorAfter},

View file

@ -180,7 +180,8 @@ static const char *CopyString(huddrawlist_h list, const char* str)
const char *old_offset = list->strbuf; const char *old_offset = list->strbuf;
size_t i; size_t i;
if (list->strbuf_capacity == 0) list->strbuf_capacity = 256; if (list->strbuf_capacity == 0) list->strbuf_capacity = 256;
else list->strbuf_capacity *= 2; while (list->strbuf_capacity <= list->strbuf_len + lenstr + 1)
list->strbuf_capacity *= 2;
list->strbuf = (char*) Z_Realloc(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL); list->strbuf = (char*) Z_Realloc(list->strbuf, sizeof(char) * list->strbuf_capacity, PU_STATIC, NULL);
// align the string pointers to make sure old pointers don't point towards invalid addresses // align the string pointers to make sure old pointers don't point towards invalid addresses

View file

@ -242,17 +242,12 @@ static int lib_getSpriteInfo(lua_State *L)
UINT32 i = NUMSPRITES; UINT32 i = NUMSPRITES;
lua_remove(L, 1); lua_remove(L, 1);
if (lua_isstring(L, 1)) if (lua_type(L, 1) == LUA_TSTRING)
{ {
const char *name = lua_tostring(L, 1); const char *name = lua_tostring(L, 1);
INT32 spr = R_GetSpriteNumByName(name); INT32 spr = R_GetSpriteNumByName(name);
if (spr == NUMSPRITES) if (spr == NUMSPRITES)
{
char *check;
i = strtol(name, &check, 10);
if (check == name || *check != '\0')
return luaL_error(L, "unknown sprite name %s", name); return luaL_error(L, "unknown sprite name %s", name);
}
i = spr; i = spr;
} }
else else
@ -1740,7 +1735,7 @@ static int lib_setSkinColor(lua_State *L)
else if (i == 6 || (str && fastcmp(str,"accessible"))) { else if (i == 6 || (str && fastcmp(str,"accessible"))) {
boolean v = lua_toboolean(L, 3); boolean v = lua_toboolean(L, 3);
if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.\n", cnum);
else else
info->accessible = v; info->accessible = v;
} }
@ -1835,7 +1830,7 @@ static int skincolor_set(lua_State *L)
else if (fastcmp(field,"accessible")) { else if (fastcmp(field,"accessible")) {
boolean v = lua_toboolean(L, 3); boolean v = lua_toboolean(L, 3);
if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible) if (cnum < FIRSTSUPERCOLOR && v != skincolors[cnum].accessible)
CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.", cnum); CONS_Alert(CONS_WARNING, "skincolors[] index %d is a standard color; accessibility changes are prohibited.\n", cnum);
else else
info->accessible = v; info->accessible = v;
} else } else

View file

@ -263,7 +263,7 @@ static void M_ConfirmTeamScramble(INT32 choice);
static void M_ConfirmTeamChange(INT32 choice); static void M_ConfirmTeamChange(INT32 choice);
static void M_SecretsMenu(INT32 choice); static void M_SecretsMenu(INT32 choice);
static void M_SetupChoosePlayer(INT32 choice); static void M_SetupChoosePlayer(INT32 choice);
static UINT16 M_SetupChoosePlayerDirect(INT32 choice); static INT32 M_SetupChoosePlayerDirect(INT32 choice);
static void M_QuitSRB2(INT32 choice); static void M_QuitSRB2(INT32 choice);
menu_t SP_MainDef, OP_MainDef; menu_t SP_MainDef, OP_MainDef;
menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef;
@ -7000,7 +7000,10 @@ static void M_LevelSelectWarp(INT32 choice)
if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef) if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef)
{ {
if (cursaveslot > 0) // do we have a save slot to load? if (cursaveslot > 0) // do we have a save slot to load?
{
CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
G_LoadGame((UINT32)cursaveslot, startmap); // reload from SP save data: this is needed to keep score/lives/continues from reverting to defaults G_LoadGame((UINT32)cursaveslot, startmap); // reload from SP save data: this is needed to keep score/lives/continues from reverting to defaults
}
else // no save slot, start new game but keep the current skin else // no save slot, start new game but keep the current skin
{ {
M_ClearMenus(true); M_ClearMenus(true);
@ -8649,9 +8652,14 @@ static void M_LoadSelect(INT32 choice)
M_NewGame(); M_NewGame();
} }
else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed
{
M_LoadGameLevelSelect(0); M_LoadGameLevelSelect(0);
}
else else
{
CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this
G_LoadGame((UINT32)saveSlotSelected, 0); G_LoadGame((UINT32)saveSlotSelected, 0);
}
cursaveslot = saveSlotSelected; cursaveslot = saveSlotSelected;
} }
@ -9072,7 +9080,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum)
description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH); description[i].namepic = W_CachePatchName(description[i].nametag, PU_PATCH);
} }
static UINT16 M_SetupChoosePlayerDirect(INT32 choice) static INT32 M_SetupChoosePlayerDirect(INT32 choice)
{ {
INT32 skinnum, botskinnum; INT32 skinnum, botskinnum;
UINT16 i; UINT16 i;
@ -9161,7 +9169,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice)
static void M_SetupChoosePlayer(INT32 choice) static void M_SetupChoosePlayer(INT32 choice)
{ {
UINT16 skinset = M_SetupChoosePlayerDirect(choice); INT32 skinset = M_SetupChoosePlayerDirect(choice);
if (skinset != MAXCHARACTERSLOTS) if (skinset != MAXCHARACTERSLOTS)
{ {
M_ChoosePlayer(skinset); M_ChoosePlayer(skinset);
@ -9510,6 +9518,8 @@ static void M_ChoosePlayer(INT32 choice)
//lastmapsaved = 0; //lastmapsaved = 0;
gamecomplete = 0; gamecomplete = 0;
CV_StealthSet(&cv_skin, skins[skinnum]->name);
G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect); G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect);
COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this

View file

@ -691,6 +691,7 @@ void D_RegisterClientCommands(void)
COM_AddCommand("timedemo", Command_Timedemo_f, 0); COM_AddCommand("timedemo", Command_Timedemo_f, 0);
COM_AddCommand("stopdemo", Command_Stopdemo_f, COM_LUA); COM_AddCommand("stopdemo", Command_Stopdemo_f, COM_LUA);
COM_AddCommand("playintro", Command_Playintro_f, COM_LUA); COM_AddCommand("playintro", Command_Playintro_f, COM_LUA);
CV_RegisterVar(&cv_resyncdemo);
COM_AddCommand("resetcamera", Command_ResetCamera_f, COM_LUA); COM_AddCommand("resetcamera", Command_ResetCamera_f, COM_LUA);
@ -1308,7 +1309,7 @@ static void SendNameAndColor(void)
SetColorLocal(consoleplayer, cv_playercolor.value); SetColorLocal(consoleplayer, cv_playercolor.value);
if (splitscreen) if (splitscreen || (!pickedchar && stricmp(cv_skin.string, skins[consoleplayer]->name) != 0))
SetSkinLocal(consoleplayer, R_SkinAvailable(cv_skin.string)); SetSkinLocal(consoleplayer, R_SkinAvailable(cv_skin.string));
else else
SetSkinLocal(consoleplayer, pickedchar); SetSkinLocal(consoleplayer, pickedchar);
@ -4941,6 +4942,8 @@ static boolean Skin2_CanChange(const char *valstr)
*/ */
static void Skin_OnChange(void) static void Skin_OnChange(void)
{ {
pickedchar = R_SkinAvailable(cv_skin.string);
if (!Playing()) if (!Playing())
return; return;

View file

@ -4865,7 +4865,7 @@ void A_AttractChase(mobj_t *actor)
else else
actor->flags2 &= ~MF2_DONTDRAW; actor->flags2 &= ~MF2_DONTDRAW;
// Turn flingrings back into regular rings if attracted. // Turn rings into flingrings if shield is lost or out of range
if (actor->tracer && actor->tracer->player if (actor->tracer && actor->tracer->player
&& !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime) && !(actor->tracer->player->powers[pw_shield] & SH_PROTECTELECTRIC) && actor->info->reactiontime && actor->type != (mobjtype_t)actor->info->reactiontime)
{ {
@ -4897,8 +4897,9 @@ void A_AttractChase(mobj_t *actor)
// If a FlingRing gets attracted by a shield, change it into a normal ring. // If a FlingRing gets attracted by a shield, change it into a normal ring.
if (actor->type == (mobjtype_t)actor->info->reactiontime) if (actor->type == (mobjtype_t)actor->info->reactiontime)
{ {
P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); actor->type = mobjinfo[actor->type].painchance; // Become the regular version of the fling object.
P_RemoveMobj(actor); actor->flags = mobjinfo[actor->type].flags; // Reset actor flags.
P_SetMobjState(actor, actor->info->spawnstate); // Go to regular object's spawn state.
return; return;
} }
@ -14857,12 +14858,18 @@ void A_RolloutRock(mobj_t *actor)
if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health)
actor->flags |= MF_PUSHABLE; actor->flags |= MF_PUSHABLE;
else if (actor->tracer->eflags & MFE_VERTICALFLIP)
{
actor->flags2 |= MF2_OBJECTFLIP;
actor->eflags |= MFE_VERTICALFLIP;
}
else else
{ {
actor->flags2 = (actor->flags2 & ~MF2_OBJECTFLIP) | (actor->tracer->flags2 & MF2_OBJECTFLIP); actor->flags2 &= ~MF2_OBJECTFLIP;
actor->eflags = (actor->eflags & ~MFE_VERTICALFLIP) | (actor->tracer->eflags & MFE_VERTICALFLIP); actor->eflags &= ~MFE_VERTICALFLIP;
} }
actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves
if (actor->eflags & MFE_JUSTHITFLOOR) if (actor->eflags & MFE_JUSTHITFLOOR)

View file

@ -389,7 +389,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{ {
INT32 pflags; INT32 pflags;
UINT8 secondjump; UINT8 secondjump;
boolean washoming;
if (spring->flags & MF_ENEMY) // Spring shells if (spring->flags & MF_ENEMY) // Spring shells
P_SetTarget(&spring->target, object); P_SetTarget(&spring->target, object);
@ -421,7 +420,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{ {
boolean wasSpindashing = object->player->dashspeed > 0 && (object->player->charability2 == CA2_SPINDASH); boolean wasSpindashing = object->player->dashspeed > 0 && (object->player->charability2 == CA2_SPINDASH);
pflags = object->player->pflags & (PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_THOKKED | PF_BOUNCING); // I still need these. pflags = object->player->pflags & (PF_STARTJUMP | PF_JUMPED | PF_NOJUMPDAMAGE | PF_SPINNING | PF_BOUNCING); // I still need these.
if (wasSpindashing) // Ensure we're in the rolling state, and not spindash. if (wasSpindashing) // Ensure we're in the rolling state, and not spindash.
P_SetMobjState(object, S_PLAY_ROLL); P_SetMobjState(object, S_PLAY_ROLL);
@ -433,7 +432,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
} }
} }
secondjump = object->player->secondjump; secondjump = object->player->secondjump;
washoming = object->player->homing;
P_ResetPlayer(object->player); P_ResetPlayer(object->player);
if (spring->info->painchance == 1) // For all those ancient, SOC'd abilities. if (spring->info->painchance == 1) // For all those ancient, SOC'd abilities.
@ -445,8 +443,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{ {
object->player->pflags |= (pflags &~ PF_STARTJUMP); object->player->pflags |= (pflags &~ PF_STARTJUMP);
object->player->secondjump = secondjump; object->player->secondjump = secondjump;
if (washoming)
object->player->pflags &= ~PF_THOKKED;
} }
else if (!vertispeed) else if (!vertispeed)
{ {
@ -1027,7 +1023,6 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
if ((thing->flags & MF_PUSHABLE) // not carrying a player if ((thing->flags & MF_PUSHABLE) // not carrying a player
&& (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something && (tmthing->player->powers[pw_carry] == CR_NONE) // player is not already riding something
&& !(tmthing->player->powers[pw_ignorelatch] & (1<<15)) && !(tmthing->player->powers[pw_ignorelatch] & (1<<15))
&& ((tmthing->eflags & MFE_VERTICALFLIP) == (thing->eflags & MFE_VERTICALFLIP))
&& (P_MobjFlip(tmthing)*tmthing->momz <= 0) && (P_MobjFlip(tmthing)*tmthing->momz <= 0)
&& ((!(tmthing->eflags & MFE_VERTICALFLIP) && abs(thing->z + thing->height - tmthing->z) < (thing->height>>2)) && ((!(tmthing->eflags & MFE_VERTICALFLIP) && abs(thing->z + thing->height - tmthing->z) < (thing->height>>2))
|| (tmthing->eflags & MFE_VERTICALFLIP && abs(tmthing->z + tmthing->height - thing->z) < (thing->height>>2)))) || (tmthing->eflags & MFE_VERTICALFLIP && abs(tmthing->z + tmthing->height - thing->z) < (thing->height>>2))))
@ -1041,6 +1036,7 @@ static unsigned PIT_DoCheckThing(mobj_t *thing)
P_SetTarget(&tmthing->tracer, thing); P_SetTarget(&tmthing->tracer, thing);
if (!P_IsObjectOnGround(thing)) if (!P_IsObjectOnGround(thing))
thing->momz += tmthing->momz; thing->momz += tmthing->momz;
return CHECKTHING_COLLIDE; return CHECKTHING_COLLIDE;
} }
} }

View file

@ -542,11 +542,21 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj)
delta2 = abs(thingtop - texmid); delta2 = abs(thingtop - texmid);
if (delta1 > delta2) { // Below if (delta1 > delta2) { // Below
if (opentop > texbottom) if (opentop > texbottom) {
opentop = texbottom; opentop = texbottom;
if (linedef->flags & ML_NOSKEW)
opentopslope = NULL;
else
opentopslope = linedef->midtexslope;
}
} else { // Above } else { // Above
if (openbottom < textop) if (openbottom < textop) {
openbottom = textop; openbottom = textop;
if (linedef->flags & ML_NOSKEW)
openbottomslope = NULL;
else
openbottomslope = linedef->midtexslope;
}
} }
} }
} }

View file

@ -1385,6 +1385,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
case MT_WATERDROP: case MT_WATERDROP:
case MT_CYBRAKDEMON: case MT_CYBRAKDEMON:
gravityadd >>= 1; gravityadd >>= 1;
break;
default: default:
break; break;
} }

View file

@ -831,13 +831,15 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
static void P_SpawnEmeraldHunt(void) static void P_SpawnEmeraldHunt(void)
{ {
INT32 emer[3], num[MAXHUNTEMERALDS], i, randomkey; INT32 emer[3], num[MAXHUNTEMERALDS], i, amount, randomkey;
fixed_t x, y, z; fixed_t x, y, z;
for (i = 0; i < numhuntemeralds; i++) for (i = 0; i < numhuntemeralds; i++)
num[i] = i; num[i] = i;
for (i = 0; i < 3; i++) amount = min(numhuntemeralds, 3);
for (i = 0; i < amount; i++)
{ {
// generate random index, shuffle afterwards // generate random index, shuffle afterwards
randomkey = P_RandomKey(numhuntemeralds--); randomkey = P_RandomKey(numhuntemeralds--);
@ -1113,6 +1115,8 @@ static void P_InitializeLinedef(line_t *ld)
ld->callcount = 0; ld->callcount = 0;
ld->secportal = UINT32_MAX; ld->secportal = UINT32_MAX;
ld->midtexslope = NULL;
// cph 2006/09/30 - fix sidedef errors right away. // cph 2006/09/30 - fix sidedef errors right away.
// cph 2002/07/20 - these errors are fatal if not fixed, so apply them // cph 2002/07/20 - these errors are fatal if not fixed, so apply them
for (j = 0; j < 2; j++) for (j = 0; j < 2; j++)

View file

@ -28,6 +28,8 @@
pslope_t *slopelist = NULL; pslope_t *slopelist = NULL;
UINT16 slopecount = 0; UINT16 slopecount = 0;
static void P_UpdateMidtextureSlopesForSector(sector_t *sector);
// Calculate line normal // Calculate line normal
void P_CalculateSlopeNormal(pslope_t *slope) void P_CalculateSlopeNormal(pslope_t *slope)
{ {
@ -212,6 +214,9 @@ void T_DynamicSlopeLine (dynlineplanethink_t* th)
slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta); slope->zangle = R_PointToAngle2(0, 0, th->extent, -zdelta);
slope->moved = true; slope->moved = true;
P_CalculateSlopeNormal(slope); P_CalculateSlopeNormal(slope);
P_UpdateMidtextureSlopesForSector(srcline->frontsector);
if (srcline->backsector)
P_UpdateMidtextureSlopesForSector(srcline->backsector);
} }
} }
@ -232,6 +237,12 @@ void T_DynamicSlopeVert (dynvertexplanethink_t* th)
} }
ReconfigureViaVertexes(th->slope, th->vex[0], th->vex[1], th->vex[2]); ReconfigureViaVertexes(th->slope, th->vex[0], th->vex[1], th->vex[2]);
for (i = 0; i < 3; i++)
{
if (th->secs[i])
P_UpdateMidtextureSlopesForSector(th->secs[i]);
}
} }
static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent) static inline void P_AddDynLineSlopeThinker (pslope_t* slope, dynplanetype_t type, line_t* sourceline, fixed_t extent)
@ -758,6 +769,111 @@ pslope_t *P_MakeSlopeViaEquationConstants(const double a, const double b, const
return ret; return ret;
} }
static pslope_t *P_GetReferenceSlopeForMidtexture(line_t *line)
{
if (line->flags & ML_MIDPEG)
{
// Line has ML_MIDPEG, so use the floor slope
fixed_t frontheight = P_GetSectorFloorZAt(line->frontsector, line->v1->x, line->v1->y);
fixed_t backheight = P_GetSectorFloorZAt(line->backsector, line->v1->x, line->v1->y);
if (frontheight > backheight)
{
return line->frontsector->f_slope;
}
else
{
return line->backsector->f_slope;
}
}
else
{
// Line does not have ML_MIDPEG, so use the ceiling slope
fixed_t frontheight = P_GetSectorCeilingZAt(line->frontsector, line->v1->x, line->v1->y);
fixed_t backheight = P_GetSectorCeilingZAt(line->backsector, line->v1->x, line->v1->y);
if (frontheight < backheight)
{
return line->frontsector->c_slope;
}
else
{
return line->backsector->c_slope;
}
}
return NULL;
}
// Updates a slope for a solid midtexture based on the slope of the sector it's in.
static void P_UpdateSolidMidtextureSlope(line_t *line, pslope_t *ref)
{
pslope_t *slope = line->midtexslope;
if (ref == NULL)
return;
// Set origin
vector3_t origin;
origin.x = line->v1->x;
origin.y = line->v1->y;
origin.z = P_GetSlopeZAt(ref, origin.x, origin.y);
FV3_Copy(&slope->o, &origin);
// Get where the line ends
vector3_t point;
point.x = line->v2->x;
point.y = line->v2->y;
point.z = P_GetSlopeZAt(ref, point.x, point.y);
// Get length of the line
fixed_t extent = R_PointToDist2(0, 0, line->dx, line->dy);
// Precalculate variables
slope->zdelta = FixedDiv(origin.z - point.z, extent);
slope->zangle = R_PointToAngle2(0, origin.z, extent, point.z);
slope->xydirection = line->angle;
// Precalculate the direction
vector2_t dir;
dir.x = FixedMul(FINECOSINE(slope->zangle >> ANGLETOFINESHIFT), FINECOSINE((slope->xydirection+ANGLE_180) >> ANGLETOFINESHIFT));
dir.y = FixedMul(FINECOSINE(slope->zangle >> ANGLETOFINESHIFT), FINESINE((slope->xydirection+ANGLE_180) >> ANGLETOFINESHIFT));
FV2_Copy(&slope->d, &dir);
P_CalculateSlopeNormal(slope);
// Calling P_CalculateSlopeVectors is not necessary.
slope->moved = true;
}
// Goes through every line in the sector and updates the midtexture slope if it is present
static void P_UpdateMidtextureSlopesForSector(sector_t *sector)
{
for (size_t i = 0; i < sector->linecount; i++)
{
if (sector->lines[i]->midtexslope != NULL)
P_UpdateSolidMidtextureSlope(sector->lines[i], P_GetReferenceSlopeForMidtexture(sector->lines[i]));
}
}
// Creates a solid midtexture slope for the line if possible
static void P_CreateSolidMidtextureSlope(line_t *line)
{
if (line->backsector == NULL) // Ignore single-sided lines (of course)
return;
if ((line->flags & ML_MIDSOLID) == 0) // Ignore if the midtexture is not solid
return;
pslope_t *ref = P_GetReferenceSlopeForMidtexture(line);
if (ref)
{
line->midtexslope = Slope_Add(ref->flags & SL_NOPHYSICS);
P_UpdateSolidMidtextureSlope(line, ref);
}
}
/// Initializes and reads the slopes from the map data. /// Initializes and reads the slopes from the map data.
void P_SpawnSlopes(const boolean fromsave) { void P_SpawnSlopes(const boolean fromsave) {
size_t i; size_t i;
@ -785,14 +901,21 @@ void P_SpawnSlopes(const boolean fromsave) {
/// Copies slopes from tagged sectors via line specials. /// Copies slopes from tagged sectors via line specials.
/// \note Doesn't actually copy, but instead they share the same pointers. /// \note Doesn't actually copy, but instead they share the same pointers.
// Also, creates midtexture slopes.
for (i = 0; i < numlines; i++) for (i = 0; i < numlines; i++)
switch (lines[i].special) {
line_t *line = &lines[i];
switch (line->special)
{ {
case 720: case 720:
P_CopySectorSlope(&lines[i]); P_CopySectorSlope(line);
default: default:
break; break;
} }
P_CreateSolidMidtextureSlope(line);
}
} }
/// Initializes slopes. /// Initializes slopes.
@ -810,10 +933,10 @@ void P_InitSlopes(void)
// Returns the height of the sloped plane at (x, y) as a fixed_t // Returns the height of the sloped plane at (x, y) as a fixed_t
fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y) fixed_t P_GetSlopeZAt(const pslope_t *slope, fixed_t x, fixed_t y)
{ {
fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) + fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) / 2 +
FixedMul(y - slope->o.y, slope->d.y); FixedMul(y - slope->o.y, slope->d.y) / 2;
return slope->o.z + FixedMul(dist, slope->zdelta); return slope->o.z + FixedMul(dist, slope->zdelta) * 2;
} }
// Like P_GetSlopeZAt but falls back to z if slope is NULL // Like P_GetSlopeZAt but falls back to z if slope is NULL

View file

@ -1089,6 +1089,13 @@ void P_ResetPlayer(player_t *player)
if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer)) if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer))
{ {
player->mo->tracer->flags |= MF_PUSHABLE; player->mo->tracer->flags |= MF_PUSHABLE;
// goose the mom a little bit to trigger gravity to process for a tic
if (player->mo->tracer->eflags & MFE_VERTICALFLIP)
player->mo->tracer->momz -= 1;
else
player->mo->tracer->momz += 1;
P_SetTarget(&player->mo->tracer->tracer, NULL); P_SetTarget(&player->mo->tracer->tracer, NULL);
} }
P_SetTarget(&player->mo->tracer, NULL); P_SetTarget(&player->mo->tracer, NULL);
@ -2372,7 +2379,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff)
if (dorollstuff) if (dorollstuff)
{ {
if ((player->charability2 == CA2_SPINDASH) && !((player->pflags & (PF_SPINNING|PF_THOKKED)) == PF_THOKKED) && !(player->charability == CA_THOK && player->secondjump) if ((player->charability2 == CA2_SPINDASH) && !((player->pflags & (PF_SPINNING|PF_THOKKED)) == PF_THOKKED) && !(player->charability == CA_THOK && player->secondjump)
&& (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) > (5*player->mo->scale))) && (player->cmd.buttons & BT_SPIN) && (FixedHypot(player->mo->momx, player->mo->momy) >= (5*player->mo->scale)))
player->pflags = (player->pflags|PF_SPINNING) & ~PF_THOKKED; player->pflags = (player->pflags|PF_SPINNING) & ~PF_THOKKED;
else if (!(player->pflags & PF_STARTDASH)) else if (!(player->pflags & PF_STARTDASH))
player->pflags &= ~PF_SPINNING; player->pflags &= ~PF_SPINNING;
@ -4546,6 +4553,13 @@ void P_DoJump(player_t *player, boolean soundandstate, boolean allowflip)
player->mo->momz += player->mo->tracer->momz; player->mo->momz += player->mo->tracer->momz;
if (!P_IsObjectOnGround(player->mo->tracer)) if (!P_IsObjectOnGround(player->mo->tracer))
P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true); P_SetObjectMomZ(player->mo->tracer, -9*FRACUNIT, true);
// goose the mom a little bit to trigger gravity to process for a tic
if (player->mo->tracer->eflags & MFE_VERTICALFLIP)
player->mo->tracer->momz -= 1;
else
player->mo->tracer->momz += 1;
player->mo->tracer->flags |= MF_PUSHABLE; player->mo->tracer->flags |= MF_PUSHABLE;
P_SetTarget(&player->mo->tracer->tracer, NULL); P_SetTarget(&player->mo->tracer->tracer, NULL);
} }
@ -4721,7 +4735,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
// Revving // Revving
else if ((cmd->buttons & BT_SPIN) && (player->pflags & PF_STARTDASH)) else if ((cmd->buttons & BT_SPIN) && (player->pflags & PF_STARTDASH))
{ {
if (player->speed > 5*player->mo->scale) if (player->speed >= 5*player->mo->scale)
{ {
player->pflags &= ~PF_STARTDASH; player->pflags &= ~PF_STARTDASH;
P_SetMobjState(player->mo, S_PLAY_ROLL); P_SetMobjState(player->mo, S_PLAY_ROLL);
@ -4761,9 +4775,8 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
if (!player->spectator) if (!player->spectator)
S_StartSound(player->mo, sfx_spin); S_StartSound(player->mo, sfx_spin);
} }
else
// Catapult the player from a spindash rev! // Catapult the player from a spindash rev!
if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING)) else if (onground && !(player->pflags & PF_SPINDOWN) && (player->pflags & PF_STARTDASH) && (player->pflags & PF_SPINNING))
{ {
player->pflags &= ~PF_STARTDASH; player->pflags &= ~PF_STARTDASH;
if (player->powers[pw_carry] == CR_BRAKGOOP) if (player->powers[pw_carry] == CR_BRAKGOOP)
@ -12129,6 +12142,10 @@ void P_PlayerThink(player_t *player)
case CR_DUSTDEVIL: case CR_DUSTDEVIL:
player->drawangle += ANG20; player->drawangle += ANG20;
break; break;
case CR_FAN:
if (player->pflags & PF_ANALOGMODE) // Don't impact drawangle in any special way when on a fan
player->drawangle = player->mo->angle;
break;
/* -- in case we wanted to have the camera freely movable during zoom tubes /* -- in case we wanted to have the camera freely movable during zoom tubes
case CR_ZOOMTUBE:*/ case CR_ZOOMTUBE:*/
case CR_ROPEHANG: case CR_ROPEHANG:

View file

@ -614,6 +614,8 @@ typedef struct line_s
INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0 INT16 callcount; // no. of calls left before triggering, for the "X calls" linedef specials, defaults to 0
UINT32 secportal; // transferred sector portal UINT32 secportal; // transferred sector portal
struct pslope_s *midtexslope;
} line_t; } line_t;
typedef struct typedef struct

View file

@ -271,75 +271,86 @@ SDL_bool framebuffer = SDL_FALSE;
UINT8 keyboard_started = false; UINT8 keyboard_started = false;
#ifdef UNIXBACKTRACE #ifdef UNIXBACKTRACE
#define STDERR_WRITE(string) if (fd != -1) I_OutputMsg("%s", string)
#define CRASHLOG_WRITE(string) if (fd != -1) junk = write(fd, string, strlen(string)) static void bt_write_file(int fd, const char *string) {
#define CRASHLOG_STDERR_WRITE(string) \ ssize_t written = 0;
if (fd != -1)\ ssize_t sourcelen = strlen(string);
junk = write(fd, string, strlen(string));\
I_OutputMsg("%s", string) while (fd != -1 && (written != -1 && errno != EINTR) && written < sourcelen)
written = write(fd, string, sourcelen);
}
static void bt_write_stderr(const char *string) {
bt_write_file(STDERR_FILENO, string);
}
static void bt_write_all(int fd, const char *string) {
bt_write_file(fd, string);
bt_write_file(STDERR_FILENO, string);
}
static void write_backtrace(INT32 signal) static void write_backtrace(INT32 signal)
{ {
int fd = -1; int fd = -1;
#ifndef NOEXECINFO
size_t size;
#endif
time_t rawtime; time_t rawtime;
struct tm timeinfo; struct tm timeinfo;
ssize_t junk;
enum { BT_SIZE = 1024, STR_SIZE = 32 }; enum { BT_SIZE = 1024, STR_SIZE = 32 };
#ifndef NOEXECINFO #ifndef NOEXECINFO
void *array[BT_SIZE]; void *funcptrs[BT_SIZE];
size_t bt_size;
#endif #endif
char timestr[STR_SIZE]; char timestr[STR_SIZE];
const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n"; const char *filename = va("%s" PATHSEP "%s", srb2home, "crash-log.txt");
const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr.
fd = open(va("%s" PATHSEP "%s", srb2home, "crash-log.txt"), O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR); fd = open(filename, O_CREAT|O_APPEND|O_RDWR, S_IRUSR|S_IWUSR);
if (fd == -1) if (fd == -1) // File handle error
I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n"); bt_write_stderr("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n");
// Get the current time as a string. // Get the current time as a string.
time(&rawtime); time(&rawtime);
localtime_r(&rawtime, &timeinfo); localtime_r(&rawtime, &timeinfo);
strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo); strftime(timestr, STR_SIZE, "%a, %d %b %Y %T %z", &timeinfo);
CRASHLOG_WRITE("------------------------\n"); // Nice looking seperator bt_write_file(fd, "------------------------\n"); // Nice looking seperator
CRASHLOG_STDERR_WRITE("\n"); // Newline to look nice for both outputs. bt_write_all(fd, "\n"); // Newline to look nice for both outputs.
CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message bt_write_all(fd, "An error occurred within SRB2! Send this stack trace to someone who can help!\n");
STDERR_WRITE(error2); // Tell the user where the crash log is.
if (fd != -1) // If the crash log exists,
bt_write_stderr("(Or find crash-log.txt in your SRB2 directory.)\n"); // tell the user where the crash log is.
// Tell the log when we crashed. // Tell the log when we crashed.
CRASHLOG_WRITE("Time of crash: "); bt_write_file(fd, "Time of crash: ");
CRASHLOG_WRITE(timestr); bt_write_file(fd, timestr);
CRASHLOG_WRITE("\n"); bt_write_file(fd, "\n");
// Give the crash log the cause and a nice 'Backtrace:' thing // Give the crash log the cause and a nice 'Backtrace:' thing
// The signal is given to the user when the parent process sees we crashed. // The signal is given to the user when the parent process sees we crashed.
CRASHLOG_WRITE("Cause: "); bt_write_file(fd, "Cause: ");
CRASHLOG_WRITE(strsignal(signal)); bt_write_file(fd, strsignal(signal));
CRASHLOG_WRITE("\n"); // Newline for the signal name bt_write_file(fd, "\n"); // Newline for the signal name
#ifndef NOEXECINFO #ifdef NOEXECINFO
CRASHLOG_STDERR_WRITE("\nBacktrace:\n"); bt_write_all(fd, "\nNo Backtrace support\n");
#else
bt_write_all(fd, "\nBacktrace:\n");
// Flood the output and log with the backtrace // Flood the output and log with the backtrace
size = backtrace(array, BT_SIZE); bt_size = backtrace(funcptrs, BT_SIZE);
backtrace_symbols_fd(array, size, fd); backtrace_symbols_fd(funcptrs, bt_size, fd);
backtrace_symbols_fd(array, size, STDERR_FILENO); backtrace_symbols_fd(funcptrs, bt_size, STDERR_FILENO);
#endif #endif
CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :) bt_write_file(fd, "\n"); // Write another newline to the log so it looks nice :)
(void)junk; if (fd != -1) {
fsync(fd); // reaaaaally make sure we got that data written.
close(fd); close(fd);
}
} }
#undef STDERR_WRITE
#undef CRASHLOG_WRITE
#undef CRASHLOG_STDERR_WRITE
#endif // UNIXBACKTRACE #endif // UNIXBACKTRACE
static void I_ReportSignal(int num, int coredumped) static void I_ReportSignal(int num, int coredumped)

View file

@ -382,6 +382,8 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code)
static boolean ShouldIgnoreMouse(void) static boolean ShouldIgnoreMouse(void)
{ {
if (cv_alwaysgrabmouse.value)
return false;
if (menuactive) if (menuactive)
return !M_MouseNeeded(); return !M_MouseNeeded();
if (paused || con_destlines || chat_on) if (paused || con_destlines || chat_on)