The start of the Co-Op revamp! Not tested over netplay yet, but uses TD's implementation of various Co-op friendly things as a reference (or in one place an outright code steal, thanks Sryder!)

* cv_sharedstarposts - Makes everyone share starposts, defaults to "On"
* cv_respawntype - Defaults to "Starpost". If set to that, people respawn at the starpost you just hit (assuming cv_sharedstarposts is on - may have to combine the two variables later, but seperate for testing for now). The other option is the old, unrestricted spawning. We COULD add TD bubble spawning at a later time using this variable, though.

The level DOES reset if everyone dies, but not in a way which allows for Mystic Realm style non-resetting resets. I'll handle that later.
This commit is contained in:
toasterbabe 2017-05-28 15:33:35 +01:00
parent 448014097e
commit 3723eff9f7
6 changed files with 188 additions and 38 deletions

View file

@ -347,7 +347,12 @@ consvar_t cv_maxping = {"maxping", "0", CV_SAVE, CV_Unsigned, NULL, 0, NULL, NUL
#endif #endif
// Intermission time Tails 04-19-2002 // Intermission time Tails 04-19-2002
static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}}; static CV_PossibleValue_t inttime_cons_t[] = {{0, "MIN"}, {3600, "MAX"}, {0, NULL}};
consvar_t cv_inttime = {"inttime", "20", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_inttime = {"inttime", "10", CV_NETVAR, inttime_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
consvar_t cv_sharedstarposts = {"sharedstarposts", "On", CV_NETVAR, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t respawntype_cons_t[] = {{0, "Request"}, {1, "Starpost"}, {0, NULL}};
consvar_t cv_respawntype = {"respawntype", "Starpost", CV_NETVAR|CV_CHEAT, respawntype_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}}; static CV_PossibleValue_t advancemap_cons_t[] = {{0, "Off"}, {1, "Next"}, {2, "Random"}, {0, NULL}};
consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_advancemap = {"advancemap", "Next", CV_NETVAR, advancemap_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL};
@ -500,6 +505,8 @@ void D_RegisterServerCommands(void)
CV_RegisterVar(&cv_hidetime); CV_RegisterVar(&cv_hidetime);
CV_RegisterVar(&cv_inttime); CV_RegisterVar(&cv_inttime);
CV_RegisterVar(&cv_sharedstarposts);
CV_RegisterVar(&cv_respawntype);
CV_RegisterVar(&cv_advancemap); CV_RegisterVar(&cv_advancemap);
CV_RegisterVar(&cv_playersforexit); CV_RegisterVar(&cv_playersforexit);
CV_RegisterVar(&cv_timelimit); CV_RegisterVar(&cv_timelimit);

View file

@ -89,7 +89,7 @@ extern consvar_t cv_recycler;
extern consvar_t cv_itemfinder; extern consvar_t cv_itemfinder;
extern consvar_t cv_inttime, cv_advancemap, cv_playersforexit; extern consvar_t cv_inttime, cv_sharedstarposts, cv_respawntype, cv_advancemap, cv_playersforexit;
extern consvar_t cv_overtime; extern consvar_t cv_overtime;
extern consvar_t cv_startinglives; extern consvar_t cv_startinglives;

View file

@ -2486,6 +2486,19 @@ void G_ChangePlayerReferences(mobj_t *oldmo, mobj_t *newmo)
} }
} }
#ifdef HAVE_BLUA
#define RESETMAP {\
LUAh_MapChange();\
G_DoLoadLevel(true);\
return;\
}
#else
#define RESETMAP {\
G_DoLoadLevel(true);\
return;\
}
#endif
// //
// G_DoReborn // G_DoReborn
// //
@ -2575,20 +2588,33 @@ void G_DoReborn(INT32 playernum)
} }
} }
else else
#ifdef HAVE_BLUA RESETMAP;
{
LUAh_MapChange();
#endif
G_DoLoadLevel(true);
#ifdef HAVE_BLUA
}
#endif
} }
else else
{ {
// respawn at the start // respawn at the start
mobj_t *oldmo = NULL; mobj_t *oldmo = NULL;
if (gametype == GT_COOP && (netgame || multiplayer) && cv_respawntype.value == 1)
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!(playeringame[i] && players[i].mo && players[i].mo->health && players[i].playerstate == PST_LIVE))
continue;
if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
continue;
if (players[i].bot) // ignore dumb, stupid tails
continue;
break;
}
if (i == MAXPLAYERS)
RESETMAP;
}
if (player->starposttime) if (player->starposttime)
starpost = true; starpost = true;
@ -2608,10 +2634,44 @@ void G_DoReborn(INT32 playernum)
void G_AddPlayer(INT32 playernum) void G_AddPlayer(INT32 playernum)
{ {
INT32 countplayers = 0, notexiting = 0;
player_t *p = &players[playernum]; player_t *p = &players[playernum];
// Go through the current players and make sure you have the latest starpost set
if (G_PlatformGametype() && (netgame || multiplayer))
{
INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if (players[i].bot) // ignore dumb, stupid tails
continue;
countplayers++;
if (!players->exiting)
notexiting++;
if (!(cv_sharedstarposts.value && (gametype == GT_COOP) && (p->starpostnum < players[i].starpostnum)))
continue;
p->starposttime = players[i].starposttime;
p->starpostx = players[i].starpostx;
p->starposty = players[i].starposty;
p->starpostz = players[i].starpostz;
p->starpostangle = players[i].starpostangle;
p->starpostnum = players[i].starpostnum;
}
}
p->jointime = 0; p->jointime = 0;
p->playerstate = PST_REBORN; p->playerstate = PST_REBORN;
if (countplayers && !notexiting)
P_DoPlayerExit(p);
} }
void G_ExitLevel(void) void G_ExitLevel(void)

