Merge remote-tracking branch 'origin/master' into f_wipes

This commit is contained in:
Jaime Passos 2019-11-14 20:24:42 -03:00
commit 6be45ec241
17 changed files with 220 additions and 169 deletions

View File

@ -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

View File

@ -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);

View File

@ -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 <name / [MAP]code / number> [-gametype <type>] [-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

View File

@ -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",

View File

@ -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))<<V_ALPHASHIFT;
whitecol[0] = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SUPERGOLD3, GTC_CACHE);
whitecol[1] = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
}
}
// Draw emblem
V_DrawSciencePatch(40<<FRACBITS, 20<<FRACBITS, 0, TTEMBL[0], sc);
if (whitecol[0])
{
V_DrawFixedPatch(40<<FRACBITS, 20<<FRACBITS, sc, whitefade, TTEMBL[0], whitecol[0]);
V_DrawFixedPatch(40<<FRACBITS, 20<<FRACBITS, sc, V_TRANSLUCENT + ((whitefade/2) & V_ALPHAMASK), TTEMBL[0], whitecol[1]);
}
// Animate SONIC ROBO BLAST 2 before the white flash at tic 30.
if (finalecount <= 29)
{
// Ribbon unfurls, revealing SONIC text, from tic 0 to tic 24. SONIC text is pre-baked into this ribbon graphic.
V_DrawSciencePatch(39<<FRACBITS, 88<<FRACBITS, 0, TTRIBB[min(max(0, finalecount), 24)], sc);
// Darken non-text things.
V_DrawFadeScreen(0xFF00, 12);
// Animate SONIC text while the ribbon unfurls, from tic 0 to tic 28.
if(finalecount >= 0)
V_DrawSciencePatch(89<<FRACBITS, 92<<FRACBITS, 0, TTSONT[min(finalecount, 28)], sc);
@ -2693,6 +2719,7 @@ void F_TitleScreenDrawer(void)
case 8: case 7: fadeval = V_30TRANS; break;
case 6: case 5: fadeval = V_20TRANS; break;
case 4: case 3: fadeval = V_10TRANS; break;
default: break;
}
}
V_DrawSciencePatch(79<<FRACBITS, 132<<FRACBITS, fadeval, TTROBO[0], sc);
@ -3113,9 +3140,15 @@ void F_TitleScreenDrawer(void)
// After tic 34, starting when the flash fades,
// draw the combined ribbon and SONIC ROBO BLAST 2 logo. Note the different Y value, because this
// graphic is cropped differently from the unfurling ribbon.
if (finalecount > 34)
if (finalecount > 29)
V_DrawSciencePatch(39<<FRACBITS, 93<<FRACBITS, 0, TTRBTX[0], sc);
if (whitecol[0])
{
V_DrawFixedPatch(39<<FRACBITS, 93<<FRACBITS, sc, whitefade, TTRBTX[0], whitecol[0]);
V_DrawFixedPatch(39<<FRACBITS, 93<<FRACBITS, sc, V_TRANSLUCENT + ((whitefade/2) & V_ALPHAMASK), TTRBTX[0], whitecol[1]);
}
//
// FRONT LAYER CHARACTERS
//
@ -3254,13 +3287,6 @@ void F_TitleScreenDrawer(void)
}
}
// Flash at tic 30, timed to O__TITLE percussion. Hold the flash until tic 34.
// After tic 34, fade the flash until tic 44.
if (finalecount > 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

View File

@ -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;

View File

@ -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;

View File

@ -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

View File

@ -1180,6 +1180,7 @@ typedef enum state
// Snailer
S_SNAILER1,
S_SNAILER_FLICKY,
// Vulture
S_VULTURE_STND,

View File

@ -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

View File

@ -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);

View File

@ -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
}

View File

@ -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);

View File

@ -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)<<FRACBITS);
for (i = 0; i < 2; i++)
{
const angle_t fa = (P_RandomByte()*FINEANGLES/16) & FINEMASK;
@ -8249,18 +8248,18 @@ void P_MobjThinker(mobj_t *mobj)
ns = 4 * FRACUNIT;
mo2->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;

View File

@ -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;

View File

@ -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);

View File

@ -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"},