Basic start on Special Stages

This commit is contained in:
Sally Coolatta 2022-10-01 21:32:55 -04:00
parent 1300ec5d56
commit 4ee46c74d7
10 changed files with 308 additions and 50 deletions

View file

@ -124,3 +124,4 @@ k_terrain.c
k_director.c
k_follower.c
k_profiles.c
k_specialstage.c

View file

@ -75,6 +75,7 @@
#include "k_boss.h"
#include "doomstat.h"
#include "m_random.h" // P_ClearRandom
#include "k_specialstage.h"
#ifdef CMAKECONFIG
#include "config.h"
@ -982,6 +983,9 @@ void D_StartTitle(void)
// Reset boss info
K_ResetBossInfo();
// Reset Special Stage
K_ResetSpecialStage();
// empty maptol so mario/etc sounds don't play in sound test when they shouldn't
maptol = 0;

View file

@ -62,6 +62,7 @@
#include "doomstat.h"
#include "deh_tables.h"
#include "m_perfstats.h"
#include "k_specialstage.h"
#ifdef HAVE_DISCORDRPC
#include "discord.h"
@ -2943,6 +2944,7 @@ static void Command_Map_f(void)
if (newgametype == GT_BATTLE)
{
grandprixinfo.gp = false;
specialStage.active = false;
K_ResetBossInfo();
if (mapheaderinfo[newmapnum-1] &&
@ -2952,66 +2954,79 @@ static void Command_Map_f(void)
bossinfo.encore = newencoremode;
}
}
else // default GP
else
{
grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value);
grandprixinfo.masterbots = false;
if (option_skill)
if (mapheaderinfo[newmapnum-1] &&
mapheaderinfo[newmapnum-1]->typeoflevel & TOL_SPECIAL) // Special Stage
{
const char *masterstr = "Master";
const char *skillname = COM_Argv(option_skill + 1);
INT32 newskill = -1;
INT32 j;
grandprixinfo.gp = false;
bossinfo.boss = false;
if (!strcasecmp(masterstr, skillname))
{
newskill = KARTGP_MASTER;
}
else
{
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
{
if (!strcasecmp(kartspeed_cons_t[j].strvalue, skillname))
{
newskill = (INT16)kartspeed_cons_t[j].value;
break;
}
}
specialStage.active = true;
specialStage.encore = newencoremode;
}
else // default GP
{
grandprixinfo.gamespeed = (cv_kartspeed.value == KARTSPEED_AUTO ? KARTSPEED_NORMAL : cv_kartspeed.value);
grandprixinfo.masterbots = false;
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
{
INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too
if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER)
newskill = (INT16)num;
}
}
if (newskill != -1)
if (option_skill)
{
if (newskill == KARTGP_MASTER)
const char *masterstr = "Master";
const char *skillname = COM_Argv(option_skill + 1);
INT32 newskill = -1;
INT32 j;
if (!strcasecmp(masterstr, skillname))
{
grandprixinfo.gamespeed = KARTSPEED_HARD;
grandprixinfo.masterbots = true;
newskill = KARTGP_MASTER;
}
else
{
grandprixinfo.gamespeed = newskill;
grandprixinfo.masterbots = false;
for (j = 0; kartspeed_cons_t[j].strvalue; j++)
{
if (!strcasecmp(kartspeed_cons_t[j].strvalue, skillname))
{
newskill = (INT16)kartspeed_cons_t[j].value;
break;
}
}
if (!kartspeed_cons_t[j].strvalue) // reached end of the list with no match
{
INT32 num = atoi(COM_Argv(option_skill + 1)); // assume they gave us a skill number, which is okay too
if (num >= KARTSPEED_EASY && num <= KARTGP_MASTER)
newskill = (INT16)num;
}
}
if (newskill != -1)
{
if (newskill == KARTGP_MASTER)
{
grandprixinfo.gamespeed = KARTSPEED_HARD;
grandprixinfo.masterbots = true;
}
else
{
grandprixinfo.gamespeed = newskill;
grandprixinfo.masterbots = false;
}
}
}
grandprixinfo.encore = newencoremode;
grandprixinfo.gp = true;
grandprixinfo.roundnum = 0;
grandprixinfo.cup = NULL;
grandprixinfo.wonround = false;
bossinfo.boss = false;
specialStage.active = false;
grandprixinfo.initalize = true;
}
grandprixinfo.encore = newencoremode;
grandprixinfo.gp = true;
grandprixinfo.roundnum = 0;
grandprixinfo.cup = NULL;
grandprixinfo.wonround = false;
bossinfo.boss = false;
grandprixinfo.initalize = true;
}
}