View file

@ -2835,8 +2835,8 @@ void A_BossDeath(mobj_t *mo)
// make sure there is a player alive for victory // make sure there is a player alive for victory
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0) if (playeringame[i] && ((players[i].mo && players[i].mo->health)
|| ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0)))) || ((netgame || multiplayer) && (players[i].lives || players[i].continues))))
break; break;
if (i == MAXPLAYERS) if (i == MAXPLAYERS)
@ -3280,10 +3280,28 @@ void A_ExtraLife(mobj_t *actor)
// In shooter gametypes, give the player 100 rings instead of an extra life. // In shooter gametypes, give the player 100 rings instead of an extra life.
if (gametype != GT_COOP && gametype != GT_COMPETITION) if (gametype != GT_COOP && gametype != GT_COMPETITION)
{
P_GivePlayerRings(player, 100); P_GivePlayerRings(player, 100);
P_PlayLivesJingle(player);
}
else else
P_GivePlayerLives(player, 1); {
P_PlayLivesJingle(player); INT32 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
if ((netgame || multiplayer) && players[i].spectator) // Ignore spectators
continue;
if (players[i].bot)
continue;
P_GivePlayerLives(&players[i], 1);
P_PlayLivesJingle(&players[i]);
}
}
} }
// Function: A_BombShield // Function: A_BombShield
@ -9389,8 +9407,8 @@ void A_ForceWin(mobj_t *actor)
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && ((players[i].mo && players[i].mo->health > 0) if (playeringame[i] && ((players[i].mo && players[i].mo->health)
|| ((netgame || multiplayer) && (players[i].lives > 0 || players[i].continues > 0)))) || ((netgame || multiplayer) && (players[i].lives || players[i].continues))))
break; break;
} }

View file

@ -1293,13 +1293,40 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (player->starpostnum >= special->health) if (player->starpostnum >= special->health)
return; // Already hit this post return; // Already hit this post
// Save the player's time and position. if (cv_sharedstarposts.value && gametype == GT_COOP && (netgame || multiplayer))
player->starposttime = leveltime; {
player->starpostx = toucher->x>>FRACBITS; for (i = 0; i < MAXPLAYERS; i++)
player->starposty = toucher->y>>FRACBITS; {
player->starpostz = special->z>>FRACBITS; if (playeringame[i])
player->starpostangle = special->angle; {
player->starpostnum = special->health; if (players[i].bot) // ignore dumb, stupid tails
continue;
players[i].starposttime = leveltime;
players[i].starpostx = player->mo->x>>FRACBITS;
players[i].starposty = player->mo->y>>FRACBITS;
players[i].starpostz = special->z>>FRACBITS;
players[i].starpostangle = special->angle;
players[i].starpostnum = special->health;
if (cv_respawntype.value == 1 && players[i].playerstate == PST_DEAD)
players[i].playerstate = PST_REBORN;
}
}
S_StartSound(NULL, special->info->painsound);
}
else
{
// Save the player's time and position.
player->starposttime = leveltime;
player->starpostx = toucher->x>>FRACBITS;
player->starposty = toucher->y>>FRACBITS;
player->starpostz = special->z>>FRACBITS;
player->starpostangle = special->angle;
player->starpostnum = special->health;
S_StartSound(toucher, special->info->painsound);
}
P_ClearStarPost(special->health); P_ClearStarPost(special->health);
// Find all starposts in the level with this value. // Find all starposts in the level with this value.

