diff --git a/src/command.c b/src/command.c index d39730f98..0a0b62956 100644 --- a/src/command.c +++ b/src/command.c @@ -345,6 +345,40 @@ size_t COM_CheckParm(const char *check) return 0; } +/** \brief COM_CheckParm, but checks only the start of each argument. + * E.g. checking for "-no" would match "-noerror" too. + */ +size_t COM_CheckPartialParm(const char *check) +{ + int len; + size_t i; + + len = strlen(check); + + for (i = 1; i < com_argc; i++) + { + if (strncasecmp(check, com_argv[i], len) == 0) + return i; + } + return 0; +} + +/** Find the first argument that starts with a hyphen (-). + * \return The index of the argument, or 0 + * if there are no such arguments. + */ +size_t COM_FirstOption(void) +{ + size_t i; + + for (i = 1; i < com_argc; i++) + { + if (com_argv[i][0] == '-')/* options start with a hyphen */ + return i; + } + return 0; +} + /** Parses a string into command-line tokens. * * \param ptext A null-terminated string. Does not need to be diff --git a/src/command.h b/src/command.h index 4682ba4a4..d324481f7 100644 --- a/src/command.h +++ b/src/command.h @@ -29,6 +29,8 @@ size_t COM_Argc(void); const char *COM_Argv(size_t arg); // if argv > argc, returns empty string char *COM_Args(void); size_t COM_CheckParm(const char *check); // like M_CheckParm :) +size_t COM_CheckPartialParm(const char *check); +size_t COM_FirstOption(void); // match existing command or NULL const char *COM_CompleteCommand(const char *partial, INT32 skips); diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 3fb204aea..14746265f 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -1736,56 +1736,6 @@ void D_MapChange(INT32 mapnum, INT32 newgametype, boolean pultmode, boolean rese } } -enum -{ - MAP_COMMAND_FORCE_OPTION, - MAP_COMMAND_GAMETYPE_OPTION, - MAP_COMMAND_NORESETPLAYERS_OPTION, - - NUM_MAP_COMMAND_OPTIONS -}; - -static size_t CheckOptions( - int num_options, - size_t *first_argumentp, - size_t *user_options, - const char ***option_names, - int *option_num_arguments -) -{ - int arguments_used; - size_t first_argument; - - int i; - const char **pp; - const char *name; - size_t n; - - arguments_used = 0; - first_argument = COM_Argc(); - - for (i = 0; i < num_options; ++i) - { - pp = option_names[i]; - name = *pp; - do - { - if (( n = COM_CheckParm(name) )) - { - user_options[i] = n; - arguments_used += 1 + option_num_arguments[i]; - if (n < first_argument) - first_argument = n; - } - } - while (( name = *++pp )) ; - } - - (*first_argumentp) = first_argument; - - return arguments_used; -} - static char * ConcatCommandArgv (int start, int end) { @@ -1829,43 +1779,10 @@ ConcatCommandArgv (int start, int end) // static void Command_Map_f(void) { - const char *force_option_names[] = - { - "-force", - "-f", - NULL - }; - const char *gametype_option_names[] = - { - "-gametype", - "-g", - "-gt", - NULL - }; - const char *noresetplayers_option_names[] = - { - "-noresetplayers", - NULL - }; - const char **option_names[] = - { - force_option_names, - gametype_option_names, - noresetplayers_option_names, - }; - int option_num_arguments[] = - { - 0,/* -force */ - 1,/* -gametype */ - 0,/* -noresetplayers */ - }; - - size_t acceptableargc;/* (this includes the command name itself!) */ - size_t first_argument; - - size_t user_options [NUM_MAP_COMMAND_OPTIONS] = {0}; - - const char *arg_gametype; + size_t first_option; + size_t option_force; + size_t option_gametype; + const char *gametypename; boolean newresetplayers; boolean mustmodifygame; @@ -1888,18 +1805,15 @@ static void Command_Map_f(void) return; } - /* map name + options */ - acceptableargc = 2 + CheckOptions(NUM_MAP_COMMAND_OPTIONS, - &first_argument, - user_options, option_names, option_num_arguments); - - newresetplayers = !user_options[MAP_COMMAND_NORESETPLAYERS_OPTION]; + option_force = COM_CheckPartialParm("-f"); + option_gametype = COM_CheckPartialParm("-g"); + newresetplayers = ! COM_CheckParm("-noresetplayers"); mustmodifygame = !( netgame || multiplayer ) && (!modifiedgame || savemoddata ); - if (mustmodifygame && !user_options[MAP_COMMAND_FORCE_OPTION]) + if (mustmodifygame && !option_force) { /* May want to be more descriptive? */ CONS_Printf(M_GetText("Sorry, level change disabled in single player.\n")); @@ -1912,26 +1826,37 @@ static void Command_Map_f(void) return; } - if (user_options[MAP_COMMAND_GAMETYPE_OPTION] && !multiplayer) + if (option_gametype) { - CONS_Printf(M_GetText("You can't switch gametypes in single player!\n")); - return; + if (!multiplayer) + { + CONS_Printf(M_GetText( + "You can't switch gametypes in single player!\n")); + return; + } + else if (COM_Argc() < option_gametype + 2)/* no argument after? */ + { + CONS_Alert(CONS_ERROR, + "No gametype name follows parameter '%s'.\n", + COM_Argv(option_gametype)); + return; + } } - /* If the first argument is an option, you fucked up. */ - if (COM_Argc() < acceptableargc || first_argument == 1) + if (!( first_option = COM_FirstOption() )) + first_option = COM_Argc(); + + if (first_option < 2) { /* I'm going over the fucking lines and I DON'T CAREEEEE */ CONS_Printf("map [-gametype ] [-force]:\n"); CONS_Printf(M_GetText( "Warp to a map, by its name, two character code, with optional \"MAP\" prefix, or by its number (though why would you).\n" - "All parameters are case-insensitive.\n" - "* \"-force\" may be shortened to \"-f\".\n" - "* \"-gametype\" may be shortened to \"-g\" or \"-gt\".\n")); + "All parameters are case-insensitive and may be abbreviated.\n")); return; } - mapname = ConcatCommandArgv(1, first_argument); + mapname = ConcatCommandArgv(1, first_option); mapnamelen = strlen(mapname); if (mapnamelen == 2)/* maybe two digit code */ @@ -1982,30 +1907,42 @@ static void Command_Map_f(void) realmapname = G_BuildMapTitle(newmapnum); } - if (mustmodifygame && user_options[MAP_COMMAND_FORCE_OPTION]) + if (mustmodifygame && option_force) { G_SetGameModified(false); } // new gametype value // use current one by default - if (user_options[MAP_COMMAND_GAMETYPE_OPTION]) + if (option_gametype) { - arg_gametype = COM_Argv(user_options[MAP_COMMAND_GAMETYPE_OPTION] + 1); + gametypename = COM_Argv(option_gametype + 1); - newgametype = G_GetGametypeByName(arg_gametype); + newgametype = G_GetGametypeByName(gametypename); if (newgametype == -1) // reached end of the list with no match { - d = atoi(arg_gametype); - // assume they gave us a gametype number, which is okay too - if (d >= 0 && d < NUMGAMETYPES) - newgametype = d; + /* Did they give us a gametype number? That's okay too! */ + if (isdigit(gametypename[0])) + { + d = atoi(gametypename); + if (d >= 0 && d < NUMGAMETYPES) + newgametype = d; + } + else + { + CONS_Alert(CONS_ERROR, + "'%s' is not a gametype.\n", + gametypename); + Z_Free(realmapname); + Z_Free(mapname); + return; + } } } // don't use a gametype the map doesn't support - if (cv_debug || user_options[MAP_COMMAND_FORCE_OPTION] || cv_skipmapcheck.value) + if (cv_debug || option_force || cv_skipmapcheck.value) fromlevelselect = false; // The player wants us to trek on anyway. Do so. // G_TOLFlag handles both multiplayer gametype and ignores it for !multiplayer else @@ -2060,7 +1997,6 @@ static void Command_Map_f(void) Z_Free(realmapname); } -#undef CHECKPARM /** Receives a map command and changes the map. * @@ -3907,13 +3843,17 @@ void D_GameTypeChanged(INT32 lastgametype) // There will always be a server, and this only needs to be done once. if (server && (multiplayer || netgame)) { - if (gametype == GT_COMPETITION || gametype == GT_COOP) + if (gametype == GT_COMPETITION) CV_SetValue(&cv_itemrespawn, 0); - else if (!cv_itemrespawn.changed) + else if (!cv_itemrespawn.changed || lastgametype == GT_COMPETITION) CV_SetValue(&cv_itemrespawn, 1); switch (gametype) { + case GT_COOP: + if (!cv_itemrespawntime.changed) + CV_Set(&cv_itemrespawntime, cv_itemrespawntime.defaultvalue); // respawn normally + break; case GT_MATCH: case GT_TEAMMATCH: if (!cv_timelimit.changed && !cv_pointlimit.changed) // user hasn't changed limits diff --git a/src/dehacked.c b/src/dehacked.c index 4fb0bc7f8..fff9dbee8 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -4866,6 +4866,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit // Snailer "S_SNAILER1", + "S_SNAILER_FLICKY", // Vulture "S_VULTURE_STND", diff --git a/src/f_finale.c b/src/f_finale.c index 1f5bb5ae8..b39a4444f 100644 --- a/src/f_finale.c +++ b/src/f_finale.c @@ -45,7 +45,7 @@ // Stage of animation: // 0 = text, 1 = art screen -static INT32 finalecount; +INT32 finalecount; INT32 titlescrollxspeed = 20; INT32 titlescrollyspeed = 0; UINT8 titlemapinaction = TITLEMAP_OFF; @@ -2506,7 +2506,7 @@ static void F_LoadAlacroixGraphics(SINT8 newttscale) if (!ttloaded[newttscale]) { for (j = 0; j < 22; j++) - sprintf(&lumpnames[j][0], "T%.1hu%s", (UINT8)newttscale+1, names[j]); + sprintf(&lumpnames[j][0], "T%.1hu%s", (UINT16)( (UINT8)newttscale+1 ), names[j]); LOADTTGFX(ttembl[newttscale], lumpnames[0], TTMAX_ALACROIX) LOADTTGFX(ttribb[newttscale], lumpnames[1], TTMAX_ALACROIX) @@ -2574,6 +2574,8 @@ void F_TitleScreenDrawer(void) { boolean hidepics; fixed_t sc = FRACUNIT / max(1, curttscale); + INT32 whitefade = 0; + UINT8 *whitecol[2] = {NULL, NULL}; if (modeattacking) return; // We likely came here from retrying. Don't do a damn thing. @@ -2659,16 +2661,40 @@ void F_TitleScreenDrawer(void) // if (finalecount <= 29) V_DrawFill(0, 0, BASEVIDWIDTH, BASEVIDHEIGHT, 31); + // Flash at tic 30, timed to O__TITLE percussion. Hold the flash until tic 34. + // After tic 34, fade the flash until tic 44. + else + { + if (finalecount > 29 && finalecount < 35) + V_DrawFadeScreen(0, (whitefade = 9)); + else if (finalecount > 34 && 44-finalecount > 0 && 44-finalecount < 10) + V_DrawFadeScreen(0, 44-finalecount); + if (39-finalecount > 0) + { + whitefade = (9 - (39-finalecount))<= 0) V_DrawSciencePatch(89< 34) + if (finalecount > 29) V_DrawSciencePatch(39< 29 && finalecount < 35) - V_DrawFadeScreen(0, 9); - else if (finalecount > 34 && 44-finalecount > 0 && 44-finalecount < 10) - V_DrawFadeScreen(0, 44-finalecount); - #undef CHARSTART #undef SONICSTART #undef SONICIDLE diff --git a/src/f_finale.h b/src/f_finale.h index 0bec7704a..e096690a1 100644 --- a/src/f_finale.h +++ b/src/f_finale.h @@ -74,6 +74,7 @@ void F_StartContinue(void); void F_ContinueTicker(void); void F_ContinueDrawer(void); +extern INT32 finalecount; extern INT32 titlescrollxspeed; extern INT32 titlescrollyspeed; diff --git a/src/g_game.c b/src/g_game.c index db80614bf..63caaa15c 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -1717,7 +1717,7 @@ boolean G_Responder(event_t *ev) if (gameaction == ga_nothing && !singledemo && ((demoplayback && !modeattacking && !titledemo) || gamestate == GS_TITLESCREEN)) { - if (ev->type == ev_keydown && ev->data1 != 301) + if (ev->type == ev_keydown && ev->data1 != 301 && !(gamestate == GS_TITLESCREEN && finalecount < TICRATE)) { M_StartControlPanel(); return true; diff --git a/src/info.c b/src/info.c index 2579f95af..ed29fe2bf 100644 --- a/src/info.c +++ b/src/info.c @@ -986,6 +986,7 @@ state_t states[NUMSTATES] = // Snailer {SPR_SNLR, 0, 1, {A_SnailerThink}, 0, 0, S_SNAILER1}, // S_SNAILER1 + {SPR_BOM1, 0, 0, {A_FlickySpawn}, 1<<17, 0, S_XPLD1}, // S_SNAILER_FLICKY // Vulture {SPR_VLTR, 4, 35, {A_Look}, 1, 0, S_VULTURE_STND}, // S_VULTURE_STND @@ -1836,18 +1837,18 @@ state_t states[NUMSTATES] = {SPR_BBLS, 3, 8, {A_BubbleCheck}, 0, 0, S_BUBBLES1}, // S_BUBBLES4 // Level End Sign - {SPR_SIGN, 0, -1, {A_SignPlayer}, -3, 0, S_NULL}, // S_SIGN - {SPR_SIGN, 0, 1, {A_SignSpin}, 30, 0, S_SIGNSPIN2}, // S_SIGNSPIN1 - {SPR_SIGN, 0, 0, {A_Repeat}, 4, S_SIGNSPIN1, S_SIGNSPIN3}, // S_SIGNSPIN2 - {SPR_SIGN, 0, 0, {A_SignPlayer}, -2, 0, S_SIGNSPIN4}, // S_SIGNSPIN3 - {SPR_SIGN, 0, 1, {A_SignSpin}, 30, 0, S_SIGNSPIN5}, // S_SIGNSPIN4 - {SPR_SIGN, 0, 0, {A_Repeat}, 4, S_SIGNSPIN4, S_SIGNSPIN6}, // S_SIGNSPIN5 - {SPR_SIGN, 0, 0, {A_SignPlayer}, -3, 0, S_SIGNSPIN1}, // S_SIGNSPIN6 - {SPR_SIGN, 0, 1, {A_SignPlayer}, -1, 0, S_SIGNSLOW}, // S_SIGNPLAYER - {SPR_SIGN, 0, 1, {A_SignSpin}, 30, 0, S_SIGNSLOW}, // S_SIGNSLOW - {SPR_SIGN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SIGNSTOP - {SPR_SIGN, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_SIGNBOARD - {SPR_SIGN, FF_PAPERSPRITE|1, -1, {NULL}, 0, 29, S_NULL}, // S_EGGMANSIGN + {SPR_SIGN, 0, -1, {A_SignPlayer}, -3, 0, S_NULL}, // S_SIGN + {SPR_SIGN, 0, 1, {A_SignSpin}, 30, 0, S_SIGNSPIN2}, // S_SIGNSPIN1 + {SPR_SIGN, 0, 0, {A_Repeat}, 4, S_SIGNSPIN1, S_SIGNSPIN3}, // S_SIGNSPIN2 + {SPR_SIGN, 0, 0, {A_SignPlayer}, -2, 0, S_SIGNSPIN4}, // S_SIGNSPIN3 + {SPR_SIGN, 0, 1, {A_SignSpin}, 30, 0, S_SIGNSPIN5}, // S_SIGNSPIN4 + {SPR_SIGN, 0, 0, {A_Repeat}, 4, S_SIGNSPIN4, S_SIGNSPIN6}, // S_SIGNSPIN5 + {SPR_SIGN, 0, 0, {A_SignPlayer}, -3, 0, S_SIGNSPIN1}, // S_SIGNSPIN6 + {SPR_SIGN, 0, 1, {A_SignPlayer}, -1, 0, S_SIGNSLOW}, // S_SIGNPLAYER + {SPR_SIGN, 0, 1, {A_SignSpin}, 30, 0, S_SIGNSLOW}, // S_SIGNSLOW + {SPR_SIGN, 0, -1, {NULL}, 0, 0, S_NULL}, // S_SIGNSTOP + {SPR_SIGN, FF_PAPERSPRITE|2, -1, {NULL}, 0, 0, S_NULL}, // S_SIGNBOARD + {SPR_SIGN, FF_PAPERSPRITE|1, -1, {NULL}, 0, 29, S_NULL}, // S_EGGMANSIGN // Spike Ball {SPR_SPIK, 0, 1, {NULL}, 0, 0, S_SPIKEBALL2}, // S_SPIKEBALL1 @@ -4575,7 +4576,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // painsound S_NULL, // meleestate S_NULL, // missilestate - S_XPLD_FLICKY, // deathstate + S_SNAILER_FLICKY, // deathstate S_NULL, // xdeathstate sfx_pop, // deathsound FRACUNIT, // speed @@ -7725,12 +7726,12 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = sfx_None, // attacksound S_SIGNPLAYER, // painstate MT_SPARK, // painchance - sfx_None, // painsound + sfx_s3kb8, // painsound S_EGGMANSIGN, // meleestate S_NULL, // missilestate S_SIGNSTOP, // deathstate S_NULL, // xdeathstate - sfx_None, // deathsound + sfx_s3k64, // deathsound 8, // speed 36*FRACUNIT, // radius 32*FRACUNIT, // height diff --git a/src/info.h b/src/info.h index b76d857fa..bbb6a21fc 100644 --- a/src/info.h +++ b/src/info.h @@ -1180,6 +1180,7 @@ typedef enum state // Snailer S_SNAILER1, + S_SNAILER_FLICKY, // Vulture S_VULTURE_STND, diff --git a/src/m_menu.c b/src/m_menu.c index 5ea8c6818..098f34b97 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -2985,6 +2985,9 @@ boolean M_Responder(event_t *ev) || gamestate == GS_CREDITS || gamestate == GS_EVALUATION || gamestate == GS_GAMEEND) return false; + if (gamestate == GS_TITLESCREEN && finalecount < TICRATE) + return false; + if (noFurtherInput) { // Ignore input after enter/escape/other buttons diff --git a/src/p_enemy.c b/src/p_enemy.c index 3ef099e1b..eedbecaa7 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -5042,7 +5042,6 @@ void A_UnsetSolidSteam(mobj_t *actor) void A_SignSpin(mobj_t *actor) { INT32 locvar1 = var1; - INT32 locvar2 = var2; INT16 i; angle_t rotateangle = FixedAngle(locvar1 << FRACBITS); @@ -5053,6 +5052,11 @@ void A_SignSpin(mobj_t *actor) if (P_IsObjectOnGround(actor) && P_MobjFlip(actor) * actor->momz <= 0) { + if (actor->flags2 & MF2_BOSSFLEE) + { + S_StartSound(actor, actor->info->deathsound); + actor->flags2 &= ~MF2_BOSSFLEE; + } if (actor->spawnpoint) { angle_t mapangle = FixedAngle(actor->spawnpoint->angle << FRACBITS); @@ -5069,14 +5073,20 @@ void A_SignSpin(mobj_t *actor) } else // no mapthing? just finish in your current angle { - P_SetMobjState(actor, locvar2); + P_SetMobjState(actor, actor->info->deathstate); return; } } else { + if (!(actor->flags2 & MF2_BOSSFLEE)) + { + S_StartSound(actor, actor->info->painsound); + actor->flags2 |= MF2_BOSSFLEE; + } actor->movedir = rotateangle; } + actor->angle += actor->movedir; if (actor->tracer == NULL || P_MobjWasRemoved(actor->tracer)) return; for (i = -1; i < 2; i += 2) @@ -5166,15 +5176,31 @@ void A_SignPlayer(mobj_t *actor) // I turned this function into a fucking mess. I'm so sorry. -Lach if (locvar1 == -2) // next skin { + player_t *player = actor->target ? actor->target->player : NULL; + UINT8 skinnum; +#define skincheck(num) (player ? !R_SkinUsable(player-players, num) : skins[num].availability > 0) if (ov->skin == NULL) // pick a random skin to start with! - skin = &skins[P_RandomKey(numskins)]; + { + UINT8 skincount = 0; + for (skincount = 0; skincount < numskins; skincount++) + if (!skincheck(skincount)) + skincount++; + skinnum = P_RandomKey(skincount); + for (skincount = 0; skincount < numskins; skincount++) + { + if (skincheck(skincount)) + skinnum++; + if (skincount > skinnum) + break; + } + } else // otherwise, advance 1 skin { - UINT8 skinnum = (skin_t*)ov->skin-skins; - player_t *player = actor->target ? actor->target->player : NULL; - while ((skinnum = (skinnum + 1) % numskins) && (player ? !R_SkinUsable(player-players, skinnum) : skins[skinnum].availability > 0)); - skin = &skins[skinnum]; + skinnum = (skin_t*)ov->skin-skins; + while ((skinnum = (skinnum + 1) % numskins) && skincheck(skinnum)); } +#undef skincheck + skin = &skins[skinnum]; } else // specific skin { @@ -11671,9 +11697,10 @@ void A_SpawnFreshCopy(mobj_t *actor) } // Internal Flicky spawning function. -mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers) +mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers, SINT8 moveforward) { mobj_t *flicky; + fixed_t offsx = 0, offsy = 0; if (!flickytype) { @@ -11686,7 +11713,14 @@ mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz } } - flicky = P_SpawnMobjFromMobj(actor, 0, 0, 0, flickytype); + if (moveforward) + { + fixed_t scal = mobjinfo[flickytype].radius*((fixed_t)moveforward); + offsx = P_ReturnThrustX(actor, actor->angle, scal); + offsy = P_ReturnThrustY(actor, actor->angle, scal); + } + + flicky = P_SpawnMobjFromMobj(actor, offsx, offsy, 0, flickytype); flicky->angle = actor->angle; if (flickytype == MT_SEED) @@ -11712,24 +11746,30 @@ mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz // // var1: // lower 16 bits: if 0, spawns random flicky based on level header. Else, spawns the designated thing type. -// upper 16 bits: if 0, no sound is played. Else, A_Scream is called. +// bit 17: if 0, no sound is played. Else, A_Scream is called. +// bit 18: if 1, spawn flicky slightly forward from spawn position, to avoid being stuck in wall. doesn't stack with 19. (snailers) +// bit 19: if 1, spawn flicky slightly backward from spawn position. doesn't stack with 18. // var2 = upwards thrust for spawned flicky. If zero, default value is provided. // void A_FlickySpawn(mobj_t *actor) { - INT32 locvar1 = var1; + INT32 locvar1 = var1 & 65535; INT32 locvar2 = var2; + INT32 test = (var1 >> 16); + SINT8 moveforward = 0; #ifdef HAVE_BLUA if (LUA_CallAction("A_FlickySpawn", actor)) return; #endif - if (locvar1 >> 16) { + if (test & 1) A_Scream(actor); // A shortcut for the truly lazy. - locvar1 &= 65535; - } + if (test & 2) + moveforward = 1; + else if (test & 4) + moveforward = -1; - P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true); + P_InternalFlickySpawn(actor, locvar1, ((locvar2) ? locvar2 : 8*FRACUNIT), true, moveforward); } // Internal Flicky color setting @@ -11793,7 +11833,7 @@ void A_FlickyCenter(mobj_t *actor) if (!actor->tracer) { - mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false); + mobj_t *flicky = P_InternalFlickySpawn(actor, locvar1, 1, false, 0); P_SetTarget(&flicky->target, actor); P_SetTarget(&actor->tracer, flicky); diff --git a/src/p_inter.c b/src/p_inter.c index 07847bd23..b0a401b10 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -2404,7 +2404,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget { P_SetTarget(&target->target, source); source->player->numboxes++; - if ((cv_itemrespawn.value && gametype != GT_COOP && (modifiedgame || netgame || multiplayer))) + if (cv_itemrespawn.value && gametype != GT_COOP && (modifiedgame || netgame || multiplayer)) target->fuse = cv_itemrespawntime.value*TICRATE + 2; // Random box generation } diff --git a/src/p_local.h b/src/p_local.h index 02f497850..17a1c32d2 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -357,7 +357,7 @@ boolean P_CheckMissileRange(mobj_t *actor); void P_NewChaseDir(mobj_t *actor); boolean P_LookForPlayers(mobj_t *actor, boolean allaround, boolean tracer, fixed_t dist); -mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers); +mobj_t *P_InternalFlickySpawn(mobj_t *actor, mobjtype_t flickytype, fixed_t momz, boolean lookforplayers, SINT8 moveforward); void P_InternalFlickySetColor(mobj_t *actor, UINT8 extrainfo); #define P_IsFlickyCenter(type) (type > MT_FLICKY_01 && type < MT_SEED && (type - MT_FLICKY_01) % 2 ? 1 : 0) void P_InternalFlickyBubble(mobj_t *actor); diff --git a/src/p_mobj.c b/src/p_mobj.c index 83e50df01..5d6a8a10f 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8227,8 +8227,7 @@ void P_MobjThinker(mobj_t *mobj) mobj->flags2 ^= MF2_DONTDRAW; break; case MT_EGGTRAP: // Egg Capsule animal release - if (mobj->fuse > 0 && mobj->fuse < 2*TICRATE-(TICRATE/7) - && (mobj->fuse & 3)) + if (mobj->fuse > 0 && mobj->fuse < 2*TICRATE-(TICRATE/7)) { INT32 i; fixed_t x,y,z; @@ -8236,7 +8235,7 @@ void P_MobjThinker(mobj_t *mobj) mobj_t *mo2; mobj_t *flicky; - z = mobj->subsector->sector->floorheight + ((P_RandomByte()&63)*FRACUNIT); + z = mobj->subsector->sector->floorheight + FRACUNIT + (P_RandomKey(64)<momx = FixedMul(FINESINE(fa),ns); mo2->momy = FixedMul(FINECOSINE(fa),ns); + mo2->angle = fa << ANGLETOFINESHIFT; - if (P_RandomChance(FRACUNIT/4)) // I filled a spreadsheet trying to get the equivalent chance to the original P_RandomByte hack! + if (!i && !(mobj->fuse & 2)) S_StartSound(mo2, mobj->info->deathsound); - flicky = P_InternalFlickySpawn(mo2, 0, 8*FRACUNIT, false); + flicky = P_InternalFlickySpawn(mo2, 0, 8*FRACUNIT, false, -1); if (!flicky) break; P_SetTarget(&flicky->target, mo2); flicky->momx = mo2->momx; flicky->momy = mo2->momy; - flicky->angle = fa << ANGLETOFINESHIFT; } mobj->fuse--; @@ -11011,7 +11010,7 @@ void P_RespawnSpecials(void) // only respawn items when cv_itemrespawn is on if (!(netgame || multiplayer) // Never respawn in single player - || gametype == GT_COOP // Never respawn in co-op gametype + || (maptol & TOL_NIGHTS) // Never respawn in NiGHTs || !cv_itemrespawn.value) // cvar is turned off return; diff --git a/src/p_setup.c b/src/p_setup.c index 84b4d76d1..77fb3b511 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -2223,7 +2223,10 @@ static void P_LevelInitStuff(void) tokenbits = 0; runemeraldmanager = false; emeraldspawndelay = 60*TICRATE; - nummaprings = mapheaderinfo[gamemap-1]->startrings; + if ((netgame || multiplayer) && !G_IsSpecialStage(gamemap)) + nummaprings = -1; + else + nummaprings = mapheaderinfo[gamemap-1]->startrings; // emerald hunt hunt1 = hunt2 = hunt3 = NULL; diff --git a/src/p_user.c b/src/p_user.c index 5b788fcc1..3c481e7e2 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -6906,7 +6906,7 @@ static void P_DoNiGHTSCapsule(player_t *player) { /*for (i = 0; i < 16; i++) { - mobj_t *flicky = P_InternalFlickySpawn(player->capsule, 0, ((i%4) + 1)*2*FRACUNIT, true); + mobj_t *flicky = P_InternalFlickySpawn(player->capsule, 0, ((i%4) + 1)*2*FRACUNIT, true, 0); flicky->z += player->capsule->height/2; flicky->angle = (i*(ANGLE_MAX/16)); P_InstaThrust(flicky, flicky->angle, 8*FRACUNIT); diff --git a/src/sounds.c b/src/sounds.c index 197bfc066..b067903b1 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -578,7 +578,7 @@ sfxinfo_t S_sfx[NUMSFX] = {"s3kb5", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Clink"}, {"s3kb6", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spin launch"}, {"s3kb7", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Tumbler"}, - {"s3kb8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Falling signpost"}, + {"s3kb8", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Spinning signpost"}, {"s3kb9", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Ring loss"}, {"s3kba", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flight"}, {"s3kbb", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Tired flight"},