View file

@ -518,6 +518,7 @@ enum TypeOfLevel
TOL_RACE = 0x0001, ///< Race
TOL_BATTLE = 0x0002, ///< Battle
TOL_BOSS = 0x0004, ///< Boss (variant of battle, but forbidden)
TOL_SPECIAL = 0x0008, ///< Special Stage (variant of race, but forbidden)
// Modifiers
TOL_TV = 0x0100 ///< Midnight Channel specific: draw TV like overlay on HUD

View file

@ -3143,6 +3143,7 @@ tolinfo_t TYPEOFLEVEL[NUMTOLNAMES] = {
{"RACE",TOL_RACE},
{"BATTLE",TOL_BATTLE},
{"BOSS",TOL_BOSS},
{"SPECIAL",TOL_SPECIAL},
{"TV",TOL_TV},
{NULL, 0}
};

View file

@ -40,6 +40,7 @@
#include "k_collide.h"
#include "k_follower.h"
#include "k_objects.h"
#include "k_specialstage.h"
// SOME IMPORTANT VARIABLES DEFINED IN DOOMDEF.H:
// gamespeed is cc (0 for easy, 1 for normal, 2 for hard)
@ -60,7 +61,11 @@ void K_TimerInit(void)
UINT8 i;
UINT8 numPlayers = 0;//, numspec = 0;
if (!bossinfo.boss)
if (specialStage.active == true)
{
K_InitSpecialStage();
}
else if (bossinfo.boss == false)
{
for (i = 0; i < MAXPLAYERS; i++)
{
@ -418,6 +423,40 @@ static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS][2] =
{ 5, 1 } // Jawz x2
};
static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] =
{
//M N O P
{ 0, 0, 2, 3, 4, 0, 0, 0 }, // Sneaker
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Rocket Sneaker
{ 0, 0, 0, 0, 2, 5, 5, 7 }, // Invincibility
{ 2, 3, 1, 0, 0, 0, 0, 0 }, // Banana
{ 1, 2, 0, 0, 0, 0, 0, 0 }, // Eggman Monitor
{ 5, 5, 2, 2, 0, 0, 0, 0 }, // Orbinaut
{ 0, 4, 2, 1, 0, 0, 0, 0 }, // Jawz
{ 0, 3, 3, 1, 0, 0, 0, 0 }, // Mine
{ 3, 0, 0, 0, 0, 0, 0, 0 }, // Land Mine
{ 0, 0, 2, 2, 0, 0, 0, 0 }, // Ballhog
{ 0, 0, 0, 0, 0, 2, 4, 0 }, // Self-Propelled Bomb
{ 0, 0, 0, 0, 2, 5, 0, 0 }, // Grow
{ 0, 0, 0, 0, 0, 2, 4, 2 }, // Shrink
{ 1, 0, 0, 0, 0, 0, 0, 0 }, // Lightning Shield
{ 0, 1, 2, 1, 0, 0, 0, 0 }, // Bubble Shield
{ 0, 0, 0, 0, 0, 1, 3, 5 }, // Flame Shield
{ 3, 0, 0, 0, 0, 0, 0, 0 }, // Hyudoro
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Pogo Spring
{ 2, 1, 1, 0, 0, 0, 0, 0 }, // Super Ring
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Kitchen Sink
{ 3, 0, 0, 0, 0, 0, 0, 0 }, // Drop Target
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Garden Top
{ 0, 0, 0, 0, 0, 0, 0, 0 }, // Sneaker x2
{ 0, 0, 0, 0, 4, 4, 4, 0 }, // Sneaker x3
{ 0, 1, 1, 0, 0, 0, 0, 0 }, // Banana x3
{ 0, 0, 0, 1, 0, 0, 0, 0 }, // Banana x10
{ 0, 0, 1, 0, 0, 0, 0, 0 }, // Orbinaut x3
{ 0, 0, 0, 2, 0, 0, 0, 0 }, // Orbinaut x4
{ 0, 0, 1, 2, 1, 0, 0, 0 } // Jawz x2
};
#define DISTVAR (2048) // Magic number distance for use with item roulette tiers
#define SPBSTARTDIST (6*DISTVAR) // Distance when SPB can start appearing
#define SPBFORCEDIST (12*DISTVAR) // Distance when SPB is forced onto the next person who rolls an item

139
src/k_specialstage.c Normal file
View file

