diff --git a/src/b_bot.c b/src/b_bot.c index af57d65ec..6229cb1d6 100644 --- a/src/b_bot.c +++ b/src/b_bot.c @@ -387,7 +387,8 @@ void B_BuildTiccmd(player_t *player, ticcmd_t *cmd) } // Bot AI isn't programmed in analog. - CV_SetValue(&cv_analog[1], false); + if (!dedicated) + CV_SetValue(&cv_analog[1], false); // Let Lua scripts build ticcmds if (LUA_HookTiccmd(player, cmd, HOOK(BotTiccmd))) diff --git a/src/d_main.c b/src/d_main.c index afa10ae3c..2405b0136 100644 --- a/src/d_main.c +++ b/src/d_main.c @@ -983,7 +983,7 @@ void D_StartTitle(void) emeralds = 0; memset(&luabanks, 0, sizeof(luabanks)); 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, // reset modeattacking @@ -1842,17 +1842,21 @@ static boolean check_top_dir(const char **path, const char *top) 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) { - const char *paths[] = { + char *paths[] = { srb2home, srb2path, - cv_addons_folder.string + cv_addons_folder.zstring }; const size_t n_paths = sizeof paths / sizeof *paths; diff --git a/src/deh_tables.c b/src/deh_tables.c index c7c7c6040..f113f6b19 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -5804,6 +5804,10 @@ struct int_const_s const INT_CONST[] = { {"MB_SCROLLUP",MB_SCROLLUP}, {"MB_SCROLLDOWN",MB_SCROLLDOWN}, + // screen.h constants + {"BASEVIDWIDTH",BASEVIDWIDTH}, + {"BASEVIDHEIGHT",BASEVIDHEIGHT}, + {NULL,0} }; diff --git a/src/filesrch.c b/src/filesrch.c index 944e8447f..3a729a9c8 100644 --- a/src/filesrch.c +++ b/src/filesrch.c @@ -699,6 +699,15 @@ static void initdirpath(char *dirpath, size_t *dirpathindex, int 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) { DIR **dirhandle; @@ -889,6 +898,9 @@ lumpinfo_t *getdirectoryfiles(const char *path, UINT16 *nlmp, UINT16 *nfolders) free(dirpathindex); free(dirhandle); + //sort files and directories + qsort (lumpinfo, numlumps, sizeof(lumpinfo_t), lumpnamecompare); + (*nlmp) = numlumps; return lumpinfo; } diff --git a/src/g_demo.c b/src/g_demo.c index 0efba5a59..cfa34fc7e 100644 --- a/src/g_demo.c +++ b/src/g_demo.c @@ -67,6 +67,8 @@ static UINT8 *metalbuffer = NULL; static UINT8 *metal_p; static UINT16 metalversion; +consvar_t cv_resyncdemo = CVAR_INIT("resyncdemo", "On", 0, CV_OnOff, NULL); + // extra data stuff (events registered this frame while recording) static struct { UINT8 flags; // EZT flags @@ -549,6 +551,9 @@ void G_ConsGhostTic(void) testmo = players[0].mo; + if (P_MobjWasRemoved(testmo)) + return; // No valid mobj exists, probably because of unexpected quit + // Grab ghost data. ziptic = READUINT8(demo_p); if (ziptic & GZT_XYZ) @@ -664,11 +669,14 @@ void G_ConsGhostTic(void) CONS_Alert(CONS_WARNING, M_GetText("Demo playback has desynced!\n")); demosynced = false; - P_UnsetThingPosition(testmo); - testmo->x = oldghost.x; - testmo->y = oldghost.y; - P_SetThingPosition(testmo); - testmo->z = oldghost.z; + if (cv_resyncdemo.value) + { + P_UnsetThingPosition(testmo); + testmo->x = oldghost.x; + testmo->y = oldghost.y; + P_SetThingPosition(testmo); + testmo->z = oldghost.z; + } } if (*demo_p == DEMOMARKER) diff --git a/src/g_demo.h b/src/g_demo.h index e8c0c8d95..67f61f54d 100644 --- a/src/g_demo.h +++ b/src/g_demo.h @@ -35,6 +35,7 @@ typedef enum } demo_file_override_e; extern demo_file_override_e demofileoverride; +extern consvar_t cv_resyncdemo; // Quit after playing a demo from cmdline. extern boolean singledemo; diff --git a/src/g_game.c b/src/g_game.c index 8d19c9e7c..bf369d111 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1363,11 +1363,11 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) axis = PlayerJoyAxis(ssplayer, JA_FIRENORMAL); if (PLAYERINPUTDOWN(ssplayer, GC_FIRENORMAL) || (usejoystick && axis > 0)) cmd->buttons |= BT_FIRENORMAL; - + // Toss flag button if (PLAYERINPUTDOWN(ssplayer, GC_TOSSFLAG)) cmd->buttons |= BT_TOSSFLAG; - + // Shield button axis = PlayerJoyAxis(ssplayer, JA_SHIELD); if (PLAYERINPUTDOWN(ssplayer, GC_SHIELD) || (usejoystick && axis > 0)) @@ -1386,6 +1386,13 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) if (PLAYERINPUTDOWN(ssplayer, GC_SPIN) || (usejoystick && axis > 0)) 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! { 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; } - else if (ticcmd_centerviewdown[forplayer]) + else if (ticcmd_centerviewdown[forplayer] || (leveltime < 5)) { if (controlstyle == CS_SIMPLE) { @@ -1435,6 +1442,9 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) { if ( P_MobjWasRemoved(ticcmd_ztargetfocus[forplayer]) || + (leveltime < 5) || + (player->playerstate != PST_LIVE) || + player->exiting || !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 ) @@ -1466,7 +1476,7 @@ void G_BuildTiccmd(ticcmd_t *cmd, INT32 realtics, UINT8 ssplayer) P_SetTarget(&newtarget->target, ticcmd_ztargetfocus[forplayer]); 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->y - ticcmd_ztargetfocus[forplayer]->y ) > 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, // So we need to temporarily transform it so Lua scripters // 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 origangle = cmd->angleturn; @@ -4018,7 +4028,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent) INT32 i; INT16 newmapnum; boolean spec = G_IsSpecialStage(gamemap); - + // go to next level // newmapnum is 0-based, unlike gamemap if (nextmapoverride != 0) @@ -4122,7 +4132,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent) if (spec && (!gottoken || ignoretokens) && !nextmapoverride) newmapnum = lastmap; // Exiting from a special stage? Go back to the game. Tails 08-11-2001 - + if (!(gametyperules & GTR_CAMPAIGN)) { if (cv_advancemap.value == 0) // Stay on same map. @@ -4130,7 +4140,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent) else if (cv_advancemap.value == 2) // Go to random map. newmapnum = RandMap(G_TOLFlag(gametype_to_use), prevmap); } - + return newmapnum; } @@ -4140,7 +4150,7 @@ INT16 G_GetNextMap(boolean ignoretokens, boolean silent) static void G_DoCompleted(void) { INT32 i; - + tokenlist = 0; // Reset the list if (modeattacking && pausedelay) @@ -4168,7 +4178,7 @@ static void G_DoCompleted(void) //Get and set prevmap/nextmap prevmap = (INT16)(gamemap-1); nextmap = G_GetNextMap(false, false); - + automapactive = false; // We are committed to this map now. diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 91b2e2c50..5dc0af894 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -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))) { 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; gl_aimingangle = 0; } diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 0bb8de851..0f466f051 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1093,19 +1093,19 @@ static modelspr2frames_t *HWR_GetModelSprite2Frames(md2_t *md2, UINT16 spr2) return &md2->model->superspr2frames[spr2]; } - if (md2->model->spr2frames) + if (md2->model->spr2frames[spr2].numframes) return &md2->model->spr2frames[spr2]; 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; UINT8 i = 0; if (!md2 || !md2->model || !skin) - return HWR_GetModelSprite2Frames(md2, 0); + return 0; while (!HWR_GetModelSprite2Frames(md2, spr2) && 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... 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 @@ -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 hflip = (UINT8)(!(spr->mobj->mirrored) != !R_ThingHorizontallyFlipped(spr->mobj)); spritedef_t *sprdef; + UINT16 spr2 = 0; spriteframe_t *sprframe; INT32 mod; interpmobjstate_t interp; @@ -1438,13 +1439,17 @@ boolean HWR_DrawModel(gl_vissprite_t *spr) frame = (spr->mobj->frame & FF_FRAMEMASK); 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) { + spritedef_t *defaultdef = P_GetSkinSpritedef(spr->mobj->skin, spr2); mod = spr2frames->numframes; #ifndef DONTHIDEDIFFANIMLENGTH // by default, different anim length is masked by the mod - if (mod > (INT32)sprdef->numframes) - mod = sprdef->numframes; + if (mod > (INT32)defaultdef->numframes) + mod = defaultdef->numframes; #endif if (!mod) mod = 1; diff --git a/src/lua_baselib.c b/src/lua_baselib.c index f6b8f462b..dc6a26c81 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -345,6 +345,18 @@ static int lib_reserveLuabanks(lua_State *L) 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 ////////////// @@ -4333,6 +4345,7 @@ static luaL_Reg lib[] = { {"userdataMetatable", lib_userdataMetatable}, {"IsPlayerAdmin", lib_isPlayerAdmin}, {"reserveLuabanks", lib_reserveLuabanks}, + {"tofixed", lib_tofixed}, // m_menu {"M_MoveColorAfter",lib_pMoveColorAfter}, diff --git a/src/lua_hudlib_drawlist.c b/src/lua_hudlib_drawlist.c index c518ba525..cb58e628e 100644 --- a/src/lua_hudlib_drawlist.c +++ b/src/lua_hudlib_drawlist.c @@ -180,7 +180,8 @@ static const char *CopyString(huddrawlist_h list, const char* str) const char *old_offset = list->strbuf; size_t i; 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); // align the string pointers to make sure old pointers don't point towards invalid addresses diff --git a/src/lua_infolib.c b/src/lua_infolib.c index eeb1067a3..511c20031 100644 --- a/src/lua_infolib.c +++ b/src/lua_infolib.c @@ -242,17 +242,12 @@ static int lib_getSpriteInfo(lua_State *L) UINT32 i = NUMSPRITES; lua_remove(L, 1); - if (lua_isstring(L, 1)) + if (lua_type(L, 1) == LUA_TSTRING) { const char *name = lua_tostring(L, 1); INT32 spr = R_GetSpriteNumByName(name); 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; } else @@ -1740,7 +1735,7 @@ static int lib_setSkinColor(lua_State *L) else if (i == 6 || (str && fastcmp(str,"accessible"))) { boolean v = lua_toboolean(L, 3); 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 info->accessible = v; } @@ -1835,7 +1830,7 @@ static int skincolor_set(lua_State *L) else if (fastcmp(field,"accessible")) { boolean v = lua_toboolean(L, 3); 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 info->accessible = v; } else diff --git a/src/m_menu.c b/src/m_menu.c index f25c78e88..e0c240fec 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -263,7 +263,7 @@ static void M_ConfirmTeamScramble(INT32 choice); static void M_ConfirmTeamChange(INT32 choice); static void M_SecretsMenu(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); menu_t SP_MainDef, OP_MainDef; menu_t MISC_ScrambleTeamDef, MISC_ChangeTeamDef; @@ -3674,7 +3674,7 @@ void M_StartControlPanel(void) { // Devmode unlocks Pandora's Box in the pause menu boolean pandora = ((M_SecretUnlocked(SECRET_PANDORA, serverGamedata) || cv_debug || devparm) && !marathonmode); - + if (gamestate != GS_LEVEL || ultimatemode) // intermission, so gray out stuff. { SPauseMenu[spause_pandora].status = (pandora) ? (IT_GRAYEDOUT) : (IT_DISABLED); @@ -4156,7 +4156,7 @@ static void M_DrawStaticBox(fixed_t x, fixed_t y, INT32 flags, fixed_t w, fixed_ temp = (gametic % temp) * h*2*FRACUNIT; // Which frame to draw V_DrawCroppedPatch(x*FRACUNIT, y*FRACUNIT, (w*FRACUNIT) / 160, (h*FRACUNIT) / 100, flags, patch, NULL, 0, temp, w*2*FRACUNIT, h*2*FRACUNIT); - + W_UnlockCachedPatch(patch); return; } @@ -7000,7 +7000,10 @@ static void M_LevelSelectWarp(INT32 choice) if (currentMenu == &SP_LevelSelectDef || currentMenu == &SP_PauseLevelSelectDef) { 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 + } else // no save slot, start new game but keep the current skin { M_ClearMenus(true); @@ -8649,9 +8652,14 @@ static void M_LoadSelect(INT32 choice) M_NewGame(); } else if (savegameinfo[saveSlotSelected-1].gamemap & 8192) // Completed + { M_LoadGameLevelSelect(0); + } else + { + CV_StealthSet(&cv_skin, DEFAULTSKIN); // already handled by loadgame so we don't want this G_LoadGame((UINT32)saveSlotSelected, 0); + } cursaveslot = saveSlotSelected; } @@ -9072,7 +9080,7 @@ static void M_CacheCharacterSelectEntry(INT32 i, INT32 skinnum) 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; UINT16 i; @@ -9161,7 +9169,7 @@ static UINT16 M_SetupChoosePlayerDirect(INT32 choice) static void M_SetupChoosePlayer(INT32 choice) { - UINT16 skinset = M_SetupChoosePlayerDirect(choice); + INT32 skinset = M_SetupChoosePlayerDirect(choice); if (skinset != MAXCHARACTERSLOTS) { M_ChoosePlayer(skinset); @@ -9510,6 +9518,8 @@ static void M_ChoosePlayer(INT32 choice) //lastmapsaved = 0; gamecomplete = 0; + CV_StealthSet(&cv_skin, skins[skinnum]->name); + G_DeferedInitNew(ultmode, G_BuildMapName(startmap), skinnum, false, fromlevelselect); COM_BufAddText("dummyconsvar 1\n"); // G_DeferedInitNew doesn't do this @@ -10186,7 +10196,7 @@ void M_DrawNightsAttackMenu(void) skinnumber = 0; //Default to Sonic else skinnumber = (cv_chooseskin.value-1); - + spritedef_t *sprdef = &skins[skinnumber]->sprites[SPR2_NFLY]; //Make our patch the selected character's NFLY sprite spritetimer = FixedInt(ntsatkdrawtimer/2) % skins[skinnumber]->sprites[SPR2_NFLY].numframes; //Make the sprite timer cycle though all the frames at 2 tics per frame spriteframe_t *sprframe = &sprdef->spriteframes[spritetimer]; //Our animation frame is equal to the number on the timer @@ -10199,11 +10209,11 @@ void M_DrawNightsAttackMenu(void) color = skins[skinnumber]->supercolor+4; else //If you don't go super in NiGHTS or at all, use prefcolor color = skins[skinnumber]->prefcolor; - + angle_t fa = (FixedAngle(((FixedInt(ntsatkdrawtimer * 4)) % 360)<>ANGLETOFINESHIFT) & FINEMASK; V_DrawFixedPatch(270<highresscale, skins[skinnumber]->shieldscale), + FixedDiv(skins[skinnumber]->highresscale, skins[skinnumber]->shieldscale), (sprframe->flip & 1<<6) ? V_FLIP : 0, natksprite, R_GetTranslationColormap(TC_BLINK, color, GTC_CACHE)); diff --git a/src/netcode/d_netcmd.c b/src/netcode/d_netcmd.c index e073a863c..f7b98c4db 100644 --- a/src/netcode/d_netcmd.c +++ b/src/netcode/d_netcmd.c @@ -691,6 +691,7 @@ void D_RegisterClientCommands(void) COM_AddCommand("timedemo", Command_Timedemo_f, 0); COM_AddCommand("stopdemo", Command_Stopdemo_f, COM_LUA); COM_AddCommand("playintro", Command_Playintro_f, COM_LUA); + CV_RegisterVar(&cv_resyncdemo); COM_AddCommand("resetcamera", Command_ResetCamera_f, COM_LUA); @@ -1308,7 +1309,7 @@ static void SendNameAndColor(void) 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)); else SetSkinLocal(consoleplayer, pickedchar); @@ -4608,7 +4609,7 @@ static void Command_ExitLevel_f(void) SendNetXCmd(XD_EXITLEVEL, NULL, 0); return; } - + // Allow exiting without cheating if at least one player beat the level // Consistent with just setting playersforexit to one if (splitscreen || multiplayer) @@ -4622,7 +4623,7 @@ static void Command_ExitLevel_f(void) continue; if (players[i].lives <= 0) continue; - + if ((players[i].pflags & PF_FINISHED) || players[i].exiting) { SendNetXCmd(XD_EXITLEVEL, NULL, 0); @@ -4630,7 +4631,7 @@ static void Command_ExitLevel_f(void) } } } - + // Only consider it a cheat if we're not allowed to go to the next map if (M_CampaignWarpIsCheat(gametype, G_GetNextMap(true, true) + 1, serverGamedata)) CONS_Alert(CONS_NOTICE, M_GetText("Cheats must be enabled to force exit to a locked level!\n")); @@ -4769,7 +4770,7 @@ static void Command_Cheats_f(void) G_SetUsedCheats(false); return; } - + if (usedCheats) CONS_Printf(M_GetText("Cheats are enabled, the game cannot be saved.\n")); else @@ -4941,6 +4942,8 @@ static boolean Skin2_CanChange(const char *valstr) */ static void Skin_OnChange(void) { + pickedchar = R_SkinAvailable(cv_skin.string); + if (!Playing()) return; diff --git a/src/p_enemy.c b/src/p_enemy.c index 4990db6fd..59934aa40 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -4865,7 +4865,7 @@ void A_AttractChase(mobj_t *actor) else 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 && !(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 (actor->type == (mobjtype_t)actor->info->reactiontime) { - P_SpawnMobj(actor->x, actor->y, actor->z, actor->info->painchance); - P_RemoveMobj(actor); + actor->type = mobjinfo[actor->type].painchance; // Become the regular version of the fling object. + actor->flags = mobjinfo[actor->type].flags; // Reset actor flags. + P_SetMobjState(actor, actor->info->spawnstate); // Go to regular object's spawn state. return; } @@ -14857,12 +14858,18 @@ void A_RolloutRock(mobj_t *actor) if (!actor->tracer || P_MobjWasRemoved(actor->tracer) || !actor->tracer->health) actor->flags |= MF_PUSHABLE; + else if (actor->tracer->eflags & MFE_VERTICALFLIP) + { + actor->flags2 |= MF2_OBJECTFLIP; + actor->eflags |= MFE_VERTICALFLIP; + } else { - actor->flags2 = (actor->flags2 & ~MF2_OBJECTFLIP) | (actor->tracer->flags2 & MF2_OBJECTFLIP); - actor->eflags = (actor->eflags & ~MFE_VERTICALFLIP) | (actor->tracer->eflags & MFE_VERTICALFLIP); + actor->flags2 &= ~MF2_OBJECTFLIP; + actor->eflags &= ~MFE_VERTICALFLIP; } + actor->friction = FRACUNIT; // turns out riding on solids sucks, so let's just make it easier on ourselves if (actor->eflags & MFE_JUSTHITFLOOR) diff --git a/src/p_map.c b/src/p_map.c index f97ddfa3c..668a8ab64 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -389,7 +389,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) { INT32 pflags; UINT8 secondjump; - boolean washoming; if (spring->flags & MF_ENEMY) // Spring shells 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); - 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. P_SetMobjState(object, S_PLAY_ROLL); @@ -433,7 +432,6 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object) } } secondjump = object->player->secondjump; - washoming = object->player->homing; P_ResetPlayer(object->player); 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->secondjump = secondjump; - if (washoming) - object->player->pflags &= ~PF_THOKKED; } else if (!vertispeed) { @@ -1027,7 +1023,6 @@ static unsigned PIT_DoCheckThing(mobj_t *thing) 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_ignorelatch] & (1<<15)) - && ((tmthing->eflags & MFE_VERTICALFLIP) == (thing->eflags & MFE_VERTICALFLIP)) && (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(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); if (!P_IsObjectOnGround(thing)) thing->momz += tmthing->momz; + return CHECKTHING_COLLIDE; } } diff --git a/src/p_maputl.c b/src/p_maputl.c index 0bc22390b..5da7839f3 100644 --- a/src/p_maputl.c +++ b/src/p_maputl.c @@ -542,11 +542,21 @@ void P_LineOpening(line_t *linedef, mobj_t *mobj) delta2 = abs(thingtop - texmid); if (delta1 > delta2) { // Below - if (opentop > texbottom) + if (opentop > texbottom) { opentop = texbottom; + if (linedef->flags & ML_NOSKEW) + opentopslope = NULL; + else + opentopslope = linedef->midtexslope; + } } else { // Above - if (openbottom < textop) + if (openbottom < textop) { openbottom = textop; + if (linedef->flags & ML_NOSKEW) + openbottomslope = NULL; + else + openbottomslope = linedef->midtexslope; + } } } } diff --git a/src/p_mobj.c b/src/p_mobj.c index 9cdd2628d..fbbae5a1e 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -1385,6 +1385,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo) case MT_WATERDROP: case MT_CYBRAKDEMON: gravityadd >>= 1; + break; default: break; } diff --git a/src/p_setup.c b/src/p_setup.c index 41487d702..c4b4a35b3 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -831,13 +831,15 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) 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; for (i = 0; i < numhuntemeralds; 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 randomkey = P_RandomKey(numhuntemeralds--); @@ -1113,6 +1115,8 @@ static void P_InitializeLinedef(line_t *ld) ld->callcount = 0; ld->secportal = UINT32_MAX; + ld->midtexslope = NULL; + // cph 2006/09/30 - fix sidedef errors right away. // cph 2002/07/20 - these errors are fatal if not fixed, so apply them for (j = 0; j < 2; j++) diff --git a/src/p_slopes.c b/src/p_slopes.c index e75d36ede..c2bacad9e 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -28,6 +28,8 @@ pslope_t *slopelist = NULL; UINT16 slopecount = 0; +static void P_UpdateMidtextureSlopesForSector(sector_t *sector); + // Calculate line normal 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->moved = true; 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]); + + 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) @@ -758,6 +769,111 @@ pslope_t *P_MakeSlopeViaEquationConstants(const double a, const double b, const 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. void P_SpawnSlopes(const boolean fromsave) { size_t i; @@ -785,14 +901,21 @@ void P_SpawnSlopes(const boolean fromsave) { /// Copies slopes from tagged sectors via line specials. /// \note Doesn't actually copy, but instead they share the same pointers. + // Also, creates midtexture slopes. for (i = 0; i < numlines; i++) - switch (lines[i].special) + { + line_t *line = &lines[i]; + + switch (line->special) { case 720: - P_CopySectorSlope(&lines[i]); + P_CopySectorSlope(line); default: break; } + + P_CreateSolidMidtextureSlope(line); + } } /// Initializes slopes. @@ -810,10 +933,10 @@ void P_InitSlopes(void) // 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 dist = FixedMul(x - slope->o.x, slope->d.x) + - FixedMul(y - slope->o.y, slope->d.y); + fixed_t dist = FixedMul(x - slope->o.x, slope->d.x) / 2 + + 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 diff --git a/src/p_user.c b/src/p_user.c index 7cd128cf0..7ad5bccbb 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -915,7 +915,7 @@ void P_NightserizePlayer(player_t *player, INT32 nighttime) player->textvar = NTV_BONUSTIMEEND; // Score and grades player->finishedspheres = (INT16)(player->spheres); player->finishedrings = (INT16)(player->rings); - + // Add score to temp leaderboards player->lastmaretime = leveltime - player->marebegunat; G_AddTempNightsRecords(player, player->marescore, player->lastmaretime, (UINT8)(oldmare + 1)); @@ -1089,6 +1089,13 @@ void P_ResetPlayer(player_t *player) if (player->mo->tracer && !P_MobjWasRemoved(player->mo->tracer)) { 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, NULL); @@ -2372,7 +2379,7 @@ boolean P_PlayerHitFloor(player_t *player, boolean dorollstuff) if (dorollstuff) { 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; else if (!(player->pflags & PF_STARTDASH)) 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; if (!P_IsObjectOnGround(player->mo->tracer)) 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; P_SetTarget(&player->mo->tracer->tracer, NULL); } @@ -4721,7 +4735,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) // Revving 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; P_SetMobjState(player->mo, S_PLAY_ROLL); @@ -4761,9 +4775,8 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) if (!player->spectator) S_StartSound(player->mo, sfx_spin); } - else // 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; if (player->powers[pw_carry] == CR_BRAKGOOP) @@ -8766,7 +8779,7 @@ void P_MovePlayer(player_t *player) if (!(player->mo->momz || player->mo->momx || player->mo->momy) && !(player->mo->eflags & MFE_GOOWATER) && player->panim == PA_IDLE && !(player->powers[pw_carry])) P_DoTeeter(player); - + // Toss a flag if (G_GametypeHasTeams() && (cmd->buttons & BT_TOSSFLAG) && !(player->powers[pw_super]) && !(player->tossdelay)) { @@ -12129,6 +12142,10 @@ void P_PlayerThink(player_t *player) case CR_DUSTDEVIL: player->drawangle += ANG20; 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 case CR_ZOOMTUBE:*/ case CR_ROPEHANG: diff --git a/src/r_defs.h b/src/r_defs.h index a363d99ff..698abc7e2 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -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 UINT32 secportal; // transferred sector portal + + struct pslope_s *midtexslope; } line_t; typedef struct diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 115b900f5..8bae550b0 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -271,75 +271,86 @@ SDL_bool framebuffer = SDL_FALSE; UINT8 keyboard_started = false; #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)) -#define CRASHLOG_STDERR_WRITE(string) \ - if (fd != -1)\ - junk = write(fd, string, strlen(string));\ - I_OutputMsg("%s", string) + +static void bt_write_file(int fd, const char *string) { + ssize_t written = 0; + ssize_t sourcelen = strlen(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) { int fd = -1; -#ifndef NOEXECINFO - size_t size; -#endif time_t rawtime; struct tm timeinfo; - ssize_t junk; enum { BT_SIZE = 1024, STR_SIZE = 32 }; #ifndef NOEXECINFO - void *array[BT_SIZE]; + void *funcptrs[BT_SIZE]; + size_t bt_size; #endif char timestr[STR_SIZE]; - const char *error = "An error occurred within SRB2! Send this stack trace to someone who can help!\n"; - const char *error2 = "(Or find crash-log.txt in your SRB2 directory.)\n"; // Shown only to stderr. + const char *filename = va("%s" PATHSEP "%s", srb2home, "crash-log.txt"); - 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) - I_OutputMsg("\nWARNING: Couldn't open crash log for writing! Make sure your permissions are correct. Please save the below report!\n"); + if (fd == -1) // File handle error + 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. time(&rawtime); localtime_r(&rawtime, &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. - CRASHLOG_STDERR_WRITE(error); // "Oops, SRB2 crashed" message - STDERR_WRITE(error2); // Tell the user where the crash log is. + bt_write_all(fd, "\n"); // Newline to look nice for both outputs. + bt_write_all(fd, "An error occurred within SRB2! Send this stack trace to someone who can help!\n"); + + 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. - CRASHLOG_WRITE("Time of crash: "); - CRASHLOG_WRITE(timestr); - CRASHLOG_WRITE("\n"); + bt_write_file(fd, "Time of crash: "); + bt_write_file(fd, timestr); + bt_write_file(fd, "\n"); // 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. - CRASHLOG_WRITE("Cause: "); - CRASHLOG_WRITE(strsignal(signal)); - CRASHLOG_WRITE("\n"); // Newline for the signal name + bt_write_file(fd, "Cause: "); + bt_write_file(fd, strsignal(signal)); + bt_write_file(fd, "\n"); // Newline for the signal name -#ifndef NOEXECINFO - CRASHLOG_STDERR_WRITE("\nBacktrace:\n"); +#ifdef NOEXECINFO + bt_write_all(fd, "\nNo Backtrace support\n"); +#else + bt_write_all(fd, "\nBacktrace:\n"); // Flood the output and log with the backtrace - size = backtrace(array, BT_SIZE); - backtrace_symbols_fd(array, size, fd); - backtrace_symbols_fd(array, size, STDERR_FILENO); + bt_size = backtrace(funcptrs, BT_SIZE); + backtrace_symbols_fd(funcptrs, bt_size, fd); + backtrace_symbols_fd(funcptrs, bt_size, STDERR_FILENO); #endif - CRASHLOG_WRITE("\n"); // Write another newline to the log so it looks nice :) - (void)junk; - close(fd); + bt_write_file(fd, "\n"); // Write another newline to the log so it looks nice :) + if (fd != -1) { + fsync(fd); // reaaaaally make sure we got that data written. + close(fd); + } } -#undef STDERR_WRITE -#undef CRASHLOG_WRITE -#undef CRASHLOG_STDERR_WRITE + #endif // UNIXBACKTRACE static void I_ReportSignal(int num, int coredumped) diff --git a/src/sdl/i_video.c b/src/sdl/i_video.c index 76fe172fc..249be61f6 100644 --- a/src/sdl/i_video.c +++ b/src/sdl/i_video.c @@ -382,6 +382,8 @@ static INT32 Impl_SDL_Scancode_To_Keycode(SDL_Scancode code) static boolean ShouldIgnoreMouse(void) { + if (cv_alwaysgrabmouse.value) + return false; if (menuactive) return !M_MouseNeeded(); if (paused || con_destlines || chat_on)