Merge branch 'deterministic-roulette' into 'master'

Deterministic roulette

See merge request KartKrew/Kart!808
This commit is contained in:
Sal 2022-12-16 00:50:45 +00:00
commit 03b37e2871
20 changed files with 1935 additions and 1256 deletions

View file

@ -125,3 +125,4 @@ k_director.c
k_follower.c k_follower.c
k_profiles.c k_profiles.c
k_specialstage.c k_specialstage.c
k_roulette.c

View file

@ -360,35 +360,36 @@ consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS] = { //Alam: Dummy for save
#endif #endif
// SRB2kart // SRB2kart
consvar_t cv_sneaker = CVAR_INIT ("sneaker", "On", CV_NETVAR, CV_OnOff, NULL); consvar_t cv_items[NUMKARTRESULTS-1] = {
consvar_t cv_rocketsneaker = CVAR_INIT ("rocketsneaker", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("sneaker", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_invincibility = CVAR_INIT ("invincibility", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("rocketsneaker", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_banana = CVAR_INIT ("banana", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("invincibility", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_eggmanmonitor = CVAR_INIT ("eggmanmonitor", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("banana", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("eggmanmonitor", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("orbinaut", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("jawz", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_landmine = CVAR_INIT ("landmine", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("mine", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("landmine", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("ballhog", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_shrink = CVAR_INIT ("shrink", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("grow", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_lightningshield = CVAR_INIT ("lightningshield", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("shrink", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_bubbleshield = CVAR_INIT ("bubbleshield", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("lightningshield", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_flameshield = CVAR_INIT ("flameshield", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("bubbleshield", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_hyudoro = CVAR_INIT ("hyudoro", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("flameshield", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_pogospring = CVAR_INIT ("pogospring", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("hyudoro", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_superring = CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("pogospring", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("superring", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_droptarget = CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("kitchensink", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_gardentop = CVAR_INIT ("gardentop", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("droptarget", "On", CV_NETVAR, CV_OnOff, NULL),
CVAR_INIT ("gardentop", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("dualsneaker", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("triplesneaker", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_triplebanana = CVAR_INIT ("triplebanana", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("triplebanana", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_tripleorbinaut = CVAR_INIT ("tripleorbinaut", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("tripleorbinaut", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_quadorbinaut = CVAR_INIT ("quadorbinaut", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("quadorbinaut", "On", CV_NETVAR, CV_OnOff, NULL),
consvar_t cv_dualjawz = CVAR_INIT ("dualjawz", "On", CV_NETVAR, CV_OnOff, NULL); CVAR_INIT ("dualjawz", "On", CV_NETVAR, CV_OnOff, NULL)
};
consvar_t cv_kartspeed = CVAR_INIT ("gamespeed", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartspeed_cons_t, KartSpeed_OnChange); consvar_t cv_kartspeed = CVAR_INIT ("gamespeed", "Auto", CV_NETVAR|CV_CALL|CV_NOINIT, kartspeed_cons_t, KartSpeed_OnChange);
static CV_PossibleValue_t kartbumpers_cons_t[] = {{1, "MIN"}, {12, "MAX"}, {0, NULL}}; static CV_PossibleValue_t kartbumpers_cons_t[] = {{1, "MIN"}, {12, "MAX"}, {0, NULL}};
@ -5659,7 +5660,7 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum)
K_StripItems(player); K_StripItems(player);
// Cancel roulette if rolling // Cancel roulette if rolling
player->itemroulette = 0; player->itemRoulette.active = false;
player->itemtype = item; player->itemtype = item;
player->itemamount = amt; player->itemamount = amt;

View file

@ -16,6 +16,7 @@
#define __D_NETCMD__ #define __D_NETCMD__
#include "command.h" #include "command.h"
#include "d_player.h"
// console vars // console vars
extern consvar_t cv_playername[MAXSPLITSCREENPLAYERS]; extern consvar_t cv_playername[MAXSPLITSCREENPLAYERS];
@ -72,37 +73,7 @@ extern consvar_t cv_pause;
extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_maxplayers, cv_respawntime; extern consvar_t cv_restrictskinchange, cv_allowteamchange, cv_maxplayers, cv_respawntime;
// SRB2kart items // SRB2kart items
extern consvar_t extern consvar_t cv_items[NUMKARTRESULTS-1];
cv_sneaker,
cv_rocketsneaker,
cv_invincibility,
cv_banana,
cv_eggmanmonitor,
cv_orbinaut,
cv_jawz,
cv_mine,
cv_landmine,
cv_ballhog,
cv_selfpropelledbomb,
cv_grow,
cv_shrink,
cv_lightningshield,
cv_bubbleshield,
cv_flameshield,
cv_hyudoro,
cv_pogospring,
cv_superring,
cv_kitchensink,
cv_droptarget,
cv_gardentop;
extern consvar_t
cv_dualsneaker,
cv_triplesneaker,
cv_triplebanana,
cv_tripleorbinaut,
cv_quadorbinaut,
cv_dualjawz;
extern consvar_t cv_kartspeed; extern consvar_t cv_kartspeed;
extern consvar_t cv_kartbumpers; extern consvar_t cv_kartbumpers;

View file

@ -225,6 +225,7 @@ typedef enum
// Item box // Item box
khud_itemblink, // Item flashing after roulette, serves as a mashing indicator khud_itemblink, // Item flashing after roulette, serves as a mashing indicator
khud_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items) khud_itemblinkmode, // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items)
khud_rouletteoffset,// Roulette stop height
// Rings // Rings
khud_ringframe, // Ring spin frame khud_ringframe, // Ring spin frame
@ -329,6 +330,41 @@ struct skybox_t {
mobj_t * centerpoint; mobj_t * centerpoint;
}; };
// player_t struct for item roulette variables
// Doing this the right way is causing problems.
// so FINE, it's a static length now.
#define ITEM_LIST_SIZE (NUMKARTRESULTS << 3)
struct itemroulette_t
{
boolean active;
#ifdef ITEM_LIST_SIZE
size_t itemListLen;
SINT8 itemList[ITEM_LIST_SIZE];
#else
size_t itemListCap;
size_t itemListLen;
SINT8 *itemList;
#endif
UINT8 useOdds;
UINT8 playing, exiting;
UINT32 dist, baseDist;
UINT32 firstDist, secondDist;
UINT32 secondToFirst;
size_t index;
UINT8 sound;
tic_t speed;
tic_t tics;
tic_t elapsed;
boolean eggman;
};
// ======================================================================== // ========================================================================
// PLAYER STRUCTURE // PLAYER STRUCTURE
// ======================================================================== // ========================================================================
@ -477,8 +513,7 @@ struct player_t
UINT8 tripwirePass; // see tripwirepass_t UINT8 tripwirePass; // see tripwirepass_t
UINT16 tripwireLeniency; // When reaching a state that lets you go thru tripwire, you get an extra second leniency after it ends to still go through it. UINT16 tripwireLeniency; // When reaching a state that lets you go thru tripwire, you get an extra second leniency after it ends to still go through it.
UINT16 itemroulette; // Used for the roulette when deciding what item to give you (was "pw_kartitem") itemroulette_t itemRoulette; // Item roulette data
UINT8 roulettetype; // Used for the roulette, for deciding type (0 = normal, 1 = better, 2 = eggman mark)
// Item held stuff // Item held stuff
SINT8 itemtype; // KITEM_ constant for item number SINT8 itemtype; // KITEM_ constant for item number

View file

@ -2260,11 +2260,10 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
SINT8 xtralife; SINT8 xtralife;
// SRB2kart // SRB2kart
itemroulette_t itemRoulette;
respawnvars_t respawn; respawnvars_t respawn;
INT32 itemtype; INT32 itemtype;
INT32 itemamount; INT32 itemamount;
INT32 itemroulette;
INT32 roulettetype;
INT32 growshrinktimer; INT32 growshrinktimer;
INT32 bumper; INT32 bumper;
boolean songcredit = false; boolean songcredit = false;
@ -2323,10 +2322,13 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE)); pflags = (players[player].pflags & (PF_WANTSTOJOIN|PF_KICKSTARTACCEL|PF_SHRINKME|PF_SHRINKACTIVE));
// SRB2kart // SRB2kart
memcpy(&itemRoulette, &players[player].itemRoulette, sizeof (itemRoulette));
memcpy(&respawn, &players[player].respawn, sizeof (respawn));
if (betweenmaps || leveltime < introtime) if (betweenmaps || leveltime < introtime)
{ {
itemroulette = 0; itemRoulette.active = false;
roulettetype = 0;
itemtype = 0; itemtype = 0;
itemamount = 0; itemamount = 0;
growshrinktimer = 0; growshrinktimer = 0;
@ -2348,9 +2350,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
} }
else else
{ {
itemroulette = (players[player].itemroulette > 0 ? 1 : 0);
roulettetype = players[player].roulettetype;
if (players[player].pflags & PF_ITEMOUT) if (players[player].pflags & PF_ITEMOUT)
{ {
itemtype = 0; itemtype = 0;
@ -2406,8 +2405,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
P_SetTarget(&players[player].follower, NULL); P_SetTarget(&players[player].follower, NULL);
} }
memcpy(&respawn, &players[player].respawn, sizeof (respawn));
p = &players[player]; p = &players[player];
memset(p, 0, sizeof (*p)); memset(p, 0, sizeof (*p));
@ -2453,8 +2450,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->xtralife = xtralife; p->xtralife = xtralife;
// SRB2kart // SRB2kart
p->itemroulette = itemroulette;
p->roulettetype = roulettetype;
p->itemtype = itemtype; p->itemtype = itemtype;
p->itemamount = itemamount; p->itemamount = itemamount;
p->growshrinktimer = growshrinktimer; p->growshrinktimer = growshrinktimer;
@ -2470,6 +2465,7 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
p->botvars.rubberband = FRACUNIT; p->botvars.rubberband = FRACUNIT;
p->botvars.controller = UINT16_MAX; p->botvars.controller = UINT16_MAX;
memcpy(&p->itemRoulette, &itemRoulette, sizeof (p->itemRoulette));
memcpy(&p->respawn, &respawn, sizeof (p->respawn)); memcpy(&p->respawn, &respawn, sizeof (p->respawn));
if (follower) if (follower)
@ -2481,7 +2477,6 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
//p->follower = NULL; // respawn a new one with you, it looks better. //p->follower = NULL; // respawn a new one with you, it looks better.
// ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore. // ^ Not necessary anyway since it will be respawned regardless considering it doesn't exist anymore.
p->playerstate = PST_LIVE; p->playerstate = PST_LIVE;
p->panim = PA_STILL; // standing animation p->panim = PA_STILL; // standing animation

View file

@ -26,6 +26,7 @@
#include "d_ticcmd.h" #include "d_ticcmd.h"
#include "m_random.h" #include "m_random.h"
#include "r_things.h" // numskins #include "r_things.h" // numskins
#include "k_roulette.h"
/*-------------------------------------------------- /*--------------------------------------------------
static inline boolean K_ItemButtonWasDown(player_t *player) static inline boolean K_ItemButtonWasDown(player_t *player)
@ -739,7 +740,7 @@ static void K_BotItemEggman(player_t *player, ticcmd_t *cmd)
tryLookback = true; tryLookback = true;
} }
if (stealth > 1 || player->itemroulette > 0) if (stealth > 1 || player->itemRoulette.active == true)
{ {
player->botvars.itemconfirm += player->botvars.difficulty * 4; player->botvars.itemconfirm += player->botvars.difficulty * 4;
throwdir = -1; throwdir = -1;
@ -1393,27 +1394,15 @@ static void K_BotItemRings(player_t *player, ticcmd_t *cmd)
--------------------------------------------------*/ --------------------------------------------------*/
static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd)
{ {
boolean mash = false;
if (K_ItemButtonWasDown(player) == true) if (K_ItemButtonWasDown(player) == true)
{ {
return; return;
} }
if (player->rings < 0 && cv_superring.value) // TODO: Would be nice to implement smarter behavior
{ // for selecting items.
// Uh oh, we need a loan!
// It'll be better in the long run for bots to lose an item set for 10 free rings.
mash = true;
}
// TODO: Mash based on how far behind you are, when items are cmd->buttons |= BT_ATTACK;
// almost garantueed to be in your favor.
if (mash == true)
{
cmd->buttons |= BT_ATTACK;
}
} }
/*-------------------------------------------------- /*--------------------------------------------------
@ -1441,7 +1430,7 @@ void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt)
return; return;
} }
if (player->itemroulette) if (player->itemRoulette.active == true)
{ {
// Mashing behaviors // Mashing behaviors
K_BotItemRouletteMash(player, cmd); K_BotItemRouletteMash(player, cmd);

View file

@ -12,6 +12,7 @@
#include "doomdef.h" // Sink snipe print #include "doomdef.h" // Sink snipe print
#include "g_game.h" // Sink snipe print #include "g_game.h" // Sink snipe print
#include "k_objects.h" #include "k_objects.h"
#include "k_roulette.h"
angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2) angle_t K_GetCollideAngle(mobj_t *t1, mobj_t *t2)
{ {
@ -158,10 +159,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
} }
else else
{ {
K_DropItems(t2->player); //K_StripItems(t2->player); K_StartEggmanRoulette(t2->player);
//K_StripOther(t2->player);
t2->player->itemroulette = 1;
t2->player->roulettetype = 2;
} }
if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD) if (t2->player->flamedash && t2->player->itemtype == KITEM_FLAMESHIELD)

View file

@ -36,6 +36,7 @@
#include "r_things.h" #include "r_things.h"
#include "r_fps.h" #include "r_fps.h"
#include "m_random.h" #include "m_random.h"
#include "k_roulette.h"
//{ Patch Definitions //{ Patch Definitions
static patch_t *kp_nodraw; static patch_t *kp_nodraw;
@ -1022,63 +1023,83 @@ static void K_drawKartItem(void)
// Why write V_DrawScaledPatch calls over and over when they're all the same? // Why write V_DrawScaledPatch calls over and over when they're all the same?
// Set to 'no item' just in case. // Set to 'no item' just in case.
const UINT8 offset = ((r_splitscreen > 1) ? 1 : 0); const UINT8 offset = ((r_splitscreen > 1) ? 1 : 0);
patch_t *localpatch = kp_nodraw; patch_t *localpatch[3] = { kp_nodraw };
patch_t *localbg = ((offset) ? kp_itembg[2] : kp_itembg[0]); patch_t *localbg = ((offset) ? kp_itembg[2] : kp_itembg[0]);
patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]); patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]);
INT32 fx = 0, fy = 0, fflags = 0; // final coords for hud and flags... INT32 fx = 0, fy = 0, fflags = 0; // final coords for hud and flags...
const INT32 numberdisplaymin = ((!offset && stplyr->itemtype == KITEM_ORBINAUT) ? 5 : 2); const INT32 numberdisplaymin = ((!offset && stplyr->itemtype == KITEM_ORBINAUT) ? 5 : 2);
INT32 itembar = 0; INT32 itembar = 0;
INT32 maxl = 0; // itembar's normal highest value INT32 maxl = 0; // itembar's normal highest value
const INT32 barlength = (r_splitscreen > 1 ? 12 : 26); const INT32 barlength = (offset ? 12 : 26);
UINT16 localcolor = SKINCOLOR_NONE; UINT16 localcolor[3] = { stplyr->skincolor };
SINT8 colormode = TC_RAINBOW; SINT8 colormode[3] = { TC_RAINBOW };
UINT8 *colmap = NULL;
boolean flipamount = false; // Used for 3P/4P splitscreen to flip item amount stuff boolean flipamount = false; // Used for 3P/4P splitscreen to flip item amount stuff
if (stplyr->itemroulette) fixed_t rouletteOffset = 0;
fixed_t rouletteSpace = ROULETTE_SPACING;
vector2_t rouletteCrop = {7, 7};
INT32 i;
if (stplyr->itemRoulette.itemListLen > 0)
{ {
const INT32 item = K_GetRollingRouletteItem(stplyr); // Init with item roulette stuff.
for (i = 0; i < 3; i++)
if (stplyr->skincolor)
localcolor = stplyr->skincolor;
switch (item)
{ {
case KITEM_INVINCIBILITY: const SINT8 indexOfs = i-1;
localpatch = localinv; const size_t index = (stplyr->itemRoulette.index + indexOfs) % stplyr->itemRoulette.itemListLen;
break;
case KITEM_ORBINAUT: const SINT8 result = stplyr->itemRoulette.itemList[index];
localpatch = kp_orbinaut[3 + offset]; const SINT8 item = K_ItemResultToType(result);
break; const UINT8 amt = K_ItemResultToAmount(result);
default: switch (item)
localpatch = K_GetCachedItemPatch(item, offset); {
case KITEM_INVINCIBILITY:
localpatch[i] = localinv;
break;
case KITEM_ORBINAUT:
localpatch[i] = kp_orbinaut[(offset ? 4 : min(amt-1, 3))];
break;
default:
localpatch[i] = K_GetCachedItemPatch(item, offset);
break;
}
} }
} }
if (stplyr->itemRoulette.active == true)
{
rouletteOffset = K_GetRouletteOffset(&stplyr->itemRoulette, rendertimefrac);
}
else else
{ {
// I'm doing this a little weird and drawing mostly in reverse order // I'm doing this a little weird and drawing mostly in reverse order
// The only actual reason is to make sneakers line up this way in the code below // The only actual reason is to make sneakers line up this way in the code below
// This shouldn't have any actual baring over how it functions // This shouldn't have any actual baring over how it functions
// Hyudoro is first, because we're drawing it on top of the player's current item // Hyudoro is first, because we're drawing it on top of the player's current item
localcolor[1] = SKINCOLOR_NONE;
rouletteOffset = stplyr->karthud[khud_rouletteoffset];
if (stplyr->stealingtimer < 0) if (stplyr->stealingtimer < 0)
{ {
if (leveltime & 2) if (leveltime & 2)
localpatch = kp_hyudoro[offset]; localpatch[1] = kp_hyudoro[offset];
else else
localpatch = kp_nodraw; localpatch[1] = kp_nodraw;
} }
else if ((stplyr->stealingtimer > 0) && (leveltime & 2)) else if ((stplyr->stealingtimer > 0) && (leveltime & 2))
{ {
localpatch = kp_hyudoro[offset]; localpatch[1] = kp_hyudoro[offset];
} }
else if (stplyr->eggmanexplode > 1) else if (stplyr->eggmanexplode > 1)
{ {
if (leveltime & 1) if (leveltime & 1)
localpatch = kp_eggman[offset]; localpatch[1] = kp_eggman[offset];
else else
localpatch = kp_nodraw; localpatch[1] = kp_nodraw;
} }
else if (stplyr->ballhogcharge > 0) else if (stplyr->ballhogcharge > 0)
{ {
@ -1086,9 +1107,9 @@ static void K_drawKartItem(void)
maxl = (((stplyr->itemamount-1) * BALLHOGINCREMENT) + 1); maxl = (((stplyr->itemamount-1) * BALLHOGINCREMENT) + 1);
if (leveltime & 1) if (leveltime & 1)
localpatch = kp_ballhog[offset]; localpatch[1] = kp_ballhog[offset];
else else
localpatch = kp_nodraw; localpatch[1] = kp_nodraw;
} }
else if (stplyr->rocketsneakertimer > 1) else if (stplyr->rocketsneakertimer > 1)
{ {
@ -1096,31 +1117,31 @@ static void K_drawKartItem(void)
maxl = (itemtime*3) - barlength; maxl = (itemtime*3) - barlength;
if (leveltime & 1) if (leveltime & 1)
localpatch = kp_rocketsneaker[offset]; localpatch[1] = kp_rocketsneaker[offset];
else else
localpatch = kp_nodraw; localpatch[1] = kp_nodraw;
} }
else if (stplyr->sadtimer > 0) else if (stplyr->sadtimer > 0)
{ {
if (leveltime & 2) if (leveltime & 2)
localpatch = kp_sadface[offset]; localpatch[1] = kp_sadface[offset];
else else
localpatch = kp_nodraw; localpatch[1] = kp_nodraw;
} }
else else
{ {
if (stplyr->itemamount <= 0) if (stplyr->itemamount <= 0)
return; return;
switch(stplyr->itemtype) switch (stplyr->itemtype)
{ {
case KITEM_INVINCIBILITY: case KITEM_INVINCIBILITY:
localpatch = localinv; localpatch[1] = localinv;
localbg = kp_itembg[offset+1]; localbg = kp_itembg[offset+1];
break; break;
case KITEM_ORBINAUT: case KITEM_ORBINAUT:
localpatch = kp_orbinaut[(offset ? 4 : min(stplyr->itemamount-1, 3))]; localpatch[1] = kp_orbinaut[(offset ? 4 : min(stplyr->itemamount-1, 3))];
break; break;
case KITEM_SPB: case KITEM_SPB:
@ -1131,44 +1152,45 @@ static void K_drawKartItem(void)
/*FALLTHRU*/ /*FALLTHRU*/
default: default:
localpatch = K_GetCachedItemPatch(stplyr->itemtype, offset); localpatch[1] = K_GetCachedItemPatch(stplyr->itemtype, offset);
if (localpatch == NULL) if (localpatch[1] == NULL)
localpatch = kp_nodraw; // diagnose underflows localpatch[1] = kp_nodraw; // diagnose underflows
break; break;
} }
if ((stplyr->pflags & PF_ITEMOUT) && !(leveltime & 1)) if ((stplyr->pflags & PF_ITEMOUT) && !(leveltime & 1))
localpatch = kp_nodraw; localpatch[1] = kp_nodraw;
} }
if (stplyr->karthud[khud_itemblink] && (leveltime & 1)) if (stplyr->karthud[khud_itemblink] && (leveltime & 1))
{ {
colormode = TC_BLINK; colormode[1] = TC_BLINK;
switch (stplyr->karthud[khud_itemblinkmode]) switch (stplyr->karthud[khud_itemblinkmode])
{ {
case 2: case 2:
localcolor = K_RainbowColor(leveltime); localcolor[1] = K_RainbowColor(leveltime);
break; break;
case 1: case 1:
localcolor = SKINCOLOR_RED; localcolor[1] = SKINCOLOR_RED;
break; break;
default: default:
localcolor = SKINCOLOR_WHITE; localcolor[1] = SKINCOLOR_WHITE;
break; break;
} }
} }
else
{
// Hide the other items.
// Effectively lets the other roulette items
// show flicker away after you select.
localpatch[0] = localpatch[2] = kp_nodraw;
}
} }
// pain and suffering defined below // pain and suffering defined below
if (r_splitscreen < 2) // don't change shit for THIS splitscreen. if (offset)
{
fx = ITEM_X;
fy = ITEM_Y;
fflags = V_SNAPTOTOP|V_SNAPTOLEFT|V_SPLITSCREEN;
}
else // now we're having a fun game.
{ {
if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3... if (stplyr == &players[displayplayers[0]] || stplyr == &players[displayplayers[2]]) // If we are P1 or P3...
{ {
@ -1183,35 +1205,91 @@ static void K_drawKartItem(void)
fflags = V_SNAPTORIGHT|V_SNAPTOTOP|V_SPLITSCREEN; fflags = V_SNAPTORIGHT|V_SNAPTOTOP|V_SPLITSCREEN;
flipamount = true; flipamount = true;
} }
}
if (localcolor != SKINCOLOR_NONE) rouletteSpace = ROULETTE_SPACING_SPLITSCREEN;
colmap = R_GetTranslationColormap(colormode, localcolor, GTC_CACHE); rouletteOffset = FixedMul(rouletteOffset, FixedDiv(ROULETTE_SPACING_SPLITSCREEN, ROULETTE_SPACING));
rouletteCrop.x = 16;
rouletteCrop.y = 15;
}
else
{
fx = ITEM_X;
fy = ITEM_Y;
fflags = V_SNAPTOTOP|V_SNAPTOLEFT|V_SPLITSCREEN;
}
V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg); V_DrawScaledPatch(fx, fy, V_HUDTRANS|V_SLIDEIN|fflags, localbg);
//V_SetClipRect((fx + 10) << FRACBITS, (fy + 10) << FRACBITS, 30 << FRACBITS, 30 << FRACBITS, V_HUDTRANS|V_SLIDEIN|fflags); // Need to draw these in a particular order, for sorting.
V_SetClipRect(
(fx + rouletteCrop.x) << FRACBITS, (fy + rouletteCrop.y) << FRACBITS,
rouletteSpace, rouletteSpace,
V_SLIDEIN|fflags
);
// Then, the numbers: V_DrawFixedPatch(
if (stplyr->itemamount >= numberdisplaymin && !stplyr->itemroulette) fx<<FRACBITS, (fy<<FRACBITS) + rouletteOffset + rouletteSpace,
FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags,
localpatch[0], (localcolor[0] ? R_GetTranslationColormap(colormode[0], localcolor[0], GTC_CACHE) : NULL)
);
V_DrawFixedPatch(
fx<<FRACBITS, (fy<<FRACBITS) + rouletteOffset - rouletteSpace,
FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags,
localpatch[2], (localcolor[2] ? R_GetTranslationColormap(colormode[2], localcolor[2], GTC_CACHE) : NULL)
);
if (stplyr->itemRoulette.active == true)
{ {
V_DrawScaledPatch(fx + (flipamount ? 48 : 0), fy, V_HUDTRANS|V_SLIDEIN|fflags|(flipamount ? V_FLIP : 0), kp_itemmulsticker[offset]); // flip this graphic for p2 and p4 in split and shift it. // Draw the item underneath the box.
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags, localpatch, colmap); V_DrawFixedPatch(
if (offset) fx<<FRACBITS, (fy<<FRACBITS) + rouletteOffset,
if (flipamount) // reminder that this is for 3/4p's right end of the screen. FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags,
V_DrawString(fx+2, fy+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SLIDEIN|fflags, va("x%d", stplyr->itemamount)); localpatch[1], (localcolor[1] ? R_GetTranslationColormap(colormode[1], localcolor[1], GTC_CACHE) : NULL)
else );
V_DrawString(fx+24, fy+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SLIDEIN|fflags, va("x%d", stplyr->itemamount)); V_ClearClipRect();
else
{
V_DrawScaledPatch(fy+28, fy+41, V_HUDTRANS|V_SLIDEIN|fflags, kp_itemx);
V_DrawKartString(fx+38, fy+36, V_HUDTRANS|V_SLIDEIN|fflags, va("%d", stplyr->itemamount));
}
} }
else else
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags, localpatch, colmap); {
// Draw the item above the box.
V_ClearClipRect();
//V_ClearClipRect(); if (stplyr->itemamount >= numberdisplaymin && stplyr->itemRoulette.active == false)
{
// Then, the numbers:
V_DrawScaledPatch(
fx + (flipamount ? 48 : 0), fy,
V_HUDTRANS|V_SLIDEIN|fflags|(flipamount ? V_FLIP : 0),
kp_itemmulsticker[offset]
); // flip this graphic for p2 and p4 in split and shift it.
V_DrawFixedPatch(
fx<<FRACBITS, (fy<<FRACBITS) + rouletteOffset,
FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags,
localpatch[1], (localcolor[1] ? R_GetTranslationColormap(colormode[1], localcolor[1], GTC_CACHE) : NULL)
);
if (offset)
{
if (flipamount) // reminder that this is for 3/4p's right end of the screen.
V_DrawString(fx+2, fy+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SLIDEIN|fflags, va("x%d", stplyr->itemamount));
else
V_DrawString(fx+24, fy+31, V_ALLOWLOWERCASE|V_HUDTRANS|V_SLIDEIN|fflags, va("x%d", stplyr->itemamount));
}
else
{
V_DrawScaledPatch(fy+28, fy+41, V_HUDTRANS|V_SLIDEIN|fflags, kp_itemx);
V_DrawKartString(fx+38, fy+36, V_HUDTRANS|V_SLIDEIN|fflags, va("%d", stplyr->itemamount));
}
}
else
{
V_DrawFixedPatch(
fx<<FRACBITS, (fy<<FRACBITS) + rouletteOffset,
FRACUNIT, V_HUDTRANS|V_SLIDEIN|fflags,
localpatch[1], (localcolor[1] ? R_GetTranslationColormap(colormode[1], localcolor[1], GTC_CACHE) : NULL)
);
}
}
// Extensible meter, currently only used for rocket sneaker... // Extensible meter, currently only used for rocket sneaker...
if (itembar) if (itembar)
@ -4434,7 +4512,7 @@ K_drawMiniPing (void)
static void K_drawDistributionDebugger(void) static void K_drawDistributionDebugger(void)
{ {
patch_t *items[NUMKARTRESULTS] = { patch_t *patches[NUMKARTRESULTS] = {
kp_sadface[1], kp_sadface[1],
kp_sneaker[1], kp_sneaker[1],
kp_rocketsneaker[1], kp_rocketsneaker[1],
@ -4466,86 +4544,67 @@ static void K_drawDistributionDebugger(void)
kp_orbinaut[4], kp_orbinaut[4],
kp_jawz[1] kp_jawz[1]
}; };
UINT8 useodds = 0;
UINT8 pingame = 0, bestbumper = 0; itemroulette_t rouletteData = {0};
UINT32 pdis = 0;
INT32 i; const fixed_t scale = (FRACUNIT >> 1);
INT32 x = -9, y = -9; const fixed_t space = 24 * scale;
const fixed_t pad = 9 * scale;
fixed_t x = -pad;
fixed_t y = -pad;
size_t i;
if (stplyr != &players[displayplayers[0]]) // only for p1 if (stplyr != &players[displayplayers[0]]) // only for p1
return;
if (K_ForcedSPB(stplyr) == true)
{ {
V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[KITEM_SPB]);
V_DrawThinString(x+11, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, "EX");
return; return;
} }
// The only code duplication from the Kart, just to avoid the actual item function from calculating pingame twice K_FillItemRouletteData(stplyr, &rouletteData);
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
pingame++;
if (players[i].bumpers > bestbumper)
bestbumper = players[i].bumpers;
}
// lovely double loop...... for (i = 0; i < rouletteData.itemListLen; i++)
for (i = 0; i < MAXPLAYERS; i++)
{ {
if (playeringame[i] && !players[i].spectator const kartitems_t item = rouletteData.itemList[i];
&& players[i].position == 1) UINT8 amount = 1;
if (y > (BASEVIDHEIGHT << FRACBITS) - space - pad)
{ {
// This player is first! Yay! x += space;
pdis = stplyr->distancetofinish - players[i].distancetofinish; y = -pad;
break;
} }
}
pdis = K_ScaleItemDistance(pdis, pingame); V_DrawFixedPatch(x, y, scale, V_SNAPTOTOP, patches[item], NULL);
if (stplyr->bot && stplyr->botvars.rival)
{
// Rival has better odds :)
pdis = (15 * pdis) / 14;
}
useodds = K_FindUseodds(stplyr, 0, pdis, bestbumper);
for (i = 1; i < NUMKARTRESULTS; i++)
{
INT32 itemodds = K_KartGetItemOdds(
useodds, i,
stplyr->distancetofinish,
0,
stplyr->bot, (stplyr->bot && stplyr->botvars.rival)
);
INT32 amount = 1;
if (itemodds <= 0)
continue;
V_DrawScaledPatch(x, y, V_SNAPTOTOP, items[i]);
V_DrawThinString(x+11, y+31, V_SNAPTOTOP, va("%d", itemodds));
// Display amount for multi-items // Display amount for multi-items
amount = K_ItemResultToAmount(i); amount = K_ItemResultToAmount(item);
if (amount > 1) if (amount > 1)
{ {
V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("x%d", amount)); V_DrawStringScaled(
x + (18 * scale),
y + (23 * scale),
scale, FRACUNIT, FRACUNIT,
V_ALLOWLOWERCASE|V_SNAPTOTOP,
NULL, HU_FONT,
va("x%d", amount)
);
} }
x += 32; y += space;
if (x >= 297)
{
x = -9;
y += 32;
}
} }
V_DrawString(0, 0, V_SNAPTOTOP, va("USEODDS %d", useodds)); V_DrawString((x >> FRACBITS) + 20, 2, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("useOdds[%u]", rouletteData.useOdds));
V_DrawString((x >> FRACBITS) + 20, 10, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("speed = %u", rouletteData.speed));
V_DrawString((x >> FRACBITS) + 20, 22, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("baseDist = %u", rouletteData.baseDist));
V_DrawString((x >> FRACBITS) + 20, 30, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("dist = %u", rouletteData.dist));
V_DrawString((x >> FRACBITS) + 20, 42, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("firstDist = %u", rouletteData.firstDist));
V_DrawString((x >> FRACBITS) + 20, 50, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("secondDist = %u", rouletteData.secondDist));
V_DrawString((x >> FRACBITS) + 20, 58, V_ALLOWLOWERCASE|V_SNAPTOTOP, va("secondToFirst = %u", rouletteData.secondToFirst));
#ifndef ITEM_LIST_SIZE
Z_Free(rouletteData.itemList);
#endif
} }
static void K_DrawWaypointDebugger(void) static void K_DrawWaypointDebugger(void)

File diff suppressed because it is too large Load diff

View file

@ -50,14 +50,6 @@ void K_ReduceVFX(mobj_t *mo, player_t *owner);
boolean K_IsPlayerLosing(player_t *player); boolean K_IsPlayerLosing(player_t *player);
fixed_t K_GetKartGameSpeedScalar(SINT8 value); fixed_t K_GetKartGameSpeedScalar(SINT8 value);
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
UINT8 K_FindUseodds(player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper);
fixed_t K_ItemOddsScale(UINT8 numPlayers);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, fixed_t mashed, boolean bot, boolean rival);
INT32 K_GetRollingRouletteItem(player_t *player);
boolean K_ForcedSPB(player_t *player);
INT32 K_GetShieldFromItem(INT32 item); INT32 K_GetShieldFromItem(INT32 item);
SINT8 K_ItemResultToType(SINT8 getitem); SINT8 K_ItemResultToType(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem); UINT8 K_ItemResultToAmount(SINT8 getitem);

View file

@ -3455,7 +3455,7 @@ void M_DrawItemToggles(void)
continue; continue;
} }
cv = KartItemCVars[currentMenu->menuitems[thisitem].mvar1-1]; cv = &cv_items[currentMenu->menuitems[thisitem].mvar1-1];
translucent = (cv->value ? 0 : V_TRANSLUCENT); translucent = (cv->value ? 0 : V_TRANSLUCENT);
drawnum = K_ItemResultToAmount(currentMenu->menuitems[thisitem].mvar1); drawnum = K_ItemResultToAmount(currentMenu->menuitems[thisitem].mvar1);
@ -3502,7 +3502,7 @@ void M_DrawItemToggles(void)
} }
else else
{ {
cv = KartItemCVars[currentMenu->menuitems[itemOn].mvar1-1]; cv = &cv_items[currentMenu->menuitems[itemOn].mvar1-1];
translucent = (cv->value ? 0 : V_TRANSLUCENT); translucent = (cv->value ? 0 : V_TRANSLUCENT);
drawnum = K_ItemResultToAmount(currentMenu->menuitems[itemOn].mvar1); drawnum = K_ItemResultToAmount(currentMenu->menuitems[itemOn].mvar1);

View file

@ -5632,12 +5632,12 @@ void M_HandleItemToggles(INT32 choice)
else else
if (currentMenu->menuitems[itemOn].mvar1 == 0) if (currentMenu->menuitems[itemOn].mvar1 == 0)
{ {
INT32 v = cv_sneaker.value; INT32 v = cv_items[0].value;
S_StartSound(NULL, sfx_s1b4); S_StartSound(NULL, sfx_s1b4);
for (i = 0; i < NUMKARTRESULTS-1; i++) for (i = 0; i < NUMKARTRESULTS-1; i++)
{ {
if (KartItemCVars[i]->value == v) if (cv_items[i].value == v)
CV_AddValue(KartItemCVars[i], 1); CV_AddValue(&cv_items[i], 1);
} }
} }
else else
@ -5650,7 +5650,7 @@ void M_HandleItemToggles(INT32 choice)
{ {
S_StartSound(NULL, sfx_s1ba); S_StartSound(NULL, sfx_s1ba);
} }
CV_AddValue(KartItemCVars[currentMenu->menuitems[itemOn].mvar1-1], 1); CV_AddValue(&cv_items[currentMenu->menuitems[itemOn].mvar1-1], 1);
} }
} }

1332
src/k_roulette.c Normal file

File diff suppressed because it is too large Load diff

169
src/k_roulette.h Normal file
View file

@ -0,0 +1,169 @@
// DR. ROBOTNIK'S RING RACERS
//-----------------------------------------------------------------------------
// Copyright (C) 2022 by Kart Krew
// Copyright (C) 2022 by Sally "TehRealSalt" Cochenour
//
// 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_roulette.h
/// \brief Item roulette code.
#ifndef __K_ROULETTE_H__
#define __K_ROULETTE_H__
#include "doomtype.h"
#include "d_player.h"
#define ROULETTE_SPACING (36 << FRACBITS)
#define ROULETTE_SPACING_SPLITSCREEN (16 << FRACBITS)
/*--------------------------------------------------
boolean K_ItemEnabled(kartitems_t item);
Determines whenever or not an item should
be enabled. Accounts for situations where
rules should not be able to be changed.
Input Arguments:-
item - The item to check.
Return:-
true if the item is enabled, otherwise false.
--------------------------------------------------*/
boolean K_ItemEnabled(kartitems_t item);
/*--------------------------------------------------
boolean K_ItemSingularity(kartitems_t item);
Determines whenever or not this item should
be using special cases to prevent more than
one existing at a time.
Input Arguments:-
item - The item to check.
Return:-
true to use the special rules, otherwise false.
--------------------------------------------------*/
boolean K_ItemSingularity(kartitems_t item);
/*--------------------------------------------------
INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item);
Gets the frequency an item should show up in
an item bracket, and adjusted for special
factors (such as Frantic Items).
Input Arguments:-
player - The player we intend to give the item to later.
Can be NULL for generic use.
roulette - The roulette data that we intend to
insert this item into.
pos - The item bracket we are in.
item - The item to give.
Return:-
The number of items we want to insert
into the roulette.
--------------------------------------------------*/
INT32 K_KartGetItemOdds(const player_t *player, itemroulette_t *const roulette, UINT8 pos, kartitems_t item);
/*--------------------------------------------------
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette);
Fills out the item roulette struct when it is
initially created. This function needs to be
HUD-safe for the item debugger, so the player
cannot be modified at this stage.
Input Arguments:-
player - The player this roulette data is for.
Can be NULL for generic use.
roulette - The roulette data struct to fill out.
Return:-
N/A
--------------------------------------------------*/
void K_FillItemRouletteData(const player_t *player, itemroulette_t *const roulette);
/*--------------------------------------------------
void K_StartItemRoulette(player_t *const player);
Starts the item roulette sequence for a player.
This stage can only be used by gameplay, thus
this handles gameplay modifications as well.
Input Arguments:-
player - The player to start the item roulette for.
Return:-
N/A
--------------------------------------------------*/
void K_StartItemRoulette(player_t *const player);
/*--------------------------------------------------
void K_StartEggmanRoulette(player_t *const player);
Starts the Eggman Mark roulette sequence for
a player. Looks identical to a regular item
roulette, but gives you the Eggman explosion
countdown instead when confirming it.
Input Arguments:-
player - The player to start the Eggman roulette for.
Return:-
N/A
--------------------------------------------------*/
void K_StartEggmanRoulette(player_t *const player);
/*--------------------------------------------------
fixed_t K_GetRouletteOffset(itemroulette_t *const roulette, fixed_t renderDelta);
Gets the Y offset, for use in the roulette HUD.
A separate function since it is used both by the
HUD itself, as well as when confirming an item.
Input Arguments:-
roulette - The roulette we are drawing for.
renderDelta - Fractional tic delta, when used for HUD.
Return:-
The Y offset when drawing the item.
--------------------------------------------------*/
fixed_t K_GetRouletteOffset(itemroulette_t *const roulette, fixed_t renderDelta);
/*--------------------------------------------------
void K_KartItemRoulette(player_t *const player, ticcmd_t *cmd);
Handles ticking a player's item roulette,
and player input for stopping it.
Input Arguments:-
player - The player to run the item roulette for.
cmd - The player's controls.
Return:-
N/A
--------------------------------------------------*/
void K_KartItemRoulette(player_t *const player, ticcmd_t *cmd);
#endif // __K_ROULETTE_H__

View file

@ -304,10 +304,10 @@ static int player_get(lua_State *L)
lua_pushinteger(L, plr->tripwirePass); lua_pushinteger(L, plr->tripwirePass);
else if (fastcmp(field,"tripwireLeniency")) else if (fastcmp(field,"tripwireLeniency"))
lua_pushinteger(L, plr->tripwireLeniency); lua_pushinteger(L, plr->tripwireLeniency);
/*
else if (fastcmp(field,"itemroulette")) else if (fastcmp(field,"itemroulette"))
lua_pushinteger(L, plr->itemroulette); lua_pushinteger(L, plr->itemroulette);
else if (fastcmp(field,"roulettetype")) */
lua_pushinteger(L, plr->roulettetype);
else if (fastcmp(field,"itemtype")) else if (fastcmp(field,"itemtype"))
lua_pushinteger(L, plr->itemtype); lua_pushinteger(L, plr->itemtype);
else if (fastcmp(field,"itemamount")) else if (fastcmp(field,"itemamount"))
@ -680,10 +680,10 @@ static int player_set(lua_State *L)
plr->tripwirePass = luaL_checkinteger(L, 3); plr->tripwirePass = luaL_checkinteger(L, 3);
else if (fastcmp(field,"tripwireLeniency")) else if (fastcmp(field,"tripwireLeniency"))
plr->tripwireLeniency = luaL_checkinteger(L, 3); plr->tripwireLeniency = luaL_checkinteger(L, 3);
/*
else if (fastcmp(field,"itemroulette")) else if (fastcmp(field,"itemroulette"))
plr->itemroulette = luaL_checkinteger(L, 3); plr->itemroulette = luaL_checkinteger(L, 3);
else if (fastcmp(field,"roulettetype")) */
plr->roulettetype = luaL_checkinteger(L, 3);
else if (fastcmp(field,"itemtype")) else if (fastcmp(field,"itemtype"))
plr->itemtype = luaL_checkinteger(L, 3); plr->itemtype = luaL_checkinteger(L, 3);
else if (fastcmp(field,"itemamount")) else if (fastcmp(field,"itemamount"))

View file

@ -34,6 +34,7 @@
#include "k_respawn.h" #include "k_respawn.h"
#include "k_collide.h" #include "k_collide.h"
#include "k_objects.h" #include "k_objects.h"
#include "k_roulette.h"
#ifdef HW3SOUND #ifdef HW3SOUND
#include "hardware/hw3sound.h" #include "hardware/hw3sound.h"
@ -13043,9 +13044,13 @@ void A_ItemPop(mobj_t *actor)
Obj_SpawnItemDebrisEffects(actor, actor->target); Obj_SpawnItemDebrisEffects(actor, actor->target);
if (locvar1 == 1) if (locvar1 == 1)
{
P_GivePlayerSpheres(actor->target->player, actor->extravalue1); P_GivePlayerSpheres(actor->target->player, actor->extravalue1);
}
else if (locvar1 == 0) else if (locvar1 == 0)
actor->target->player->itemroulette = 1; {
K_StartItemRoulette(actor->target->player);
}
// Here at mapload in battle? // Here at mapload in battle?
if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP)) if ((gametyperules & GTR_BUMPERS) && (actor->flags2 & MF2_BOSSNOTRAP))

View file

@ -38,6 +38,7 @@
#include "k_respawn.h" #include "k_respawn.h"
#include "p_spec.h" #include "p_spec.h"
#include "k_objects.h" #include "k_objects.h"
#include "k_roulette.h"
// CTF player names // CTF player names
#define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : "" #define CTFTEAMCODE(pl) pl->ctfteam ? (pl->ctfteam == 1 ? "\x85" : "\x84") : ""
@ -130,7 +131,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
return false; return false;
// Already have fake // Already have fake
if (player->roulettetype == 2 if (player->itemRoulette.eggman == true
|| player->eggmanexplode) || player->eggmanexplode)
return false; return false;
} }
@ -143,7 +144,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
return false; return false;
// Item slot already taken up // Item slot already taken up
if (player->itemroulette if (player->itemRoulette.active == true
|| (weapon != 3 && player->itemamount) || (weapon != 3 && player->itemamount)
|| (player->pflags & PF_ITEMOUT)) || (player->pflags & PF_ITEMOUT))
return false; return false;
@ -411,8 +412,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0)) if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumpers <= 0))
return; return;
player->itemroulette = 1; K_StartItemRoulette(player);
player->roulettetype = 1;
// Karma fireworks // Karma fireworks
for (i = 0; i < 5; i++) for (i = 0; i < 5; i++)
@ -1449,8 +1449,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
} }
player->karthud[khud_itemblink] = TICRATE; player->karthud[khud_itemblink] = TICRATE;
player->karthud[khud_itemblinkmode] = 0; player->karthud[khud_itemblinkmode] = 0;
player->itemroulette = 0; player->itemRoulette.active = false;
player->roulettetype = 0;
if (P_IsDisplayPlayer(player)) if (P_IsDisplayPlayer(player))
S_StartSound(NULL, sfx_itrolf); S_StartSound(NULL, sfx_itrolf);
} }

View file

@ -6128,7 +6128,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
break; break;
// see also K_drawKartItem in k_hud.c // see also K_drawKartItem in k_hud.c
case MT_PLAYERARROW: case MT_PLAYERARROW: // FIXME: Delete this object, attach to name tags instead.
if (mobj->target && mobj->target->health if (mobj->target && mobj->target->health
&& mobj->target->player && !mobj->target->player->spectator && mobj->target->player && !mobj->target->player->spectator
&& mobj->target->health && mobj->target->player->playerstate != PST_DEAD && mobj->target->health && mobj->target->player->playerstate != PST_DEAD
@ -6182,7 +6182,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
} }
// Do this in an easy way // Do this in an easy way
if (mobj->target->player->itemroulette) if (mobj->target->player->itemRoulette.active)
{ {
mobj->tracer->color = mobj->target->player->skincolor; mobj->tracer->color = mobj->target->player->skincolor;
mobj->tracer->colorized = true; mobj->tracer->colorized = true;
@ -6198,11 +6198,11 @@ static void P_MobjSceneryThink(mobj_t *mobj)
const INT32 numberdisplaymin = ((mobj->target->player->itemtype == KITEM_ORBINAUT) ? 5 : 2); const INT32 numberdisplaymin = ((mobj->target->player->itemtype == KITEM_ORBINAUT) ? 5 : 2);
// Set it to use the correct states for its condition // Set it to use the correct states for its condition
if (mobj->target->player->itemroulette) if (mobj->target->player->itemRoulette.active)
{ {
P_SetMobjState(mobj, S_PLAYERARROW_BOX); P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM; mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = K_GetRollingRouletteItem(mobj->target->player) | FF_FULLBRIGHT; mobj->tracer->frame = 1 | FF_FULLBRIGHT;
mobj->tracer->renderflags &= ~RF_DONTDRAW; mobj->tracer->renderflags &= ~RF_DONTDRAW;
} }
else if (mobj->target->player->stealingtimer < 0) else if (mobj->target->player->stealingtimer < 0)

View file

@ -96,7 +96,7 @@ static void P_NetArchivePlayers(void)
{ {
INT32 i, j; INT32 i, j;
UINT16 flags; UINT16 flags;
// size_t q; size_t q;
WRITEUINT32(save_p, ARCHIVEBLOCK_PLAYERS); WRITEUINT32(save_p, ARCHIVEBLOCK_PLAYERS);
@ -310,9 +310,6 @@ static void P_NetArchivePlayers(void)
WRITEUINT8(save_p, players[i].tripwirePass); WRITEUINT8(save_p, players[i].tripwirePass);
WRITEUINT16(save_p, players[i].tripwireLeniency); WRITEUINT16(save_p, players[i].tripwireLeniency);
WRITEUINT16(save_p, players[i].itemroulette);
WRITEUINT8(save_p, players[i].roulettetype);
WRITESINT8(save_p, players[i].itemtype); WRITESINT8(save_p, players[i].itemtype);
WRITEUINT8(save_p, players[i].itemamount); WRITEUINT8(save_p, players[i].itemamount);
WRITESINT8(save_p, players[i].throwdir); WRITESINT8(save_p, players[i].throwdir);
@ -410,6 +407,50 @@ static void P_NetArchivePlayers(void)
WRITEUINT32(save_p, players[i].botvars.itemconfirm); WRITEUINT32(save_p, players[i].botvars.itemconfirm);
WRITESINT8(save_p, players[i].botvars.turnconfirm); WRITESINT8(save_p, players[i].botvars.turnconfirm);
WRITEUINT32(save_p, players[i].botvars.spindashconfirm); WRITEUINT32(save_p, players[i].botvars.spindashconfirm);
// itemroulette_t
WRITEUINT8(save_p, players[i].itemRoulette.active);
#ifdef ITEM_LIST_SIZE
WRITEUINT32(save_p, players[i].itemRoulette.itemListLen);
for (q = 0; q < ITEM_LIST_SIZE; q++)
{
if (q >= players[i].itemRoulette.itemListLen)
{
WRITESINT8(save_p, KITEM_NONE);
}
else
{
WRITESINT8(save_p, players[i].itemRoulette.itemList[q]);
}
}
#else
if (players[i].itemRoulette.itemList == NULL)
{
WRITEUINT32(save_p, 0);
WRITEUINT32(save_p, 0);
}
else
{
WRITEUINT32(save_p, players[i].itemRoulette.itemListCap);
WRITEUINT32(save_p, players[i].itemRoulette.itemListLen);
for (q = 0; q < players[i].itemRoulette.itemListLen; q++)
{
WRITESINT8(save_p, players[i].itemRoulette.itemList[q]);
}
}
#endif
WRITEUINT8(save_p, players[i].itemRoulette.useOdds);
WRITEUINT32(save_p, players[i].itemRoulette.dist);
WRITEUINT32(save_p, players[i].itemRoulette.index);
WRITEUINT8(save_p, players[i].itemRoulette.sound);
WRITEUINT32(save_p, players[i].itemRoulette.speed);
WRITEUINT32(save_p, players[i].itemRoulette.tics);
WRITEUINT32(save_p, players[i].itemRoulette.elapsed);
WRITEUINT8(save_p, players[i].itemRoulette.eggman);
} }
} }
@ -417,6 +458,7 @@ static void P_NetUnArchivePlayers(void)
{ {
INT32 i, j; INT32 i, j;
UINT16 flags; UINT16 flags;
size_t q;
if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS) if (READUINT32(save_p) != ARCHIVEBLOCK_PLAYERS)
I_Error("Bad $$$.sav at archive block Players"); I_Error("Bad $$$.sav at archive block Players");
@ -612,9 +654,6 @@ static void P_NetUnArchivePlayers(void)
players[i].tripwirePass = READUINT8(save_p); players[i].tripwirePass = READUINT8(save_p);
players[i].tripwireLeniency = READUINT16(save_p); players[i].tripwireLeniency = READUINT16(save_p);
players[i].itemroulette = READUINT16(save_p);
players[i].roulettetype = READUINT8(save_p);
players[i].itemtype = READSINT8(save_p); players[i].itemtype = READSINT8(save_p);
players[i].itemamount = READUINT8(save_p); players[i].itemamount = READUINT8(save_p);
players[i].throwdir = READSINT8(save_p); players[i].throwdir = READSINT8(save_p);
@ -713,6 +752,61 @@ static void P_NetUnArchivePlayers(void)
players[i].botvars.turnconfirm = READSINT8(save_p); players[i].botvars.turnconfirm = READSINT8(save_p);
players[i].botvars.spindashconfirm = READUINT32(save_p); players[i].botvars.spindashconfirm = READUINT32(save_p);
// itemroulette_t
players[i].itemRoulette.active = (boolean)READUINT8(save_p);
#ifdef ITEM_LIST_SIZE
players[i].itemRoulette.itemListLen = (size_t)READUINT32(save_p);
for (q = 0; q < ITEM_LIST_SIZE; q++)
{
players[i].itemRoulette.itemList[q] = READSINT8(save_p);
}
#else
players[i].itemRoulette.itemListCap = (size_t)READUINT32(save_p);
players[i].itemRoulette.itemListLen = (size_t)READUINT32(save_p);
if (players[i].itemRoulette.itemListCap > 0)
{
if (players[i].itemRoulette.itemList == NULL)
{
players[i].itemRoulette.itemList = Z_Calloc(
sizeof(SINT8) * players[i].itemRoulette.itemListCap,
PU_STATIC,
&players[i].itemRoulette.itemList
);
}
else
{
players[i].itemRoulette.itemList = Z_Realloc(
players[i].itemRoulette.itemList,
sizeof(SINT8) * players[i].itemRoulette.itemListCap,
PU_STATIC,
&players[i].itemRoulette.itemList
);
}
if (players[i].itemRoulette.itemList == NULL)
{
I_Error("Not enough memory for item roulette list\n");
}
for (q = 0; q < players[i].itemRoulette.itemListLen; q++)
{
players[i].itemRoulette.itemList[q] = READSINT8(save_p);
}
}
#endif
players[i].itemRoulette.useOdds = READUINT8(save_p);
players[i].itemRoulette.dist = READUINT32(save_p);
players[i].itemRoulette.index = (size_t)READUINT32(save_p);
players[i].itemRoulette.sound = READUINT8(save_p);
players[i].itemRoulette.speed = (tic_t)READUINT32(save_p);
players[i].itemRoulette.tics = (tic_t)READUINT32(save_p);
players[i].itemRoulette.elapsed = (tic_t)READUINT32(save_p);
players[i].itemRoulette.eggman = (boolean)READUINT8(save_p);
//players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point //players[i].viewheight = P_GetPlayerViewHeight(players[i]); // scale cannot be factored in at this point
} }
} }

View file

@ -37,6 +37,7 @@ TYPEDEF (discordRequest_t);
TYPEDEF (respawnvars_t); TYPEDEF (respawnvars_t);
TYPEDEF (botvars_t); TYPEDEF (botvars_t);
TYPEDEF (skybox_t); TYPEDEF (skybox_t);
TYPEDEF (itemroulette_t);
TYPEDEF (player_t); TYPEDEF (player_t);
// d_clisrv.h // d_clisrv.h