@ -0,0 +1,139 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2022 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_specialstage.c
/// \brief Special Stage game logic
#include "k_specialstage.h"
#include "doomdef.h"
#include "d_player.h"
#include "g_game.h"
#include "p_local.h"
#include "k_kart.h"
#include "s_sound.h"
#include "st_stuff.h"
#include "z_zone.h"
#include "k_waypoint.h"
struct specialStage specialStage;
/*--------------------------------------------------
void K_ResetSpecialStage(void)
See header file for description.
--------------------------------------------------*/
void K_ResetSpecialStage(void)
{
memset(&specialStage, 0, sizeof(struct specialStage));
}
/*--------------------------------------------------
void K_InitSpecialStage(void)
See header file for description.
--------------------------------------------------*/
void K_InitSpecialStage(void)
{
INT32 i;
specialStage.beamDist = UINT32_MAX; // TODO: make proper value
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *player = NULL;
if (playeringame[i] == false)
{
continue;
}
player = &players[i];
if (player->spectator == true)
{
continue;
}
if (player->mo == NULL || P_MobjWasRemoved(player->mo) == true)
{
continue;
}
// Rolling start? lol
P_InstaThrust(player->mo, player->mo->angle, K_GetKartSpeed(player, false, false));
}
}
/*--------------------------------------------------
static void K_MoveExitBeam(void)
Updates the exit beam.
--------------------------------------------------*/
static void K_MoveExitBeam(void)
{
UINT32 moveDist = 0;
INT32 i;
if (leveltime <= 2)
{
return;
}
moveDist = (8 * mapobjectscale) / FRACUNIT;
if (specialStage.beamDist <= moveDist)
{
specialStage.beamDist = 0;
// TODO: Fail Special Stage
}
else
{
specialStage.beamDist -= moveDist;
}
// Find players who are now outside of the level.
for (i = 0; i < MAXPLAYERS; i++)
{
player_t *player = NULL;
if (playeringame[i] == false)
{
continue;
}
player = &players[i];
if (player->spectator == true
|| player->exiting > 0
|| (player->pflags & PF_NOCONTEST))
{
continue;
}
if (player->distancetofinish > specialStage.beamDist)
{
P_DoTimeOver(player);
}
}
}
/*--------------------------------------------------
void K_TickSpecialStage(void)
See header file for description.
--------------------------------------------------*/
void K_TickSpecialStage(void)
{
if (specialStage.active == false)
{
return;
}
K_MoveExitBeam();
}

55
src/k_specialstage.h Normal file
View file

@ -0,0 +1,55 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
// Copyright (C) 2022 by Kart Krew
//
// This program is free software distributed under the
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_specialstage.h
/// \brief Special Stage game logic
#ifndef __K_SPECIALSTAGE__
#define __K_SPECIALSTAGE__
#include "doomdef.h"
#include "doomstat.h"
extern struct specialStage
{
boolean active; ///< If true, then we are in a special stage
boolean encore; ///< Copy of encore, just to make sure you can't cheat it with cvars
UINT32 beamDist; ///< Where the exit beam is.
mobj_t *capsule; ///< The Chaos Emerald capsule.
} specialStage;
/*--------------------------------------------------
void K_ResetSpecialStage(void);
Resets Special Stage information to a clean slate.
--------------------------------------------------*/
void K_ResetSpecialStage(void);
/*--------------------------------------------------
void K_InitSpecialStage(void);
Initializes Special Stage data on map load.
--------------------------------------------------*/
void K_InitSpecialStage(void);
/*--------------------------------------------------
void K_TickSpecialStage(void);
Updates Special Stage data each frame.
--------------------------------------------------*/
void K_TickSpecialStage(void);
#endif

View file

@ -96,8 +96,8 @@
#include "k_boss.h"
#include "k_terrain.h" // TRF_TRIPWIRE
#include "k_brightmap.h"
#include "k_terrain.h" // TRF_TRIPWIRE
#include "k_director.h" // K_InitDirector
#include "k_specialstage.h"
// Replay names have time
#if !defined (UNDER_CE)

View file

@ -36,6 +36,7 @@
#include "k_boss.h"
#include "k_waypoint.h"
#include "k_director.h"
#include "k_specialstage.h"
tic_t leveltime;
@ -695,6 +696,8 @@ void P_Ticker(boolean run)
K_BossInfoTicker();
K_TickSpecialStage();
if ((gametyperules & GTR_BUMPERS))
{
if (wantedcalcdelay && --wantedcalcdelay <= 0)