View file

@ -8105,22 +8105,60 @@ static void P_DeathThink(player_t *player)
player->playerstate = PST_REBORN; player->playerstate = PST_REBORN;
else if (player->lives > 0 && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages! else if (player->lives > 0 && !G_IsSpecialStage(gamemap)) // Don't allow "click to respawn" in special stages!
{ {
// Respawn with jump button, force respawn time (3 second default, cheat protected) in shooter modes. if (gametype == GT_COOP && (netgame || multiplayer) && cv_respawntype.value == 1) // Shamelessly lifted from TD. Thanks, Sryder!
if ((cmd->buttons & BT_JUMP) && player->deadtimer > cv_respawntime.value*TICRATE {
&& gametype != GT_RACE && gametype != GT_COOP) INT32 i, lastdeadplayer = -1, deadtimercheck = INT32_MAX;
player->playerstate = PST_REBORN; for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i])
continue;
// Instant respawn in race or if you're spectating. if (players[i].spectator) // Ignore spectators
if ((cmd->buttons & BT_JUMP) && (gametype == GT_RACE || player->spectator)) continue;
player->playerstate = PST_REBORN;
// One second respawn in coop. if (players[i].bot) // ignore dumb, stupid tails
if ((cmd->buttons & BT_JUMP) && player->deadtimer > TICRATE && (gametype == GT_COOP || gametype == GT_COMPETITION)) continue;
player->playerstate = PST_REBORN;
// Single player auto respawn if (players[i].playerstate != PST_DEAD)
if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE) break;
player->playerstate = PST_REBORN;
if (players[i].lives && players[i].deadtimer < deadtimercheck)
{
lastdeadplayer = i;
deadtimercheck = players[i].deadtimer;
}
}
if (i == MAXPLAYERS && lastdeadplayer != -1 && deadtimercheck > 2*TICRATE) // the last killed player will reset the level in G_DoReborn
players[lastdeadplayer].playerstate = PST_REBORN;
}
else
{
// Respawn with jump button, force respawn time (3 second default, cheat protected) in shooter modes.
if (cmd->buttons & BT_JUMP)
{
if (player->spectator)
player->playerstate = PST_REBORN;
else switch(gametype) {
case GT_COOP:
case GT_COMPETITION:
if (player->deadtimer > TICRATE)
player->playerstate = PST_REBORN;
break;
case GT_RACE:
player->playerstate = PST_REBORN;
break;
default:
if (player->deadtimer > cv_respawntime.value*TICRATE)
player->playerstate = PST_REBORN;
break;
}
}
// Single player auto respawn
if (!(netgame || multiplayer) && player->deadtimer > 5*TICRATE)
player->playerstate = PST_REBORN;
}
} }
else if ((netgame || multiplayer) && player->deadtimer == 8*TICRATE) else if ((netgame || multiplayer) && player->deadtimer == 8*TICRATE)
{ {
@ -8130,7 +8168,7 @@ static void P_DeathThink(player_t *player)
INT32 i; INT32 i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && !players[i].exiting && players[i].lives > 0) if (playeringame[i] && !players[i].exiting && players[i].lives)
break; break;
if (i == MAXPLAYERS) if (i == MAXPLAYERS)
@ -8147,7 +8185,7 @@ static void P_DeathThink(player_t *player)
INT32 i; INT32 i;
for (i = 0; i < MAXPLAYERS; i++) for (i = 0; i < MAXPLAYERS; i++)
if (playeringame[i] && (players[i].exiting || players[i].lives > 0)) if (playeringame[i] && (players[i].exiting || players[i].lives))
break; break;
if (i == MAXPLAYERS) if (i == MAXPLAYERS)