Merge branch 'blankart-dev' into openalclassic

This commit is contained in:
NepDisk 2025-11-16 20:22:49 -05:00
commit d64c36bbf7
68 changed files with 4447 additions and 3691 deletions

View file

@ -87,10 +87,16 @@ option(SRB2_CONFIG_PROFILEMODE "Compile for profiling (GCC only)." OFF)
option(SRB2_CONFIG_TRACY "Compile with Tracy profiling enabled" OFF)
option(SRB2_CONFIG_ASAN "Compile with AddressSanitizer (libasan)." OFF)
option(SRB2_CONFIG_UBSAN "Compile with UndefinedBehaviorSanitizer (libubsan)." OFF)
option(SRB2_CONFIG_NOVERIFYIWADS "Compile with IWAD verification turned off." OFF)
set(SRB2_CONFIG_ASSET_DIRECTORY "" CACHE PATH "Path to directory that contains all asset files for the installer. If set, assets will be part of installation and cpack.")
option(SRB2_CONFIG_LTO "Enable link time optimizations, improves performance at the cost of longer link times." ON)
option(SRB2_CONFIG_TIDY "Enable clang tiny, checks compiled code for issues at the cost of longer compile times." OFF)
if(SRB2_CONFIG_NOVERIFYIWADS)
target_compile_definitions(SRB2SDL2 PRIVATE -DNOVERIFYIWADS)
endif()
if(SRB2_CONFIG_ENABLE_TESTS)
# https://github.com/catchorg/Catch2
CPMAddPackage(

64
extras/Items.md Normal file
View file

@ -0,0 +1,64 @@
# Items
BlanKart features its own collection of both new items and toggleable alternate takes on existing SRB2Kart v1 items. Most new items also appear in Ring Racers, but function significantly differently. This wiki page will cover all necessary information for these items.
## Alternate Items
Alternative items are secondary versions of existing SRB2Kart items that **reinterpret them in (mostly) unique ways**. As BlanKart develops further, more alternate items may appear.
To toggle on/off these alternate versions, you can do so with the following commands:
- ``altitem_invincibility`` (for Invincibility)
- ``altitem_shrink`` (for Shrink)
### Alt. Invincibility (Power: Occupies Slot)
Invincibility, in its normal form, is a power item that appears in the lower ranks, letting players cut through offroad and spin out opponents with prejudice. **Alt. Invincibility** works significantly different, trading its aggression for speed and optimized recovery.
To begin, Alt. Invincibility's item odds work as an inversion of the Self-Propelled Bomb's: Like how the S.P.B. only appears when first is extremely far ahead of the pack, Alt. Invincibility only reveals itself to players who are **extremely far behind the pack**. In some extreme cases, Alt. Invincibilty will override the race-start cooldown to power-up players already left in the dust.
Unlike the standard Invincibility, **you can't damage players with Alt. Invincibility**, instead bumping them like you would normally.
Its time limit (and power) is directly tied to your distance from the "cluster player", the player closest to the largest collection on the map of (losing) players. If you notice yourself falling super far behind on the minimap, you're likely to roll Alt. Invincibility. **The further the distance, the stronger your invincibility**, and the faster you'll go. Think of it like a non-autopilot version of Mario Kart's Bullet Bill, or Sonic Racing's Drill Wisp. _Make huge comebacks, and don't lose hope!_
Do note, though: Alt. Invincibility is designed as a "gap closer", and not traditional catchup. Once you pass the cluster player, the timer **decreases at an exponentially fast rate**; don't count on it to let you steal wins from the leader!
As you run out of power (your Invincibility drops below 5 seconds), **offroad will gradually begin to affect you again**. A warning signal usually sounds as your invincibility is about to run out, as well. Be careful when you see the rainbow color begin to fade!
If you want something else, or your invincibility is running low, hold ITEM to cancel your Invincibility; the same as you would Grow.
### Alt. Shrink (Power)
Shrink, in its normal form, functions much like Mario Kart's Lightning item. Most servers keep it off due to how frequent and disruptive it is to races.
**Alt. Shrink** forgoes that and turns it into an inversion of Grow! In its alternate form, Shrink appears as a **midpack power item**, shrinking you to a dimunitive size and increasing your acceleration and top speed, whilist **doubling the amount of nearly every item** you roll while under its effects. With some luck, you can roll impressive items and put pressure on first!
Be careful, though: running into anyone while in this state **will flip you over** and significantly cut your speed. Nimble dodging is required to make the most of this item!
## New Items
### Bubble Shield (Defense: Occupies Slot)
This is an item that appears around the upper-midpack of any race. This item's focus is **defense**.
When a player holds onto this shield, they can inflate the shield to protect themselves from items.
As the shield is used more, and takes damage from items and player bumps, it **cracks more and more until finally shattering**. Some item interactions, like a snipe from a Banana or Orbinaut, make it **shatter right away**!
Hold down ITEM to inflate the shield. Once you let go, it slowly deflates. As long as it's in an inflated state--be it inflating or deflating--you can **protect yourself from items** without spinning out.
While in an _uninflated_ state, however, the Bubble Shield can let you **nullify only one item hit**, shattering itself in the process.
If you hold ITEM for too long, you'll **overinflate the shield**, causing it to shatter, no matter the amount of health it still had. That's not all bad, though; you'll get a nice speed boost, and be temporarily invulnerable to hazards and items; proximity mines are no match!
The Bubble Shield also makes your bumps stronger: if you bump into another player, you won't rebound, but they will. If your shield isn't inflated while bumping other players, it'll **take severe damage** from the bump. Careful play is key with this shield!
### Flame Shield (Offense+Boost: Occupies Slot)
This is an item that appears around the lower-midpack of any race.
The Flame Shield can be used by holding down ITEM.
When in use, a **Flamometer** appears next to your character. The Flamometer shows how much you're charging the shield, and how much fuel you have left.
The fuel gauge is constantly depleting once the Flame Shield is first used. As you hold ITEM; you'll increase the Flame Shield's boost power, but it'll **use up whatever fuel you have** at the moment.
If you overcharge the Flame Shield, the Flamometer **catches fire**, and you'll gain no extra boost power, but can more easily cut through offroad. If you pace yourself, you can make this item last very long.
If you run into players while charging your Flame Shield, **you'll flip them over**, making them lose a significant amount of speed. You however, rush right through them.
### Land Mine (Drop Behind)
This is an item exclusive to first. Drop a discreet mine onto the track; anyone who runs into it **flips over and loses speed**.

View file

@ -132,7 +132,7 @@ k_bot.cpp
k_botitem.cpp
k_botsearch.cpp
k_cluster.cpp
k_odds.c
k_items.c
k_grandprix.c
k_boss.c
k_hud.c

View file

@ -188,9 +188,6 @@ extern CV_PossibleValue_t CV_Natural[];
#define KARTGP_MASTER 4 // Not a speed setting, gives hard speed with maxed out bots
#define KARTGP_NIGHTMARE 5 // Not a speed setting, gives expert speed with maxed out bots
extern CV_PossibleValue_t kartspeed_cons_t[], gpdifficulty_cons_t[];
// Invincibility types.
#define KARTINVIN_LEGACY 0
#define KARTINVIN_ALTERN 1
extern consvar_t cv_execversion;

View file

@ -94,7 +94,7 @@
#define ASSET_HASH_TEXTURES_KART 0xb4211b2f32b6a291
#define ASSET_HASH_CHARS_KART 0x1e68a3e01aa5c68b
#define ASSET_HASH_MAPS_KART 0x38558ed00da41ce9
#define ASSET_HASH_MAIN_PK3 0x26b5dde340bc9059
#define ASSET_HASH_MAIN_PK3 0x9dc33fb314952e03
#define ASSET_HASH_MAPPATCH_PK3 0xd4d4ce4a090d5473
#define ASSET_HASH_BONUSCHARS_KART 0x60e6f13d822a7461
#ifdef USE_PATCH_FILE
@ -1861,7 +1861,7 @@ void D_SRB2Main(void)
if (WADNAMECHECK(word))
{
if (!(pstartmap = wadnamemap))
I_Error("Bad '%s' level warp; pstartmap (%d) != wadnamemap (%d)).\n"
I_Error("Bad '%s' level warp; pstartmap (%d) != wadnamemap (%d).\n"
#if defined (_WIN32)
"Are you using MSDOS 8.3 filenames in Zone Builder?\n"
"\n"

View file

@ -68,6 +68,7 @@
#include "m_perfstats.h"
#include "g_party.h"
#include "k_specialstage.h"
#include "k_items.h"
#define CV_RESTRICT CV_NETVAR
@ -166,7 +167,6 @@ static void KartItemLitter_OnChange(void);
static void KartItemPush_OnChange(void);
static void KartAntiBump_OnChange(void);
static void KartItemBreaker_OnChange(void);
static void KartInvinType_OnChange(void);
static void KartBumpSpark_OnChange(void);
static void Schedule_OnChange(void);
@ -383,35 +383,6 @@ consvar_t cv_joyscale[MAXSPLITSCREENPLAYERS] = { //Alam: Dummy for save
#endif
// SRB2kart
consvar_t cv_sneaker = CVAR_INIT ("sneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_rocketsneaker = CVAR_INIT ("rocketsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_invincibility = CVAR_INIT ("invincibility", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_banana = CVAR_INIT ("banana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_eggmanmonitor = CVAR_INIT ("eggmanmonitor", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_orbinaut = CVAR_INIT ("orbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_jawz = CVAR_INIT ("jawz", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_mine = CVAR_INIT ("mine", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_ballhog = CVAR_INIT ("ballhog", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_selfpropelledbomb = CVAR_INIT ("selfpropelledbomb", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_grow = CVAR_INIT ("grow", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_shrink = CVAR_INIT ("shrink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_thundershield = CVAR_INIT ("thundershield", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_hyudoro = CVAR_INIT ("hyudoro", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_pogospring = CVAR_INIT ("pogospring", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_kitchensink = CVAR_INIT ("kitchensink", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_superring = CVAR_INIT ("superring", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_landmine = CVAR_INIT ("landmine", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_bubbleshield = CVAR_INIT ("bubbleshield", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_flameshield = CVAR_INIT ("flameshield", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_dualsneaker = CVAR_INIT ("dualsneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_triplesneaker = CVAR_INIT ("triplesneaker", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_triplebanana = CVAR_INIT ("triplebanana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_decabanana = CVAR_INIT ("decabanana", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_tripleorbinaut = CVAR_INIT ("tripleorbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_quadorbinaut = CVAR_INIT ("quadorbinaut", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_dualjawz = CVAR_INIT ("dualjawz", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
static CV_PossibleValue_t kartminimap_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
consvar_t cv_kartminimap = CVAR_INIT ("kartminimap", "4", CV_SAVE, kartminimap_cons_t, NULL);
consvar_t cv_kartcheck = CVAR_INIT ("kartcheck", "Yes", CV_SAVE, CV_YesNo, NULL);
@ -499,6 +470,10 @@ consvar_t cv_kartstacking_grow_speedboost = CVAR_INIT ("vanillaboost_grow_speedb
consvar_t cv_kartstacking_grow_accelboost = CVAR_INIT ("vanillaboost_grow_accelboost", "0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_grow_stackable = CVAR_INIT ("vanillaboost_grow_stackable", "Off", CV_NETVAR|CV_GUARD, CV_OnOff, NULL);
consvar_t cv_kartstacking_altshrink_speedboost = CVAR_INIT ("vanillaboost_altshrink_speedboost", "0.50", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_altshrink_accelboost = CVAR_INIT ("vanillaboost_altshrink_accelboost", "0.15", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_altshrink_stackable = CVAR_INIT ("vanillaboost_altshrink_stackable", "On", CV_NETVAR|CV_GUARD, CV_OnOff, NULL);
consvar_t cv_kartstacking_bubble_speedboost = CVAR_INIT ("vanillaboost_bubble_speedboost", "0.35", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_bubble_accelboost = CVAR_INIT ("vanillaboost_bubble_accelboost", "8.0", CV_NETVAR|CV_CHEAT|CV_FLOAT|CV_GUARD, CV_Unsigned, NULL);
consvar_t cv_kartstacking_bubble_stackable = CVAR_INIT ("vanillaboost_bubble_stackable", "Off", CV_NETVAR|CV_GUARD, CV_OnOff, NULL);
@ -588,7 +563,7 @@ consvar_t cv_kartantibump = CVAR_INIT ("kartantibump", "0", CV_NETVAR|CV_CALL|CV
// Odds distancing
#define MAXODDSDIST ((INT32_MAX / FRACUNIT) / 2)
static CV_PossibleValue_t distvar_cons_t[] = {{1, "MIN"}, {MAXODDSDIST, "MAX"}, {0, NULL}};
consvar_t cv_kartoddsdist = CVAR_INIT ("kartoddsdist", "987", CV_NETVAR|CV_CHEAT|CV_GUARD, distvar_cons_t, NULL);
consvar_t cv_kartoddsdist = CVAR_INIT ("kartoddsdist", "1480", CV_NETVAR|CV_CHEAT|CV_GUARD, distvar_cons_t, NULL);
consvar_t cv_kartlegacyoddsdist = CVAR_INIT ("kartlegacyoddsdist", "1050", CV_NETVAR|CV_CHEAT|CV_GUARD, distvar_cons_t, NULL);
// SPB distance
@ -597,9 +572,12 @@ consvar_t cv_kartspbdist = CVAR_INIT ("kartspbdist", "4432", CV_NETVAR|CV_CHEAT|
consvar_t cv_kartlegacyspbdist = CVAR_INIT ("kartlegacyspbdist", "2216", CV_NETVAR|CV_CHEAT|CV_GUARD, spbdist_cons_t, NULL);
#undef MAXODDSDIST
// Invincibility modifiers
static CV_PossibleValue_t invintype_cons_t[] = {{0, "Legacy"}, {1, "Alternative"}, {0, NULL}};
consvar_t cv_kartinvintype = CVAR_INIT ("kartinvintype", "Legacy", CV_NETVAR|CV_CALL, invintype_cons_t, KartInvinType_OnChange);
// SPB Rush toggle; toggles on/off the more aggressive "pressure" odds when an SPB is active
consvar_t cv_kartspbrush = CVAR_INIT ("kartspbrush", "On", CV_NETVAR, CV_OnOff, NULL);
// Time limit for Alt. Shrink
static CV_PossibleValue_t altshrinktime_cons_t[] = {{0, "MIN"}, {(INT16_MAX / TICRATE), "MAX"}, {0, NULL}};
consvar_t cv_kartaltshrinktime = CVAR_INIT ("kartaltshrinktime", "14", CV_NETVAR|CV_CHEAT|CV_GUARD, altshrinktime_cons_t, NULL);
// How far the player must be from the cluster to begin frequently rolling Invincibility.
static CV_PossibleValue_t invindist_cons_t[] = {{1, "MIN"}, {32000, "MAX"}, {0, NULL}};
@ -621,23 +599,7 @@ consvar_t cv_kartflame_offroadburn = CVAR_INIT ("kartflame_offroadburn", "Off",
static CV_PossibleValue_t kartairsquish_cons_t[] = {{1, "Squish"}, {2, "Flip-over"}, {0, "None"}, {0, NULL}};
consvar_t cv_kartairsquish = CVAR_INIT ("kartairsquish", "None", CV_NETVAR, kartairsquish_cons_t, NULL);
static CV_PossibleValue_t kartdebugitem_cons_t[] =
{
#define FOREACH( name, n ) { n, #name }
KART_ITEM_ITERATOR,
#undef FOREACH
{0}
};
consvar_t cv_kartdebugitem = CVAR_INIT ("kartdebugitem", "NONE", CV_NETVAR|CV_CHEAT, kartdebugitem_cons_t, NULL);
static CV_PossibleValue_t kartdebugamount_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}};
consvar_t cv_kartdebugamount = CVAR_INIT ("kartdebugamount", "1", CV_NETVAR|CV_CHEAT, kartdebugamount_cons_t, NULL);
consvar_t cv_kartdebugshrink = CVAR_INIT ("kartdebugshrink", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
#ifdef DEVELOP
#define VALUE "Yes"
#else
#define VALUE "No"
#endif
#undef VALUE
consvar_t cv_kartdebugdistribution = CVAR_INIT ("kartdebugdistribution", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_kartdebughuddrop = CVAR_INIT ("kartdebughuddrop", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
@ -1274,6 +1236,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_growmusic);
CV_RegisterVar(&cv_supermusic);
CV_RegisterVar(&cv_altshrinkmusic);
CV_RegisterVar(&cv_songcredits);
CV_RegisterVar(&cv_tutorialprompt);
@ -1340,6 +1303,7 @@ void D_RegisterClientCommands(void)
CV_RegisterVar(&cv_invincmusicfade);
CV_RegisterVar(&cv_growmusicfade);
CV_RegisterVar(&cv_altshrinkmusicfade);
CV_RegisterVar(&cv_resetspecialmusic);
@ -6220,16 +6184,15 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum)
}
case CHEAT_GIVEITEM: {
SINT8 item = READSINT8(*cp);
UINT8 item = READUINT8(*cp);
UINT8 amt = READUINT8(*cp);
item = max(item, KITEM_SAD);
item = min(item, NUMKARTITEMS - 1);
item = min(item, numkartitems - 1);
K_StripItems(player);
// Cancel roulette if rolling
player->itemroulette = KROULETTE_DISABLED;
player->itemroulette = 0;
player->itemtype = item;
player->itemamount = amt;
@ -6240,10 +6203,7 @@ static void Got_Cheat(UINT8 **cp, INT32 playernum)
}
else
{
// FIXME: we should have actual KITEM_ name array
const char *itemname = cv_kartdebugitem.PossibleValue[1 + item].strvalue;
CV_CheaterWarning(playernum, va("give item %s x%d", itemname, amt));
CV_CheaterWarning(playernum, va("give item %s x%d", item < 0 ? "SAD" : DEH_KartItemName(item), amt));
}
break;
}
@ -6528,8 +6488,6 @@ static void Command_KartGiveItem_f(void)
const char *name;
INT32 item;
const char * str;
int i;
ac = COM_Argc();
@ -6541,7 +6499,7 @@ static void Command_KartGiveItem_f(void)
}
else
{
item = NUMKARTITEMS;
item = numkartitems;
name = COM_Argv(1);
@ -6557,18 +6515,18 @@ static void Command_KartGiveItem_f(void)
CONS_Printf("\x83" "Autocomplete:\n");
/* then do very loose partial matching */
for (i = 0; ( str = kartdebugitem_cons_t[i].strvalue ); ++i)
for (i = 0; i < numkartitems; i++)
{
if (strcasestr(str, name) != NULL)
if (strcasestr(DEH_KartItemName(i), name) != NULL)
{
CONS_Printf("\x83\t%s\n", str);
item = kartdebugitem_cons_t[i].value;
CONS_Printf("\x83\t%s\n", DEH_KartItemName(i));
item = i;
}
}
}
}
if (item < NUMKARTITEMS)
if (item < numkartitems)
{
INT32 amt;
@ -7816,24 +7774,6 @@ static void KartItemBreaker_OnChange(void)
}
}
static void KartInvinType_OnChange(void)
{
if (K_CanChangeRules(false) == false)
{
return;
}
if (leveltime < starttime)
{
CONS_Printf(M_GetText("Invincibility type has been changed to \"%s\".\n"), cv_kartinvintype.string);
invintype = (UINT8)cv_kartinvintype.value;
}
else
{
CONS_Printf(M_GetText("Invincibility type will be changed to \"%s\" next round.\n"), cv_kartinvintype.string);
}
}
static void KartBumpSpark_OnChange(void)
{
if (K_CanChangeRules(false) == false)

View file

@ -72,38 +72,6 @@ extern consvar_t cv_spectatorreentry, cv_antigrief;
extern consvar_t cv_debugtraversemax;
#endif
// SRB2kart items
extern consvar_t
cv_sneaker,
cv_rocketsneaker,
cv_invincibility,
cv_banana,
cv_eggmanmonitor,
cv_orbinaut,
cv_jawz,
cv_mine,
cv_ballhog,
cv_selfpropelledbomb,
cv_grow,
cv_shrink,
cv_thundershield,
cv_hyudoro,
cv_pogospring,
cv_kitchensink,
cv_superring,
cv_landmine,
cv_bubbleshield,
cv_flameshield;
extern consvar_t
cv_dualsneaker,
cv_triplesneaker,
cv_triplebanana,
cv_decabanana,
cv_tripleorbinaut,
cv_quadorbinaut,
cv_dualjawz;
extern consvar_t cv_kartminimap;
extern consvar_t cv_kartcheck;
extern consvar_t cv_kartinvinsfx;
@ -160,6 +128,11 @@ extern consvar_t cv_kartstacking_bubble_speedboost;
extern consvar_t cv_kartstacking_bubble_accelboost;
extern consvar_t cv_kartstacking_bubble_stackable;
extern consvar_t cv_kartaltshrinktime;
extern consvar_t cv_kartstacking_altshrink_speedboost;
extern consvar_t cv_kartstacking_altshrink_accelboost;
extern consvar_t cv_kartstacking_altshrink_stackable;
extern consvar_t cv_kartstacking_start_speedboost;
extern consvar_t cv_kartstacking_start_accelboost;
extern consvar_t cv_kartstacking_start_stackable;
@ -202,7 +175,6 @@ extern consvar_t cv_kartexplosion_limitlifetime;
extern consvar_t cv_kartexplosion_limitlifetime_cap;
extern consvar_t cv_kartslipdash;
extern consvar_t cv_kartslopeboost;
extern consvar_t cv_kartinvintype;
extern consvar_t cv_kartinvindist;
extern consvar_t cv_kartinvindistmul;
extern consvar_t cv_kartinvin_maxtime;
@ -230,6 +202,8 @@ extern consvar_t cv_kartlegacyoddsdist;
extern consvar_t cv_kartspbdist;
extern consvar_t cv_kartlegacyspbdist;
extern consvar_t cv_kartspbrush;
extern consvar_t cv_encorevotes;
extern consvar_t cv_votetime;

View file

@ -58,14 +58,6 @@ typedef enum
PST_REBORN
} playerstate_t;
typedef enum
{
IF_USERINGS = 1, // Have to be not holding the item button to change from using rings to using items (or vice versa) - prevents weirdness
IF_ITEMOUT = 1<<1, // Are you holding an item out?
IF_EGGMANOUT = 1<<2, // Eggman mark held, separate from IF_ITEMOUT so it doesn't stop you from getting items
IF_HOLDREADY = 1<<3, // Hold button-style item is ready to activate
} itemflags_t;
//
// Player internal flags
//
@ -137,71 +129,13 @@ typedef enum
CR_ZOOMTUBE,
} carrytype_t; // carry
/*
To use: #define FOREACH( name, number )
Do with it whatever you want.
Run this macro, then #undef FOREACH afterward
*/
#define KART_ITEM_ITERATOR \
FOREACH (SAD, -1),\
FOREACH (NONE, 0),\
FOREACH (SNEAKER, 1),\
FOREACH (ROCKETSNEAKER, 2),\
FOREACH (INVINCIBILITY, 3),\
FOREACH (BANANA, 4),\
FOREACH (EGGMAN, 5),\
FOREACH (ORBINAUT, 6),\
FOREACH (JAWZ, 7),\
FOREACH (MINE, 8),\
FOREACH (BALLHOG, 9),\
FOREACH (SPB, 10),\
FOREACH (GROW, 11),\
FOREACH (SHRINK, 12),\
FOREACH (THUNDERSHIELD, 13),\
FOREACH (HYUDORO, 14),\
FOREACH (POGOSPRING, 15),\
FOREACH (KITCHENSINK, 16),\
FOREACH (SUPERRING, 17),\
FOREACH (LANDMINE, 18),\
FOREACH (BUBBLESHIELD, 19),\
FOREACH (FLAMESHIELD, 20)
typedef enum
{
#define FOREACH( name, n ) KITEM_ ## name = n
KART_ITEM_ITERATOR,
#undef FOREACH
NUMKARTITEMS,
// Additional roulette numbers, only used for K_KartGetItemResult
KRITEM_DUALSNEAKER = NUMKARTITEMS,
KRITEM_TRIPLESNEAKER,
KRITEM_TRIPLEBANANA,
KRITEM_TENFOLDBANANA,
KRITEM_TRIPLEORBINAUT,
KRITEM_QUADORBINAUT,
KRITEM_DUALJAWZ,
NUMKARTRESULTS
} kartitems_t;
typedef enum {
KROULETTE_DISABLED,
KROULETTE_ACTIVE,
} kartroulette_t;
typedef enum {
KROULETTETYPE_NORMAL,
KROULETTETYPE_KARMA,
KROULETTETYPE_EGGMAN,
} kartroulettetype_t;
typedef enum {
KITEMBLINKMODE_NORMAL,
KITEMBLINKMODE_MASHED,
KITEMBLINKMODE_KARMA,
} kartitemblinkmode_t;
IF_USERINGS = 1, // Have to be not holding the item button to change from using rings to using items (or vice versa) - prevents weirdness
IF_ITEMOUT = 1<<1, // Are you holding an item out?
IF_EGGMANOUT = 1<<2, // Eggman mark held, separate from IF_ITEMOUT so it doesn't stop you from getting items
IF_HOLDREADY = 1<<3, // Hold button-style item is ready to activate
} itemflags_t;
typedef enum
{
@ -660,20 +594,24 @@ struct player_t
UINT16 draftleeway; // Leniency timer before removing draft power
SINT8 lastdraft; // (-1 to 15) - Last player being drafted
UINT8 tripwireState; // see tripwirestate_t
UINT8 tripwirePass; // see tripwirepass_t
UINT8 tripwireState; // see tripwirestate_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.
UINT8 tripwireReboundDelay; // When failing Tripwire, brieftly lock out speed-based tripwire pass (anti-cheese)
UINT16 itemroulette; // Used for the roulette when deciding what item to give you (was "pw_kartitem")
UINT16 previtemroulette; // Used determining when to give rings after hitting item boxes
UINT16 itemroulette; // Used for the roulette when deciding what item to give you (was "pw_kartitem")
UINT16 previtemroulette; // Used determining when to give rings after hitting item boxes
UINT16 itemblink; // Item flashing after roulette, serves as a mashing indicator. Also prevents item from being stolen.
UINT16 itemblinkmode; // Type of flashing: 0 = white (normal), 1 = red (mashing), 2 = rainbow (enhanced items)
UINT8 roulettetype; // Used for the roulette, for deciding type (0 = normal, 1 = better, 2 = eggman mark)
UINT8 roulettetype; // Used for the roulette, for deciding type (0 = normal, 1 = better, 2 = eggman mark)
// Item held stuff
SINT8 itemtype; // KITEM_ constant for item number
UINT8 itemamount; // Amount of said item
UINT8 itemtype; // KITEM_ constant for item number
UINT8 itemamount; // Amount of said item
itemflags_t itemflags; // holds IF_flags (see itemstate_t)
tic_t itemusecooldown; // timer for which the player is locked out of using an item or mashing the item roulette (implementation of xItemLib setPlayerItemCooldown)
tic_t itemusecooldownmax; // most recent highest value for itemusecooldown, mainly used for HUD rendering currently
SINT8 throwdir; // Held dir of controls; 1 = forward, 0 = none, -1 = backward (was "player->heldDir")
UINT8 sadtimer; // How long you've been sad
@ -724,13 +662,14 @@ struct player_t
fixed_t slopeaccel; // Handle slopeboost accel
INT16 growshrinktimer; // > 0 = Big, < 0 = small
INT16 altshrinktimeshit; // (Alt. Shrink) How many times were you flipped over while shrunk?
INT16 growcancel; // Duration of grow canceling
INT16 squishedtimer; // Duration of being squished
UINT16 rocketsneakertimer; // Rocket Sneaker duration timer
UINT16 invincibilitytimer; // Invincibility timer
UINT16 maxinvincibilitytime; // (Alternate) Initial time for Invincibility, used for the item bar.
UINT16 invincibilitytimer; // Invincibility timer
UINT16 maxinvincibilitytime; // (Alternate) Initial time for Invincibility, used for the item bar.
UINT16 invincibilitybottleneck; // (Alternate) Prevents breakaways by gradienting towards a heavier decrement.
INT16 invincibilitycancel; // (Alternate) Duration of Invincibility canceling.
UINT8 invincibilitywarning; // (Alternate) "Timer warning" boolean to signal Alt. Invin. is running out.
@ -836,8 +775,6 @@ struct player_t
UINT8 typing_duration; // How long since resumed timer
UINT8 kickstartaccel;
UINT8 itemflags; // holds IF_flags (see itemstate_t)
fixed_t outrun; // Milky Way road effect
UINT8 outruntime; // Used to bypass the speed cap for fall off

View file

@ -439,6 +439,26 @@ static int ScanConstants(lua_State *L, boolean mathlib, const char *word)
}
return luaL_error(L, "karthud '%s' could not be found.\n", word);
}
else if (fastncmp("KITEM_",word,6)) {
p = word+6;
if (fastcmp(p, "LIGHTNINGSHIELD"))
{
lua_pushinteger(L, KITEM_THUNDERSHIELD);
return 1;
}
if (fastcmp(p, "SAD"))
{
lua_pushinteger(L, MAXKARTITEMS);
return 1;
}
i = DEH_FindKartItem(p);
if (i != MAXKARTITEMS)
{
CacheAndPushConstant(L, word, i);
return 1;
}
return luaL_error(L, "kartitem '%s' could not be found.\n", word);
}
else if (fastncmp("SKINCOLOR_",word,10)) {
p = word+10;
i = DEH_FindSkincolor(p);

View file

@ -27,6 +27,7 @@ extern "C" {
#include "fastcmp.h"
#include "lua_script.h"
#include "lua_libs.h"
#include "k_items.h"
#include "dehacked.h"
#include "deh_tables.h"

View file

@ -53,6 +53,7 @@
#include "filesrch.h" // refreshdirmenu
#include "k_follower.h"
#include "doomstat.h" // MAXMUSNAMES
#include "k_items.h"
// Loops through every constant and operation in word and performs its calculations, returning the final value.
fixed_t get_number(const char *word)
@ -3694,7 +3695,7 @@ void readfollower(MYFILE *f)
char *s;
char *word, *word2, dname[SKINNAMESIZE+1];
char *tmp;
char testname[SKINNAMESIZE];
char testname[SKINNAMESIZE+1];
boolean nameset;
INT32 fallbackstate = 0;
@ -4035,6 +4036,211 @@ void readweather(MYFILE *f, INT32 num)
Z_Free(s);
}
#define WARN(str, ...) deh_warning("KartItem %s: " str, strbuf_get(kartitemnames, item->info.nameofs), __VA_ARGS__)
#define WARN0(str) deh_warning("KartItem %s: " str, strbuf_get(kartitemnames, item->info.nameofs))
void readkartitem(MYFILE *f, kartitem_t *item)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word = s;
char *word2;
char *tmp;
INT32 i;
do if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
word2 = (tmp += 2);
strupr(word2);
if (fastcmp(word, "BIGPATCHES") || fastcmp(word, "SMALLPATCHES"))
{
kartitemgraphics_t *graphics = &item->graphics[word[0] == 'B' ? 0 : 1];
if (graphics == &item->graphics[0] && item->spritedef.numframes > 0)
{
Z_Free(item->spritedef.spriteframes);
memset(&item->spritedef, 0, sizeof(item->spritedef));
}
for (i = 0; i < graphics->numpatches; i++)
{
Z_Free(graphics->patchnames[i]);
Patch_Free(graphics->patches[i]);
graphics->patches[i] = NULL;
}
tmp = strtok(word2,",");
for (graphics->numpatches = 0; graphics->numpatches < MAXITEMPATCHES;)
{
graphics->patchnames[graphics->numpatches++] = Z_StrDup(tmp);
if ((tmp = strtok(NULL,",")) == NULL)
break;
}
}
else if (fastcmp(word, "FLAGS") || fastcmp(word, "FLAGSALT"))
{
item->flags[word[5] == 'A' ? 1 : 0] = get_number(word2);
}
else
WARN("unknown word '%s'", word);
}
while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
#undef WARN
#undef WARN0
#define WARN(str, ...) deh_warning("KartResult %s: " str, result->cvar->name, __VA_ARGS__)
#define WARN0(str) deh_warning("KartResult %s: " str, result->cvar->name)
void readkartresult(MYFILE *f, kartresult_t *result)
{
char *s = Z_Malloc(MAXLINELEN, PU_STATIC, NULL);
char *word = s;
char *word2;
char *tmp;
do if (myfgets(s, MAXLINELEN, f))
{
if (s[0] == '\n')
break;
// First remove trailing newline, if there is one
tmp = strchr(s, '\n');
if (tmp)
*tmp = '\0';
tmp = strchr(s, '#');
if (tmp)
*tmp = '\0';
if (s == tmp)
continue; // Skip comment lines, but don't break.
// Get the part before the " = "
tmp = strchr(s, '=');
if (tmp)
*(tmp-1) = '\0';
else
break;
strupr(word);
// Now get the part after
word2 = tmp + 2;
//strupr(word2);
if (fastcmp(word, "TYPE"))
{
if (result->isalt)
{
WARN0("can't set type for alternate result");
continue;
}
result->type = get_kartitem(word2);
}
else if (fastcmp(word, "AMOUNT"))
{
if (result->isalt)
{
WARN0("can't set amount for alternate result");
continue;
}
result->amount = get_number(word2);
}
else if (fastcmp(word, "ISALT"))
{
result->isalt = (boolean)(atoi(word2) || word2[0] == 'T' || word2[0] == 'Y');
}
else if (fastcmp(word, "FLAGS"))
{
result->flags = get_number(word2);
}
else if (fastncmp(word, "ODDS", 4))
{
UINT8 oddstable;
if (fastcmp(word+4, "RACE"))
oddstable = ODDS_RACE;
else if (fastcmp(word+4, "BATTLE"))
oddstable = ODDS_BATTLE;
else if (fastcmp(word+4, "SPECIAL"))
oddstable = ODDS_SPECIAL;
else
{
WARN("unknown word '%s'", word);
continue;
}
UINT8 *odds = result->odds[oddstable];
memset(odds, 0, sizeof(*odds)*MAXODDS);
tmp = strtok(word2,",");
for (UINT8 i = 0; i <= MAXODDS; i++)
{
if (i == oddstablemax[oddstable])
{
WARN("odds table %s is limited to %d odds", word+4, oddstablemax[oddstable]);
continue;
}
odds[i] = atoi(tmp);
if ((tmp = strtok(NULL,",")) == NULL)
break;
}
}
else if (fastncmp(word, "UNIQUEODDS", 10))
{
UINT8 oddstable;
if (fastcmp(word+10, "RACE"))
oddstable = ODDS_RACE;
else if (fastcmp(word+10, "BATTLE"))
oddstable = ODDS_BATTLE;
else if (fastcmp(word+10, "SPECIAL"))
oddstable = ODDS_SPECIAL;
else
{
WARN("unknown word '%s'", word);
continue;
}
result->unique_odds[oddstable] = get_useoddsfunc(word2);
}
else if (fastcmp(word, "COOLDOWNTIME"))
{
result->basecooldown = atoi(word2) * TICRATE;
}
else if (fastcmp(word, "DISPLAYNAME"))
{
result->displayname = Z_StrDup(word2);
}
else
WARN("unknown word '%s'", word);
}
while (!myfeof(f)); // finish when the line is empty
Z_Free(s);
}
#undef WARN
#undef WARN0
//
//
//
@ -4192,6 +4398,29 @@ preciptype_t get_precip(const char *word)
return PRECIP_NONE;
}
kartitemtype_e get_kartitem(const char *word)
{ // Returns the value of KITEM_ enumerations
kartitemtype_e i;
if (fastncmp("KITEM_",word,6))
word += 6; // take off the KITEM_
i = DEH_FindKartItem(word);
if (i == MAXKARTITEMS)
deh_warning("Couldn't find kartitem named 'KITEM_%s'", word);
return i;
}
useoddsfunc_f *get_useoddsfunc(const char *word)
{ // Returns the value of KO_ enumerations
size_t i;
if (fastncmp("KO_",word,3))
word += 3; // take off the KO_
for (i = 0; USEODDS_FUNCS[i].name; i++)
if (fasticmp(word, USEODDS_FUNCS[i].name))
return USEODDS_FUNCS[i].func;
deh_warning("Couldn't find odds function named 'KO_%s'",word);
return NULL;
}
/// \todo Make ANY of this completely over-the-top math craziness obey the order of operations.
static fixed_t op_mul(fixed_t a, fixed_t b) { return a*b; }
static fixed_t op_div(fixed_t a, fixed_t b) { return a/b; }

View file

@ -36,6 +36,7 @@
#include "fastcmp.h"
#include "lua_script.h" // Reluctantly included for LUA_EvalMath
#include "d_clisrv.h"
#include "k_items.h"
#ifdef HWRENDER
#include "hardware/hw_light.h"
@ -62,6 +63,8 @@ menudrawer_f *get_menudrawer(const char *word);
//INT16 get_gametype(const char *word);
//powertype_t get_power(const char *word);
skincolornum_t get_skincolor(const char *word);
kartitemtype_e get_kartitem(const char *word);
useoddsfunc_f *get_useoddsfunc(const char *word);
void readwipes(MYFILE *f);
void readmaincfg(MYFILE *f);
@ -91,6 +94,8 @@ void readcupheader(MYFILE *f, cupheader_t *cup);
void readfollower(MYFILE *f);
preciptype_t get_precip(const char *word);
void readweather(MYFILE *f, INT32 num);
void readkartitem(MYFILE *f, kartitem_t *item);
void readkartresult(MYFILE *f, kartresult_t *result);
#ifdef __cplusplus
} // extern "C"

View file

@ -40,6 +40,7 @@ strbuf_t *statenames;
strbuf_t *mobjnames;
strbuf_t *skincolornames;
strbuf_t *menunames;
strbuf_t *kartitemnames;
UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
const char *DEH_MobjtypeName(mobjtype_t i)
@ -62,6 +63,11 @@ const char *DEH_MenutypeName(menutype_t i)
return strbuf_get(menunames, menudefs[i].info.nameofs);
}
const char *DEH_KartItemName(kartitemtype_e i)
{
return strbuf_get(kartitemnames, kartitems[i].info.nameofs);
}
mobjtype_t DEH_FindMobjtype(const char *word)
{
mobjtype_t i;
@ -114,6 +120,19 @@ menutype_t DEH_FindMenutype(const char *word)
return MAXMENUTYPES;
}
kartitemtype_e DEH_FindKartItem(const char *word)
{
kartitemtype_e i;
UINT32 hash = HASH32(word, strlen(word));
for (i = 0; i < numkartitems; i++) {
if (hash != kartitems[i].info.namehash)
continue;
if (fastcmp(word, DEH_KartItemName(i)))
return i;
}
return MAXKARTITEMS;
}
struct flickytypes_s FLICKYTYPES[] = {
{"BLUEBIRD", MT_FLICKY_01}, // Flicky (Flicky)
{"RABBIT", MT_FLICKY_02}, // Pocky (1)
@ -796,6 +815,7 @@ struct menu_routine_s const MENU_ROUTINES[] = {
{ "RESETCONTROLS", &MR_ResetControls },
{ "CHANGECONTROL", &MR_ChangeControl },
{ "ASSIGNJOYSTICK", &MR_AssignJoystick },
{ "SETUPMONITORTOGGLES", &MR_SetupMonitorToggles },
{ "HANDLEMONITORTOGGLES", &MR_HandleMonitorToggles },
{ "RESTARTAUDIO", &MR_RestartAudio },
{ "ENTERVIEWSERVER", &MR_EnterViewServer },
@ -837,6 +857,12 @@ struct menu_drawer_s const MENU_DRAWERS[] = {
{ NULL, NULL }
};
struct odds_func_s const USEODDS_FUNCS[] = {
{ "ALTINVINODDS", &KO_AltInvinOdds },
{ "SPBRACEODDS", &KO_SPBRaceOdds },
{ NULL, NULL }
};
struct int_const_s const INT_CONST[] = {
// If a mod removes some variables here,
// please leave the names in-tact and just set
@ -1512,21 +1538,6 @@ struct int_const_s const INT_CONST[] = {
{"BASEVIDWIDTH", BASEVIDWIDTH},
{"BASEVIDHEIGHT", BASEVIDHEIGHT},
// SRB2Kart
// kartitems_t
#define FOREACH( name, n ) { TOSTR (KITEM_ ## name), KITEM_ ## name }
KART_ITEM_ITERATOR, // Actual items (can be set for k_itemtype)
#undef FOREACH
{"NUMKARTITEMS",NUMKARTITEMS},
{"KRITEM_DUALSNEAKER",KRITEM_DUALSNEAKER}, // Additional roulette IDs (not usable for much in Lua besides K_GetItemPatch)
{"KRITEM_TRIPLESNEAKER",KRITEM_TRIPLESNEAKER},
{"KRITEM_TRIPLEBANANA",KRITEM_TRIPLEBANANA},
{"KRITEM_TENFOLDBANANA",KRITEM_TENFOLDBANANA},
{"KRITEM_TRIPLEORBINAUT",KRITEM_TRIPLEORBINAUT},
{"KRITEM_QUADORBINAUT",KRITEM_QUADORBINAUT},
{"KRITEM_DUALJAWZ",KRITEM_DUALJAWZ},
{"NUMKARTRESULTS",NUMKARTRESULTS},
// kartshields_t
{"KSHIELD_NONE",KSHIELD_NONE},
{"KSHIELD_THUNDER",KSHIELD_THUNDER},
@ -1535,22 +1546,34 @@ struct int_const_s const INT_CONST[] = {
{"KSHIELD_FLAME",KSHIELD_FLAME},
{"NUMKARTSHIELDS",NUMKARTSHIELDS},
// kartitems_t
{"KITEM_LIGHTNINGSHIELD",KITEM_THUNDERSHIELD},
// kartroulette_t
{"KROULETTE_DISABLED",KROULETTE_DISABLED},
{"KROULETTE_ACTIVE",KROULETTE_ACTIVE},
// kartroulettetype_t
// kartroulettetype_e
{"KROULETTETYPE_NORMAL",KROULETTETYPE_NORMAL},
{"KROULETTETYPE_KARMA",KROULETTETYPE_KARMA},
{"KROULETTETYPE_EGGMAN",KROULETTETYPE_EGGMAN},
// kartitemblinkmode_t
{"KITEMBLINKMODE_NORMAL",KITEMBLINKMODE_NORMAL},
{"KITEMBLINKMODE_MASHED",KITEMBLINKMODE_MASHED},
{"KITEMBLINKMODE_KARMA",KITEMBLINKMODE_KARMA},
// kartitemblink_e
{"KITEMBLINK_NORMAL",KITEMBLINK_NORMAL},
{"KITEMBLINK_MASHED",KITEMBLINK_MASHED},
{"KITEMBLINK_KARMA",KITEMBLINK_KARMA},
{"KITEMBLINK_DEBUG",KITEMBLINK_DEBUG},
// kartitemflags_e
{"KIF_UNIQUESLOT",KIF_UNIQUESLOT},
{"KIF_UNIQUEDROP",KIF_UNIQUEDROP},
{"KIF_UNIQUE",KIF_UNIQUE},
{"KIF_ANIMATED",KIF_ANIMATED},
{"KIF_DARKBG",KIF_DARKBG},
{"KIF_COLPATCH2PLAYER",KIF_COLPATCH2PLAYER},
{"KIF_HIDEFROMROULETTE",KIF_HIDEFROMROULETTE},
// kartresultflags_e
{"KRF_INDIRECTITEM",KRF_INDIRECTITEM},
{"KRF_POWERITEM",KRF_POWERITEM},
{"KRF_COOLDOWNONSTART",KRF_COOLDOWNONSTART},
{"KRF_NOTNEAREND",KRF_NOTNEAREND},
{"KRF_NOTFORBOTTOM",KRF_NOTFORBOTTOM},
{"KRF_RUNNERAUGMENT",KRF_RUNNERAUGMENT},
{"KRF_HIDEFROMSPB",KRF_HIDEFROMSPB},
// kartspinoutflags_t
{"KSPIN_THRUST",KSPIN_THRUST},
@ -1684,10 +1707,6 @@ struct int_const_s const INT_CONST[] = {
{"FACE_MINIMAP", FACE_MINIMAP},
{"NUMFACES", NUMFACES},
// invintype
{"KARTINVIN_LEGACY", KARTINVIN_LEGACY},
{"KARTINVIN_ALTERN", KARTINVIN_ALTERN},
// k_waypoint.h values
{"DEFAULT_WAYPOINT_RADIUS",DEFAULT_WAYPOINT_RADIUS},

View file

@ -19,6 +19,7 @@
#include "lua_script.h"
#include "strbuf.h"
#include "m_menu.h" // menutype_t
#include "k_items.h"
#ifdef __cplusplus
extern "C" {
@ -30,17 +31,20 @@ extern strbuf_t *statenames;
extern strbuf_t *mobjnames;
extern strbuf_t *skincolornames;
extern strbuf_t *menunames;
extern strbuf_t *kartitemnames;
extern UINT8 used_spr[(NUMSPRITEFREESLOTS / 8) + 1]; // Bitwise flag for sprite freeslot in use! I would use ceil() here if I could, but it only saves 1 byte of memory anyway.
const char *DEH_MobjtypeName(mobjtype_t i);
const char *DEH_StateName(statenum_t i);
const char *DEH_SkincolorName(skincolornum_t i);
const char *DEH_MenutypeName(menutype_t i);
const char *DEH_KartItemName(kartitemtype_e i);
mobjtype_t DEH_FindMobjtype(const char *word);
statenum_t DEH_FindState(const char *word);
skincolornum_t DEH_FindSkincolor(const char *word);
menutype_t DEH_FindMenutype(const char *word);
kartitemtype_e DEH_FindKartItem(const char *word);
struct flickytypes_s {
const char *name;
@ -67,6 +71,11 @@ struct menu_drawer_s {
menudrawer_f *drawer;
};
struct odds_func_s {
const char *name;
useoddsfunc_f *func;
};
struct int_const_s {
const char *n;
// has to be able to hold both fixed_t and angle_t, so drastic measure!!
@ -97,6 +106,7 @@ extern const char *const KARTHUD_LIST[];
extern const char *const HUDITEMS_LIST[];
extern struct menu_routine_s const MENU_ROUTINES[];
extern struct menu_drawer_s const MENU_DRAWERS[];
extern struct odds_func_s const USEODDS_FUNCS[];
extern struct int_const_s const INT_CONST[];

View file

@ -376,6 +376,22 @@ INT32 DEH_ReadFreeslot(const char *type, const char *word, INT32 *out)
*out = nummenutypes++;
return 0;
}
else if (fastcmp(type, "KITEM"))
{
*out = DEH_FindKartItem(word);
if (*out != MAXKARTITEMS)
return 0; // already allocated
if (numkartitems == MAXKARTITEMS) {
CONS_Alert(CONS_WARNING, "Ran out of free kartitem slots!\n");
return -1;
}
CONS_Printf("Kartitem KITEM_%s allocated.\n",word);
DEH_Link(word, &kartitems[numkartitems].info, &kartitemnames);
K_RegisterItem(numkartitems);
*out = numkartitems++;
return 0;
}
return -2;
}
@ -750,6 +766,27 @@ static void DEH_LoadDehackedFile(MYFILE *f, boolean mainfile)
ignorelines(f);
}
}
else if (fastcmp(word, "KARTITEM"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number
i = get_kartitem(word2); // find a kartitem by name
if (i >= (mainfile ? 0 : 1) && i < numkartitems)
readkartitem(f, &kartitems[i]);
else
{
// zero-based, but let's start at 1
deh_warning("KartItem number %d out of range (1 - %d)", i, numkartitems-1);
ignorelines(f);
}
}
else if (fastncmp(word, "KARTRESULT", 10))
{
boolean alternate = fastcmp(word, "KARTRESULTALT");
kartresult_t *result = K_GetKartResultAlt(word2, alternate);
if (result == NULL)
result = K_RegisterResult(word2, alternate);
readkartresult(f, result);
}
else if (fastcmp(word, "WEATHER") || fastcmp(word, "PRECIP") || fastcmp(word, "PRECIPITATION"))
{
if (i == 0 && word2[0] != '0') // If word2 isn't a number

View file

@ -665,7 +665,6 @@ extern INT32 cheats;
// SRB2kart
extern UINT8 numlaps;
extern UINT8 gamespeed;
extern UINT8 invintype;
extern boolean franticitems;
extern boolean encoremode, prevencoremode;
extern boolean comeback;
@ -673,8 +672,6 @@ extern boolean comeback;
extern SINT8 mostwanted;
extern SINT8 battlewanted[4];
extern tic_t wantedcalcdelay;
extern tic_t indirectitemcooldown;
//extern tic_t hyubgone;
extern tic_t mapreset;
extern boolean thwompsactive;
extern UINT8 lastLowestLap;

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Vivian "toastergrl" Grannell.
// Copyright (C) 2025 by Kart Krew.
// Copyright (C) 2025 by "Anonimus".
// Copyright (C) 2025 by "yama".
// Copyright (C) 2025 Blankart Team.
//
// This program is free software distributed under the

View file

@ -2,7 +2,7 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2025 by Vivian "toastergrl" Grannell.
// Copyright (C) 2025 by Kart Krew.
// Copyright (C) 2025 by "Anonimus".
// Copyright (C) 2025 by "yama".
// Copyright (C) 2025 Blankart Team.
//
// This program is free software distributed under the

View file

@ -890,7 +890,7 @@ const char *blancredits[] = {
"\"GenericHeroGuy\"",
"\"Alug\"",
"\"Indev\"",
"\"Anonimus\" aka \"yama\"",
"\"yama\"",
"\"minenice\"",
"",
"\1Support Programming",
@ -899,7 +899,7 @@ const char *blancredits[] = {
"",
"\1Item Programming",
"\"NepDisk\"",
"\"Anonimus\" aka \"yama\"",
"\"yama\"",
"",
"\1External Programming",
"\"Hanicef\"",
@ -922,7 +922,7 @@ const char *blancredits[] = {
"",
"\1Item Design",
"\"NepDisk\"",
"\"Anonimus\" aka \"yama\"",
"\"yama\"",
"\"GenericHeroGuy\"",
"",
"\1Design Support",
@ -937,7 +937,7 @@ const char *blancredits[] = {
"\"Jin\"",
"\"NepDisk\"",
"\"Mayo\"",
"\"Anonimus\" aka \"yama\"",
"\"yama\"",
"",
"\1New HUD Art",
"\"Spee\"",
@ -966,7 +966,7 @@ const char *blancredits[] = {
"\1Super Special SIGSEGV Search and Smash Squad",
"\"NepDisk\"",
"\"GenericHeroGuy\"",
"\"Anonimus\" aka \"yama\"",
"\"yama\"",
"\"MotoBugger\"",
"\"Rim Jobless\"",
"\"Toad The Fungus\"",
@ -982,7 +982,7 @@ const char *blancredits[] = {
"\"JonUD\"",
"\"MotoBugger\"",
"\"Toad The Fungus\"",
"\"Anonimus\" aka \"yama\"",
"\"yama\"",
"\"luna\"",
"\"swift\"",
"\"Rim Jobless\"",

View file

@ -61,7 +61,7 @@
#include "k_boss.h"
#include "k_specialstage.h"
#include "k_bot.h"
#include "k_odds.h"
#include "k_items.h"
#include "doomstat.h"
#include "acs/interface.h"
#include "k_director.h"
@ -295,7 +295,6 @@ INT32 cheats; //for multiplayer cheat commands
// Cvars that we don't want changed mid-game
UINT8 numlaps; // Removed from Cvar hell
UINT8 gamespeed; // Game's current speed (or difficulty, or cc, or etc); 0 for easy, 1 for normal, 2 for hard
UINT8 invintype; // How Invincibility functions. 0 for Legacy/Vanilla, 1 for Alternative.
boolean encoremode = false; // Encore Mode currently enabled?
boolean prevencoremode;
boolean franticitems; // Frantic items currently enabled?
@ -310,8 +309,6 @@ SINT8 pickedvote; // What vote the host rolls
SINT8 battlewanted[4]; // WANTED players in battle, worth x2 points
SINT8 mostwanted; // The "most wanted" (first in line) player.
tic_t wantedcalcdelay; // Time before it recalculates WANTED
tic_t indirectitemcooldown; // Cooldown before any more Shrink, SPB, or any other item that works indirectly is awarded
// hyubgone was taken out back. See k_odds.c
tic_t mapreset; // Map reset delay when enough players have joined an empty game
boolean thwompsactive; // Thwomps activate on lap 2
UINT8 lastLowestLap; // Last lowest lap, for activating race lap executors
@ -442,11 +439,13 @@ consvar_t cv_showfreeplay = CVAR_INIT ("showfreeplay", "On", CV_SAVE, CV_OnOff,
static CV_PossibleValue_t powermusic_cons_t[] = {{0, "Off"}, {1, "On"}, {2, "SFX"}, {0, NULL}};
consvar_t cv_growmusic = CVAR_INIT ("growmusic", "On", CV_SAVE, powermusic_cons_t, NULL);
consvar_t cv_supermusic = CVAR_INIT ("supermusic", "On", CV_SAVE, powermusic_cons_t, NULL);
consvar_t cv_altshrinkmusic = CVAR_INIT ("altshrinkmusic", "On", CV_SAVE, powermusic_cons_t, NULL);
consvar_t cv_invertmouse = CVAR_INIT ("invertmouse", "Off", CV_SAVE, CV_OnOff, NULL);
consvar_t cv_invincmusicfade = CVAR_INIT ("invincmusicfade", "300", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_growmusicfade = CVAR_INIT ("growmusicfade", "500", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_altshrinkmusicfade = CVAR_INIT ("altshrinkmusicfade", "500", CV_SAVE, CV_Unsigned, NULL);
consvar_t cv_resetspecialmusic = CVAR_INIT ("resetspecialmusic", "Yes", CV_SAVE, CV_YesNo, NULL);
@ -2807,8 +2806,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
// SRB2kart
if (betweenmaps || leveltime <= starttime || spectator == true)
{
itemroulette = KROULETTE_DISABLED;
previtemroulette = KROULETTE_DISABLED;
itemroulette = 0;
previtemroulette = 0;
roulettetype = KROULETTETYPE_NORMAL;
itemtype = 0;
itemamount = 0;
@ -2848,8 +2847,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
}
else
{
itemroulette = (players[player].itemroulette > KROULETTE_DISABLED ? KROULETTE_ACTIVE : KROULETTE_DISABLED);
previtemroulette = (players[player].previtemroulette > KROULETTE_DISABLED ? KROULETTE_ACTIVE : KROULETTE_DISABLED);
itemroulette = players[player].itemroulette > 0 ? 1 : 0;
previtemroulette = players[player].previtemroulette > 0 ? 1 : 0;
roulettetype = players[player].roulettetype;
if (players[player].itemflags & IF_ITEMOUT)
@ -2864,7 +2863,8 @@ void G_PlayerReborn(INT32 player, boolean betweenmaps)
}
// Keep Shrink status, remove Grow status
if (players[player].growshrinktimer < 0)
// Alt. Shrink is a powerup, so don't keep that.
if (players[player].growshrinktimer < 0 && !K_IsKartItemAlternate(KITEM_SHRINK))
growshrinktimer = players[player].growshrinktimer;
else
growshrinktimer = 0;

View file

@ -71,7 +71,7 @@ extern consvar_t cv_chatwidth, cv_chatnotifications, cv_chatheight, cv_chattime,
extern consvar_t cv_shoutname, cv_shoutcolor, cv_autoshout;
extern consvar_t cv_songcredits;
extern consvar_t cv_showfreeplay;
extern consvar_t cv_growmusic, cv_supermusic;
extern consvar_t cv_growmusic, cv_supermusic, cv_altshrinkmusic;
extern consvar_t cv_pauseifunfocused;
@ -88,6 +88,7 @@ extern consvar_t cv_ghost_besttime, cv_ghost_bestlap, cv_ghost_last, cv_ghost_gu
extern consvar_t cv_invincmusicfade;
extern consvar_t cv_growmusicfade;
extern consvar_t cv_altshrinkmusicfade;
extern consvar_t cv_resetspecialmusic;

View file

@ -336,6 +336,16 @@ void K_DisplayItemTimers(void)
true,
}
);
timers.push_back(
{ // item cooldown
"itemusecooldown",
(INT32)stplyr->itemusecooldown,
//{qche("K_ISFLMS")},
{qche("SERVLOCK")},
1, /*-15, -15,*/ -4, -2,
false, false
}
);
/*timers.push_back(
{ // dead

View file

@ -977,11 +977,20 @@ void HWR_PrecacheLevel(void)
// Precache flats.
HWR_PrecacheLevelFlats();
// prevent timeouts
NetKeepAlive();
// Precache textures.
HWR_PrecacheLevelTextures();
// prevent timeouts
NetKeepAlive();
// Precache sprites.
//HWR_PrecacheLevelSprites();
// prevent timeouts
//NetKeepAlive();
}
void HWR_LoadMapTextures(size_t pnumtextures)

View file

@ -50,6 +50,7 @@
#include "../k_kart.h"
#include "../r_fps.h"
#include "../r_plane.h" // R_FlatDimensionsFromLumpSize
#include "../k_items.h"
#define R_FAKEFLOORS
#define HWPRECIP
@ -295,7 +296,7 @@ void HWR_Lighting(FSurfaceInfo *Surface, INT32 light_level, extracolormap_t *col
}
// Clamp the light level, since it can sometimes go out of the 0-255 range from animations
light_level = min(max(light_level, cv_glsecbright.value), 255);
light_level = min(max(light_level, cv_secbright.value), 255);
V_CubeApply(&tint_color.s.red, &tint_color.s.green, &tint_color.s.blue);
V_CubeApply(&fade_color.s.red, &fade_color.s.green, &fade_color.s.blue);
@ -4789,6 +4790,13 @@ static void HWR_ProjectSprite(mobj_t *thing)
sprdef = &((skin_t *)thing->skin)->sprites[thing->sprite2];
#ifdef ROTSPRITE
sprinfo = &((skin_t *)thing->skin)->sprinfo[thing->sprite2];
#endif
}
else if (thing->sprite == SPR_ITEM)
{
sprdef = &kartitems[thing->threshold > 0 && thing->threshold < numkartitems ? thing->threshold : 0].spritedef;
#ifdef ROTSPRITE
sprinfo = &spriteinfo[SPR_UNKN];
#endif
}
else
@ -4905,9 +4913,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
const fixed_t visoffymul = (vflip ? -FRACUNIT : FRACUNIT);
if (R_ThingIsUsingBakedOffsets(thing))
if (R_ThingIsUsingBakedOffsets(interptarg))
{
R_RotateSpriteOffsetsByPitchRoll(thing,
R_RotateSpriteOffsetsByPitchRoll(interptarg,
vflip,
hflip,
&interp,

View file

@ -97,7 +97,6 @@ extern consvar_t cv_glcoronasize;
#endif
extern consvar_t cv_glshaders, cv_glallowshaders;
extern consvar_t cv_glsecbright;
extern consvar_t cv_glmodels;
// SRB2Kart: We don't like these options.

View file

@ -20,6 +20,7 @@
#include "d_main.h"
#include "m_menu.h"
#include "deh_tables.h"
#include "k_items.h"
// Hey, moron! If you wanna change this table, you can just change the sprite enum in info/sprites.h,
// so you don't have to copy and paste the list of sprite names back in here :^)
@ -116,6 +117,12 @@ static const char *hardcodemenus =
#undef _
;
static const char *hardcodeitems =
#define _(name, ...) #name "\0"
#include "info/kartitems.h"
#undef _
;
void P_ResetData(INT32 flags)
{
INT32 i;
@ -233,4 +240,22 @@ void P_ResetData(INT32 flags)
for (i = 0; i < MN_FIRSTFREESLOT; i++, name += strlen(name)+1)
DEH_Link(name, &menudefs[i].info, &menunames);
}
// kartitems
if (init)
{
memset(kartitems, 0, sizeof(kartitems));
numkartitems = KITEM_FIRSTFREESLOT;
if (kartitemnames)
Z_Free(kartitemnames);
kartitemnames = strbuf_alloc();
name = hardcodeitems;
for (i = 0; i < KITEM_FIRSTFREESLOT; i++, name += strlen(name)+1)
{
DEH_Link(name, &kartitems[i].info, &kartitemnames);
K_RegisterItem(i);
}
}
}

21
src/info/kartitems.h Normal file
View file

@ -0,0 +1,21 @@
_(NONE)
_(SNEAKER)
_(ROCKETSNEAKER)
_(INVINCIBILITY)
_(BANANA)
_(EGGMAN)
_(ORBINAUT)
_(JAWZ)
_(MINE)
_(BALLHOG)
_(SPB)
_(GROW)
_(SHRINK)
_(THUNDERSHIELD)
_(HYUDORO)
_(POGOSPRING)
_(KITCHENSINK)
_(SUPERRING)
_(LANDMINE)
_(BUBBLESHIELD)
_(FLAMESHIELD)

View file

@ -602,7 +602,11 @@ _(SMOLDERING) // New explosion
_(BOOMEXPLODE)
_(BOOMPARTICLE)
_(LANDMINE) // Land Mine
// Land Mine
_(LANDMINE)
// Egg Mine
// _(EGGMINE_CAPSULE)
// _(EGGMINE_SHIELD)
_(BALLHOG) // Ballhog
_(BALLHOGBOOM)
@ -614,7 +618,7 @@ _(THUNDERSHIELD) // Shields
_(BUBBLESHIELD)
_(FLAMESHIELD)
_(BUBBLESHIELDTRAP)
_(BUBBLESHLD_DEBRIS)
_(BUBBLESHIELD_DEBRIS)
_(SINK) // Kitchen Sink Stuff
_(SINK_SHIELD)

View file

@ -41,8 +41,6 @@ _(pstop)
_(steam1)
_(steam2)
_(wbreak)
_(ambmac)
_(spsmsh)
_(rainin)
_(litng1)
@ -114,7 +112,6 @@ _(dmpain)
_(drown)
_(fizzle)
_(gbeep)
_(wepfir)
_(ghit)
_(gloop)
_(gspray)
@ -126,19 +123,12 @@ _(lose)
_(lvpass)
_(mindig)
_(mixup)
_(monton)
_(pogo)
_(pop)
_(rail1)
_(rail2)
_(rlaunc)
_(shield)
_(wirlsg)
_(forcsg)
_(frcssg)
_(elemsg)
_(armasg)
_(attrsg)
_(shldls)
_(spdpad)
_(spkdth)
@ -154,24 +144,8 @@ _(trfire)
_(trpowr)
_(turhit)
_(wdjump)
_(shrpsp)
_(shrpgo)
_(mswarp)
_(mspogo)
_(boingf)
_(corkp)
_(corkh)
_(alart)
_(vwre)
_(bowl)
_(chuchu)
//sfx_bsnipe,
_(sprong)
_(lvfal1)
_(pscree)
_(iceb)
_(shattr)
_(antiri)
// Menu, interface
_(chchng)
@ -185,16 +159,12 @@ _(radio)
_(wepchg)
_(wtrdng)
_(zelda)
_(adderr)
_(notadd)
_(addfil)
// NiGHTS
_(ideya)
_(xideya) // Xmas
_(nbmper)
_(nxbump) // Xmas
_(ncchip)
_(ncitem)
_(nxitem) // Xmas
_(ngdone)
@ -210,14 +180,6 @@ _(hoop3)
_(hidden)
_(prloop)
_(timeup)
_(ngjump)
_(peww)
// Halloween
_(lntsit)
_(lntdie)
_(pumpkn)
_(ghosty)
// Mario
_(koopfr)
@ -400,7 +362,6 @@ _(s26f)
_(s270)
// S3&K sounds
_(s3k2b)
_(s3k33)
_(s3k34)
_(s3k35)
@ -522,21 +483,6 @@ _(s3ka8)
_(s3ka9)
_(s3kaa)
_(s3kab)
_(s3kab1)
_(s3kab2)
_(s3kab3)
_(s3kab4)
_(s3kab5)
_(s3kab6)
_(s3kab7)
_(s3kab8)
_(s3kab9)
_(s3kaba)
_(s3kabb)
_(s3kabc)
_(s3kabd)
_(s3kabe)
_(s3kabf)
_(s3kac)
_(s3kad)
_(s3kae)
@ -845,18 +791,6 @@ _(itfree)
_(dbgsal)
_(bhurry) // mine: wasn't here already?
// Chaining Sound
_(bstchn)
// Low Ring Sound
_(ringlw)
// Flip Over Sound
_(flipos)
// Shout message sound effect
_(sysmsg)
// Next up: UNIQUE ENGINE SOUNDS! Hoooooo boy...
// Engine class A - Low Speed, Low Weight
_(krta00)
@ -997,3 +931,82 @@ _(kbost2)
_(kslow)
_(khitem)
_(kgloat)
// Relocated 2.2 sounds to fix magic numbers in v1 maps
_(ambmac)
_(spsmsh)
_(wepfir)
_(monton)
_(wirlsg)
_(forcsg)
_(frcssg)
_(elemsg)
_(armasg)
_(attrsg)
_(shrpsp)
_(shrpgo)
_(boingf)
_(corkp)
_(corkh)
_(alart)
_(vwre)
_(bowl)
_(chuchu)
_(sprong)
_(lvfal1)
_(pscree)
_(iceb)
_(shattr)
_(antiri)
_(adderr)
_(notadd)
_(addfil)
_(ncchip)
_(ngjump)
_(peww)
// Halloween
_(lntsit)
_(lntdie)
_(pumpkn)
_(ghosty)
_(s3k2b)
_(s3kab1)
_(s3kab2)
_(s3kab3)
_(s3kab4)
_(s3kab5)
_(s3kab6)
_(s3kab7)
_(s3kab8)
_(s3kab9)
_(s3kaba)
_(s3kabb)
_(s3kabc)
_(s3kabd)
_(s3kabe)
_(s3kabf)
// New Blan sounds
// Chaining Sound
_(bstchn)
// Low Ring Sound
_(ringlw)
// Flip Over Sound
_(flipos)
// Shout message sound effect
_(sysmsg)

View file

@ -493,9 +493,6 @@ _(ARRO) // player arrows
_(ITEM) // base item
_(ITMO) // Multi-Orbinaut
_(ITMI) // Invincibility
_(ITSN) // Multi-Sneaker
_(ITBA) // Multi-Banana
_(ITJA) // Multi-Jawz
_(ITMN)
_(WANT)

View file

@ -2816,6 +2816,11 @@ _(SLOWBOOM10)
_(LANDMINE)
_(LANDMINE_EXPLODE)
// Egg mine
// _(EGGMINE)
// _(EGGMINE_POP)
// _(EGGMINE_SHIELD)
// Ballhog
_(BALLHOG1)
_(BALLHOG2)

View file

@ -44,6 +44,7 @@
#include "blan/b_soc.h"
#include "v_video.h" // for debugging
#include "k_waypoint.h"
#include "k_items.h"
consvar_t cv_forcebots = CVAR_INIT ("kartforcebots", "Off", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);
consvar_t cv_botcontrol = CVAR_INIT ("kartbotcontrol", "On", CV_NETVAR|CV_CHEAT, CV_OnOff, NULL);

View file

@ -29,7 +29,7 @@
#include "m_random.h"
#include "r_things.h" // numskins
#include "m_easing.h"
#include "k_odds.h"
#include "k_items.h"
#include "k_waypoint.h"
// Looks for players around the bot, and presses the item button
@ -305,6 +305,14 @@ static void K_ItemConfirmForTarget(botdata_t *bd, const player_t *bot, const pla
}
}
/// @brief checks if given bot isn't prevented from using items due to item cooldowns
/// @param bot bot to check cooldowns for
/// @return if bot is able to use item-related actions (using items or mashing the roulette)
static boolean K_CheckBotItemCooldown(const player_t *bot)
{
return bot->itemusecooldown <= 0;
}
// Presses the item button & aim buttons for the bot.
// dir - Aiming direction: 1 for forwards, -1 for backwards, 0 for neutral.
@ -958,7 +966,8 @@ static void K_BotItemFlame(botdata_t *bd, const player_t *player)
{
ZoneScoped;
if (player->flametimer >= (itemtime*3)-5)
// if we're smart enough, allow overheating the flame shield if we want to go off-road
if (player->flametimer >= (itemtime*3)-5 && !(K_ApplyOffroad(player) && player->botvars.difficulty >= 6))
{
bd->itemdelay = 5;
}
@ -1155,7 +1164,7 @@ static void K_BotItemRouletteMash(botdata_t *bd, const player_t *player)
}
}
if (player->rings < 0 && cv_superring.value && K_RingsActive())
if (player->rings < 0 && K_ItemResultEnabled(K_GetKartResult("superring")))
{
// Uh oh, we need a loan!
// It'll be better in the long run for bots to lose an item set for 5-15 free rings.
@ -1201,7 +1210,7 @@ void K_BotItemUsage(botdata_t *bd, const player_t *player)
}
return;
}
if (K_CanHandleItemDelay(bd, player))
{
bd->itemdelay--;
@ -1209,6 +1218,8 @@ void K_BotItemUsage(botdata_t *bd, const player_t *player)
return;
}
if (!K_CheckBotItemCooldown(player)) return;
if (player->itemroulette)
{
// Mashing behaviors

View file

@ -33,6 +33,7 @@
#include "p_slopes.h" // P_GetZAt
#include "m_perfstats.h"
#include "k_objects.h"
#include "k_items.h"
#include "blan/b_soc.h"

View file

@ -7,7 +7,7 @@
#include "doomtype.h"
#include "p_mobj.h"
#include "k_kart.h"
#include "k_odds.h"
#include "k_items.h"
#include "p_local.h"
#include "s_sound.h"
#include "r_main.h" // R_PointToAngle2, R_PointToDist2
@ -256,10 +256,7 @@ boolean K_EggItemCollide(mobj_t *t1, mobj_t *t2)
}
else
{
K_DropItems(t2->player); //K_StripItems(t2->player);
//K_StripOther(t2->player);
t2->player->itemroulette = KROULETTE_ACTIVE;
t2->player->roulettetype = KROULETTETYPE_EGGMAN;
K_StartRoulette(t2->player, KROULETTETYPE_EGGMAN);
}
if (t2->player->flamestore && (K_GetShieldFromPlayer(t2->player) == KSHIELD_FLAME))
@ -515,6 +512,12 @@ static inline BlockItReturn_t PIT_ThunderShieldAttack(mobj_t *thing)
}
#endif
if (thing->type == MT_SPB) // If you destroy a SPB, you don't get the luxury of a cooldown.
{
spbplace = -1;
K_SetIndirectItemCooldown(0);
}
P_DamageMobj(thing, lightningSource, lightningSource, 1, DMG_VOLTAGE|DMG_CANTHURTSELF);
return BMIT_CONTINUE;
}
@ -573,12 +576,13 @@ static void K_BubbleShieldCollideDrain(player_t *player, mobj_t *bubble, INT16 d
static boolean K_BubbleReflectingTrapItem(const mobj_t *t)
{
return t->type == MT_BANANA || (t->type == MT_ORBINAUT && t->flags2 & MF2_AMBUSH) || t->type == MT_JAWZ_DUD ||
t->type == MT_EGGMANITEM || t->type == MT_SSMINE || t->type == MT_SSMINE_SHIELD || t->type == MT_LANDMINE;
t->type == MT_EGGMANITEM || t->type == MT_SSMINE || t->type == MT_SSMINE_SHIELD || t->type == MT_LANDMINE;// ||
// t->type == MT_EGGMINE_CAPSULE || t->type == MT_EGGMINE_SHIELD;
}
static boolean K_StrongPlayerBump(const player_t *player)
{
return (((K_GetKartInvinType() == KARTINVIN_LEGACY) && (player->invincibilitytimer))
return (((!K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (player->invincibilitytimer))
|| (player->growshrinktimer > 0));
}
@ -636,7 +640,7 @@ boolean K_BubbleShieldCanReflect(mobj_t *t)
{
return (t->type == MT_ORBINAUT || t->type == MT_JAWZ || t->type == MT_JAWZ_DUD
|| t->type == MT_BANANA || t->type == MT_EGGMANITEM || t->type == MT_BALLHOG
|| t->type == MT_SSMINE || t->type == MT_LANDMINE || t->type == MT_SINK
|| t->type == MT_SSMINE || t->type == MT_LANDMINE || t->type == MT_SINK //|| t->type == MT_EGGMINE_CAPSULE
|| t->type == MT_KART_LEFTOVER
|| t->type == MT_PLAYER);
}
@ -656,6 +660,7 @@ static INT16 K_GetBubbleDamage(mobj_t* itm)
{
case MT_EGGMANITEM:
case MT_BALLHOG:
// case MT_EGGMINE_CAPSULE:
// Experiment: Let Bubble Shields hard-counter Ballhogs and Eggboxes.
dmg = 0;
break;
@ -820,7 +825,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
boolean t2Condition = false;
// Rim suggestion: Flipover damage is negligible at best, just cull it from Invincibility as a whole.
if (K_GetKartInvinType() == KARTINVIN_LEGACY)
if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
{
t1Condition = (t1->player->invincibilitytimer > 0);
t2Condition = (t2->player->invincibilitytimer > 0);
@ -832,7 +837,7 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
K_DoInstashield(t2->player);
return false;
}
else if (K_GetKartInvinType() == KARTINVIN_LEGACY)
else if (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))
{
if (t1Condition == true && t2Condition == false)
{
@ -857,19 +862,40 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
{
if (G_CompatLevel(0x0008) || !hyudoroT1)
{
switch (cv_kartairsquish.value)
if ((t2->player) && (K_IsAltShrunk(t2->player)) &&
(!(t1->player && t1->player->growshrinktimer > 0)))
{
case 1:
P_DamageMobj(t2, t1, t1, 1, DMG_SQUISH);
return true;
break;
case 2:
P_DamageMobj(t2, t1, t1, 1, DMG_FLIPOVER);
return true;
break;
default:
return false;
break;
// Alt. Shrink: Just make the player flip over.
if (P_DamageMobj(t2, NULL, NULL, 1, DMG_FLIPOVER))
{
K_AltShrinkPityIncrease(t2->player);
t2->player->altshrinktimeshit++;
P_InstaThrust(t2, K_MomentumAngle(t2), K_Momentum2D(t2) / 3);
K_PlayPainSound(t2, NULL);
}
}
if (P_IsObjectOnGround(t1) && P_IsObjectOnGround(t2))
{
P_DamageMobj(t2, t1, t1, 1, DMG_SQUISH);
}
else
{
switch (cv_kartairsquish.value)
{
case 1:
P_DamageMobj(t2, t1, t1, 1, DMG_SQUISH);
return true;
break;
case 2:
P_DamageMobj(t2, t1, t1, 1, DMG_FLIPOVER);
return true;
break;
default:
return false;
break;
}
}
}
}
@ -878,20 +904,42 @@ boolean K_PvPTouchDamage(mobj_t *t1, mobj_t *t2)
if (G_CompatLevel(0x0008) || !hyudoroT2)
{
// shitty code duplication 🥲
switch (cv_kartairsquish.value)
if ((t1->player) && (K_IsAltShrunk(t1->player)) &&
(!(t2->player && t2->player->growshrinktimer > 0)))
{
case 1:
P_DamageMobj(t1, t2, t2, 1, DMG_SQUISH);
return true;
break;
case 2:
P_DamageMobj(t1, t2, t2, 1, DMG_FLIPOVER);
return true;
break;
default:
return false;
break;
// Alt. Shrink: Just make the player flip over.
if (P_DamageMobj(t1, NULL, NULL, 1, DMG_FLIPOVER))
{
K_AltShrinkPityIncrease(t1->player);
t1->player->altshrinktimeshit++;
P_InstaThrust(t1, K_MomentumAngle(t1), K_Momentum2D(t1) / 3);
K_PlayPainSound(t1, NULL);
}
}
else if (P_IsObjectOnGround(t1) && P_IsObjectOnGround(t2))
{
P_DamageMobj(t1, t2, t2, 1, DMG_SQUISH);
}
else
{
switch (cv_kartairsquish.value)
{
case 1:
P_DamageMobj(t1, t2, t2, 1, DMG_SQUISH);
return true;
break;
case 2:
P_DamageMobj(t1, t2, t2, 1, DMG_FLIPOVER);
return true;
break;
default:
return false;
break;
}
}
}
return true;
}

View file

@ -17,7 +17,7 @@
#include "k_boss.h"
#include "k_color.h"
#include "k_director.h"
#include "k_odds.h"
#include "k_items.h"
#include "p_mobj.h"
#include "screen.h"
#include "doomtype.h"
@ -181,33 +181,12 @@ static patch_t *kp_wantedreticle;
static patch_t *kp_minimapdot;
static patch_t *kp_itembg[8];
static patch_t *kp_itemalt[4];
static patch_t *kp_itemtimer[2];
static patch_t *kp_itemmulsticker[4];
static patch_t *kp_itemx;
static patch_t *kp_sadface[2];
static patch_t *kp_sneaker[4];
static patch_t *kp_rocketsneaker[2];
static patch_t *kp_invincibility[13];
static patch_t *kp_banana[5];
static patch_t *kp_eggman[2];
static patch_t *kp_orbinaut[5];
static patch_t *kp_jawz[3];
static patch_t *kp_mine[2];
static patch_t *kp_ballhog[2];
static patch_t *kp_selfpropelledbomb[2];
static patch_t *kp_grow[2];
static patch_t *kp_shrink[2];
static patch_t *kp_thundershield[2];
static patch_t *kp_hyudoro[2];
static patch_t *kp_pogospring[2];
static patch_t *kp_kitchensink[2];
static patch_t *kp_superring[2];
static patch_t *kp_landmine[2];
static patch_t *kp_bubbleshield[2];
static patch_t *kp_flameshield[2];
static patch_t *kp_check[6];
static patch_t *kp_check[11];
static patch_t *kp_eggnum[4];
@ -540,95 +519,54 @@ void K_LoadKartHUDGraphics(void)
// Kart Item Windows
HU_UpdatePatch(&kp_itembg[0], "K_ITBG");
HU_UpdatePatch(&kp_itembg[1], "K_ITBGD");
HU_UpdatePatch(&kp_itembg[4], "K_ITBC");
HU_UpdatePatch(&kp_itembg[5], "K_ITBCD");
HU_UpdatePatch(&kp_itemtimer[0], "K_ITIMER");
HU_UpdatePatch(&kp_itemmulsticker[0], "K_ITMUL");
HU_UpdatePatch(&kp_itemmulsticker[2], "K_ITMULC");
HU_UpdatePatch(&kp_itemx, "K_ITX");
HU_UpdatePatch(&kp_sadface[0], "K_ITSAD");
HU_UpdatePatch(&kp_sneaker[0], "K_ITSHOE");
HU_UpdatePatch(&kp_sneaker[1], "K_ITSHO2");
HU_UpdatePatch(&kp_sneaker[2], "K_ITSHO3");
HU_UpdatePatch(&kp_rocketsneaker[0], "K_ITRSHE");
sprintf(buffer, "K_ITINVx");
for (i = 0; i < 7; i++)
{
buffer[7] = '1'+i;
HU_UpdatePatch(&kp_invincibility[i], "%s", buffer);
}
HU_UpdatePatch(&kp_banana[0], "K_ITBANA");
HU_UpdatePatch(&kp_banana[1], "K_ITBAN2");
HU_UpdatePatch(&kp_banana[2], "K_ITBAN3");
HU_UpdatePatch(&kp_banana[3], "K_ITBAN4");
HU_UpdatePatch(&kp_eggman[0], "K_ITEGGM");
sprintf(buffer, "K_ITORBx");
for (i = 0; i < 4; i++)
{
buffer[7] = '1'+i;
HU_UpdatePatch(&kp_orbinaut[i], "%s", buffer);
}
HU_UpdatePatch(&kp_jawz[0], "K_ITJAWZ");
HU_UpdatePatch(&kp_jawz[1], "K_ITJAW2");
HU_UpdatePatch(&kp_mine[0], "K_ITMINE");
HU_UpdatePatch(&kp_ballhog[0], "K_ITBHOG");
HU_UpdatePatch(&kp_selfpropelledbomb[0], "K_ITSPB");
HU_UpdatePatch(&kp_grow[0], "K_ITGROW");
HU_UpdatePatch(&kp_shrink[0], "K_ITSHRK");
HU_UpdatePatch(&kp_thundershield[0], "K_ITTHNS");
HU_UpdatePatch(&kp_hyudoro[0], "K_ITHYUD");
HU_UpdatePatch(&kp_pogospring[0], "K_ITPOGO");
HU_UpdatePatch(&kp_kitchensink[0], "K_ITSINK");
HU_UpdatePatch(&kp_superring[0], "K_ITRING");
HU_UpdatePatch(&kp_landmine[0], "K_ITLNDM");
HU_UpdatePatch(&kp_bubbleshield[0], "K_ITBUBS");
HU_UpdatePatch(&kp_flameshield[0], "K_ITFLMS");
// Splitscreen
HU_UpdatePatch(&kp_itembg[2], "K_ISBG");
HU_UpdatePatch(&kp_itembg[3], "K_ISBGD");
HU_UpdatePatch(&kp_itembg[4], "K_ITBC");
HU_UpdatePatch(&kp_itembg[5], "K_ITBCD");
HU_UpdatePatch(&kp_itembg[6], "K_ISBC");
HU_UpdatePatch(&kp_itembg[7], "K_ISBCD");
HU_UpdatePatch(&kp_itemalt[0], "K_ALTITM");
HU_UpdatePatch(&kp_itemalt[1], "K_ALTITS");
HU_UpdatePatch(&kp_itemalt[2], "K_ALTIMM");
HU_UpdatePatch(&kp_itemalt[3], "K_ALTISM");
HU_UpdatePatch(&kp_itemtimer[0], "K_ITIMER");
HU_UpdatePatch(&kp_itemtimer[1], "K_ISIMER");
HU_UpdatePatch(&kp_itemmulsticker[0], "K_ITMUL");
HU_UpdatePatch(&kp_itemmulsticker[1], "K_ISMUL");
HU_UpdatePatch(&kp_itemmulsticker[2], "K_ITMULC");
HU_UpdatePatch(&kp_itemmulsticker[3], "K_ISMULC");
HU_UpdatePatch(&kp_itemx, "K_ITX");
HU_UpdatePatch(&kp_sadface[1], "K_ISSAD");
HU_UpdatePatch(&kp_sneaker[3], "K_ISSHOE");
HU_UpdatePatch(&kp_rocketsneaker[1], "K_ISRSHE");
sprintf(buffer, "K_ISINVx");
for (i = 0; i < 6; i++)
for (i = 0; i < numkartitems; i++)
{
buffer[7] = '1'+i;
HU_UpdatePatch(&kp_invincibility[i+7], "%s", buffer);
kartitem_t *item = &kartitems[i];
for (j = 0; j < 2; j++)
{
kartitemgraphics_t *graphics = &item->graphics[j];
for (INT32 k = 0; k < graphics->numpatches; k++)
{
if (graphics->patches[k] == NULL)
{
// have to manually do this because HU_UpdatePatch only checks graphics from added WADs during partadd
// UUUUUGGGGGGGHHHHHHHHHHHHHHHHHHh
lumpnum_t lump = W_CheckNumForName(graphics->patchnames[k]);
graphics->patches[k] = lump == LUMPERROR ? missingpat : W_CachePatchNum(lump, PU_HUDGFX);
}
else
HU_UpdatePatch(&graphics->patches[k], graphics->patchnames[k]);
}
}
R_AddKartItemSprites(item);
}
HU_UpdatePatch(&kp_banana[4], "K_ISBANA");
HU_UpdatePatch(&kp_eggman[1], "K_ISEGGM");
HU_UpdatePatch(&kp_orbinaut[4], "K_ISORBN");
HU_UpdatePatch(&kp_jawz[2], "K_ISJAWZ");
HU_UpdatePatch(&kp_mine[1], "K_ISMINE");
HU_UpdatePatch(&kp_ballhog[1], "K_ISBHOG");
HU_UpdatePatch(&kp_selfpropelledbomb[1], "K_ISSPB");
HU_UpdatePatch(&kp_grow[1], "K_ISGROW");
HU_UpdatePatch(&kp_shrink[1], "K_ISSHRK");
HU_UpdatePatch(&kp_thundershield[1], "K_ISTHNS");
HU_UpdatePatch(&kp_hyudoro[1], "K_ISHYUD");
HU_UpdatePatch(&kp_pogospring[1], "K_ISPOGO");
HU_UpdatePatch(&kp_kitchensink[1], "K_ISSINK");
HU_UpdatePatch(&kp_superring[1], "K_ISRING");
HU_UpdatePatch(&kp_landmine[1], "K_ISLNDM");
HU_UpdatePatch(&kp_bubbleshield[1], "K_ISBUBS");
HU_UpdatePatch(&kp_flameshield[1], "K_ISFLMS");
// CHECK indicators
sprintf(buffer, "K_CHECKx");
for (i = 0; i < 6; i++)
for (i = 0; i < 10; i++)
{
buffer[7] = '1'+i;
HU_UpdatePatch(&kp_check[i], "%s", buffer);
}
HU_UpdatePatch(&kp_check[10], "K_CHECKA");
// Eggman warning numbers
sprintf(buffer, "K_EGGNx");
@ -723,103 +661,6 @@ void K_LoadKartHUDGraphics(void)
}
}
// For the item toggle menu
const char *K_GetItemPatch(UINT8 item, boolean tiny)
{
switch (item)
{
case KITEM_SNEAKER:
return (tiny ? "K_ISSHOE" : "K_ITSHOE");
case KITEM_ROCKETSNEAKER:
return (tiny ? "K_ISRSHE" : "K_ITRSHE");
case KITEM_INVINCIBILITY:
return (tiny ? "K_ISINV1" : "K_ITINV1");
case KITEM_BANANA:
return (tiny ? "K_ISBANA" : "K_ITBANA");
case KITEM_EGGMAN:
return (tiny ? "K_ISEGGM" : "K_ITEGGM");
case KITEM_ORBINAUT:
return (tiny ? "K_ISORBN" : "K_ITORB1");
case KITEM_JAWZ:
return (tiny ? "K_ISJAWZ" : "K_ITJAWZ");
case KITEM_MINE:
return (tiny ? "K_ISMINE" : "K_ITMINE");
case KITEM_BALLHOG:
return (tiny ? "K_ISBHOG" : "K_ITBHOG");
case KITEM_SPB:
return (tiny ? "K_ISSPB" : "K_ITSPB");
case KITEM_GROW:
return (tiny ? "K_ISGROW" : "K_ITGROW");
case KITEM_SHRINK:
return (tiny ? "K_ISSHRK" : "K_ITSHRK");
case KITEM_THUNDERSHIELD:
return (tiny ? "K_ISTHNS" : "K_ITTHNS");
case KITEM_HYUDORO:
return (tiny ? "K_ISHYUD" : "K_ITHYUD");
case KITEM_POGOSPRING:
return (tiny ? "K_ISPOGO" : "K_ITPOGO");
case KITEM_KITCHENSINK:
return (tiny ? "K_ISSINK" : "K_ITSINK");
case KITEM_SUPERRING:
return (tiny ? "K_ISRING" : "K_ITRING");
case KITEM_LANDMINE:
return (tiny ? "K_ISLNDM" : "K_ITLNDM");
case KITEM_BUBBLESHIELD:
return (tiny ? "K_ISBUBS" : "K_ITBUBS");
case KITEM_FLAMESHIELD:
return (tiny ? "K_ISFLMS" : "K_ITFLMS");
case KRITEM_DUALSNEAKER:
return (tiny ? "K_ISSHOE" : "K_ITSHO2");
case KRITEM_TRIPLESNEAKER:
return (tiny ? "K_ISSHOE" : "K_ITSHO3");
case KRITEM_TRIPLEORBINAUT:
return (tiny ? "K_ISORBN" : "K_ITORB3");
case KRITEM_DUALJAWZ:
return (tiny ? "K_ISJAWZ" : "K_ITJAW2");
case KRITEM_TRIPLEBANANA:
return (tiny ? "K_ISBANA" : "K_ITBAN3");
case KRITEM_TENFOLDBANANA:
return (tiny ? "K_ISBANA" : "K_ITBAN4");
case KRITEM_QUADORBINAUT:
return (tiny ? "K_ISORBN" : "K_ITORB4");
default:
return (tiny ? "K_ISSAD" : "K_ITSAD");
}
}
static patch_t *K_GetCachedItemPatch(INT32 item, UINT8 offset)
{
patch_t **kp[1 + NUMKARTITEMS] = {
kp_sadface,
NULL,
kp_sneaker,
kp_rocketsneaker,
kp_invincibility,
kp_banana,
kp_eggman,
kp_orbinaut,
kp_jawz,
kp_mine,
kp_ballhog,
kp_selfpropelledbomb,
kp_grow,
kp_shrink,
kp_thundershield,
kp_hyudoro,
kp_pogospring,
kp_kitchensink,
kp_superring,
kp_landmine,
kp_bubbleshield,
kp_flameshield,
};
if (item == KITEM_SAD || (item > KITEM_NONE && item < NUMKARTITEMS))
return kp[item - KITEM_SAD][offset];
else
return NULL;
}
//}
INT32 ITEM_X, ITEM_Y; // Item Window
@ -890,6 +731,12 @@ patch_t *K_getItemMulPatch(boolean small)
return K_UseColorHud() ? kp_itemmulsticker[2+ofs] : kp_itemmulsticker[ofs];
}
patch_t *K_getItemAltPatch(boolean small, boolean multimode)
{
UINT8 ofs = (small ? 1 : 0) + (multimode ? 2 : 0);
return kp_itemalt[ofs];
}
// This version of the function was prototyped in Lua by Nev3r ... a HUGE thank you goes out to them!
void K_ObjectTracking(trackingResult_t *result, const vector3_t *point, boolean reverse)
{
@ -1322,6 +1169,32 @@ static void K_DrawItemBar(INT32 fx, INT32 fy, INT32 fflags, fixed_t itembar, UIN
V_DrawFixedFill(x+2*FRACUNIT, y+FRACUNIT, max(0, length - 2*FRACUNIT), FRACUNIT, colors[0]|fflags); // the shine
}
// TODO: use an actual patch overlay and clip it instead of using a rect, now that an actual patch can be added for this
static void K_DrawItemCooldown(INT32 fx, INT32 fy, INT32 fflags, tic_t timer, tic_t maxtimer)
{
const boolean fourp = r_splitscreen > 1;
const INT32 rectTopFour = 13*FRACUNIT;
INT32 rectTop = 10*FRACUNIT;
INT32 rectSize = 40*FRACUNIT;
fixed_t prog = FixedDiv(timer, maxtimer);
INT32 length = min(rectSize, FixedMul(rectSize, prog));
if (timer > 0 && maxtimer > 0)
{
if (fourp)
{
rectTop = 14*FRACUNIT;
rectSize = 20*FRACUNIT;
length = min(rectSize, FixedMul(rectSize, prog));
V_DrawFixedFill(fx + rectTop, fy + rectTopFour + (rectSize - length), rectSize, length, 2|fflags);
}
else
{
V_DrawFixedFill(fx + rectTop, fy + rectTop + (rectSize - length), rectSize, length, 2|fflags);
}
}
}
// see also MT_PLAYERARROW mobjthinker in p_mobj.c
static void K_drawKartItem(void)
{
@ -1330,19 +1203,18 @@ static void K_drawKartItem(void)
// Why write V_DrawScaledPatch calls over and over when they're all the same?
// Set to 'no item' just in case.
const UINT8 offset = ((r_splitscreen > 1) ? 1 : 0);
const boolean tiny = r_splitscreen > 1;
patch_t *localpatch = kp_nodraw;
patch_t *localbg;
patch_t *localinv = ((offset) ? kp_invincibility[((leveltime % (6*3)) / 3) + 7] : kp_invincibility[(leveltime % (7*3)) / 3]);
boolean dark = false;
INT32 fx = 0, fy = 0, fflags = 0; // final coords for hud and flags...
INT32 numberdisplaymin = 2;
fixed_t itembar = -1, flamebar = -1;
UINT16 localcolor = SKINCOLOR_NONE;
SINT8 colormode = TC_RAINBOW;
UINT8 *colmap = NULL;
UINT8 *colormap = NULL;
boolean flipamount = false; // Used for 3P/4P splitscreen to flip item amount stuff
boolean isalt = false;
if (stplyr->itemroulette)
{
@ -1351,26 +1223,7 @@ static void K_drawKartItem(void)
if (K_GetHudColor())
localcolor = K_GetHudColor();
switch (item)
{
case KITEM_SNEAKER:
localpatch = kp_sneaker[offset ? 3: 0];
break;
case KITEM_BANANA:
localpatch = kp_banana[offset ? 4: 0];
break;
case KITEM_ORBINAUT:
localpatch = kp_orbinaut[3+offset];
break;
case KITEM_JAWZ:
localpatch = kp_jawz[offset ? 2: 0];
break;
case KITEM_INVINCIBILITY:
localpatch = localinv;
break;
default:
localpatch = K_GetCachedItemPatch(item, offset);
}
localpatch = K_GetCachedItemPatch(item, tiny, 0);
}
else
{
@ -1381,18 +1234,18 @@ static void K_drawKartItem(void)
if (stplyr->stolentimer > 0)
{
if (leveltime & 2)
localpatch = kp_hyudoro[offset];
localpatch = K_GetCachedItemPatch(KITEM_HYUDORO, tiny, 0);
else
localpatch = kp_nodraw;
}
else if ((stplyr->stealingtimer > 0) && (leveltime & 2))
{
localpatch = kp_hyudoro[offset];
localpatch = K_GetCachedItemPatch(KITEM_HYUDORO, tiny, 0);
}
else if (stplyr->eggmanexplode > 1)
{
if (leveltime & 1)
localpatch = kp_eggman[offset];
localpatch = K_GetCachedItemPatch(KITEM_EGGMAN, tiny, 0);
else
localpatch = kp_nodraw;
}
@ -1401,7 +1254,7 @@ static void K_drawKartItem(void)
itembar = FixedDiv(stplyr->rocketsneakertimer, itemtime*3);
if (leveltime & 1)
localpatch = kp_rocketsneaker[offset];
localpatch = K_GetCachedItemPatch(KITEM_ROCKETSNEAKER, tiny, 0);
else
localpatch = kp_nodraw;
}
@ -1409,7 +1262,6 @@ static void K_drawKartItem(void)
{
itembar = FixedDiv(stplyr->flametimer, itemtime*3);
flamebar = FixedDiv(stplyr->flamestore, FLAMESTOREMAX);
localbg = kp_itembg[offset+1];
dark = true;
if ((stplyr->flamestore >= FLAMESTOREMAX-1) && (leveltime & 1))
@ -1419,7 +1271,7 @@ static void K_drawKartItem(void)
}
if (leveltime & 1)
localpatch = kp_flameshield[offset];
localpatch = K_GetCachedItemPatch(KITEM_FLAMESHIELD, tiny, 0);
else
localpatch = kp_nodraw;
}
@ -1429,11 +1281,11 @@ static void K_drawKartItem(void)
itembar = FixedDiv(stplyr->growcancel, 26);
if (leveltime & 1)
localpatch = kp_grow[offset];
localpatch = K_GetCachedItemPatch(KITEM_GROW, tiny, 0);
else
localpatch = kp_nodraw;
}
else if ((stplyr->invincibilitytimer) && (K_GetKartInvinType() == KARTINVIN_ALTERN))
else if ((stplyr->invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)))
{
itembar = FixedDiv(stplyr->invincibilitytimer, max(1, stplyr->maxinvincibilitytime));
@ -1441,13 +1293,16 @@ static void K_drawKartItem(void)
flamebar = FixedDiv(stplyr->invincibilitycancel, 26);
if (leveltime & 1)
localpatch = localinv;
{
localpatch = K_GetCachedItemPatch(KITEM_INVINCIBILITY, tiny, 0);
isalt = true;
}
else
localpatch = kp_nodraw;
}
else if (K_GetShieldFromPlayer(stplyr) == KSHIELD_BUBBLE)
{
localpatch = kp_bubbleshield[offset];
localpatch = K_GetCachedItemPatch(KITEM_BUBBLESHIELD, tiny, 0);
dark = true;
if (stplyr->bubbleblowup > 0 && leveltime & 1)
@ -1461,53 +1316,22 @@ static void K_drawKartItem(void)
else if (stplyr->sadtimer > 0)
{
if (leveltime & 2)
localpatch = kp_sadface[offset];
localpatch = K_GetCachedItemPatch(MAXKARTITEMS, tiny, 0);
else
localpatch = kp_nodraw;
}
else
{
if (stplyr->itemamount <= 0)
if (stplyr->itemamount <= 0 && stplyr->itemusecooldown <= 0)
return;
switch(stplyr->itemtype)
{
case KITEM_SNEAKER:
localpatch = kp_sneaker[(offset ? 3 : min(stplyr->itemamount-1, 2))];
numberdisplaymin = 4;
numberdisplaymin = offset ? 2 : 4;
break;
case KITEM_INVINCIBILITY:
localpatch = localinv;
localbg = kp_itembg[offset+1];
break;
case KITEM_BANANA:
localpatch = kp_banana[(offset ? 4 : min(stplyr->itemamount-1, 3))];
numberdisplaymin = offset ? 2 : 5;
break;
case KITEM_ORBINAUT:
localpatch = kp_orbinaut[(offset ? 4 : min(stplyr->itemamount-1, 3))];
numberdisplaymin = offset ? 2 : 5;
break;
case KITEM_JAWZ:
localpatch = kp_jawz[(offset ? 2 : min(stplyr->itemamount-1, 1))];
numberdisplaymin = 3;
numberdisplaymin = offset ? 2 : 3;
break;
case KITEM_SPB:
case KITEM_THUNDERSHIELD:
case KITEM_BUBBLESHIELD:
case KITEM_FLAMESHIELD:
dark = true;
/*FALLTHRU*/
localpatch = K_GetCachedItemPatch(stplyr->itemtype, tiny, stplyr->itemamount);
if (localpatch == NULL)
localpatch = kp_nodraw; // diagnose underflows
else if (K_IsKartItemAlternate(stplyr->itemtype))
isalt = true;
default:
localpatch = K_GetCachedItemPatch(stplyr->itemtype, offset);
if (localpatch == NULL)
localpatch = kp_nodraw; // diagnose underflows
break;
}
dark = K_GetItemFlags(stplyr->itemtype) & KIF_DARKBG;
if ((stplyr->itemflags & IF_ITEMOUT) && !(leveltime & 1))
localpatch = kp_nodraw;
@ -1519,10 +1343,11 @@ static void K_drawKartItem(void)
switch (stplyr->itemblinkmode)
{
case 2:
case KITEMBLINK_DEBUG:
case KITEMBLINK_KARMA:
localcolor = K_RainbowColor(leveltime);
break;
case 1:
case KITEMBLINK_MASHED:
localcolor = SKINCOLOR_RED;
break;
default:
@ -1532,7 +1357,7 @@ static void K_drawKartItem(void)
}
}
localbg = K_getItemBoxPatch((boolean)offset, dark);
localbg = K_getItemBoxPatch(tiny, dark);
drawinfo_t info;
K_getItemBoxDrawinfo(&info);
fx = info.x;
@ -1540,7 +1365,14 @@ static void K_drawKartItem(void)
fflags = info.flags;
flipamount = info.flipamount;
if (localcolor != SKINCOLOR_NONE)
{
colmap = R_GetTranslationColormap(colormode, localcolor, GTC_CACHE);
}
else if (K_GetItemFlags(stplyr->itemtype) & KIF_COLPATCH2PLAYER)
{
colmap = R_GetTranslationColormap(TC_DEFAULT, stplyr->skincolor, GTC_CACHE);
}
if (K_UseColorHud())
colormap = R_GetTranslationColormap(TC_DEFAULT, K_GetHudColor(), GTC_CACHE);
@ -1551,10 +1383,11 @@ static void K_drawKartItem(void)
fixed_t rfy = fy<<FRACBITS;
INT32 fancyflags = V_HUDTRANS|fflags;
// mine: TODO - implement even nicer version from xItemLib-next
if (cv_fancyroulette.value && stplyr->itemroulette && !stplyr->deadtimer)
{
fixed_t frac = R_GetTimeFrac(RTF_LEVEL);
UINT8 fancystep = (offset ? 6 : 10);
UINT8 fancystep = tiny ? 6 : 10;
fixed_t fancyoffset = (stplyr->itemroulette % 3)-1;
if (fancyoffset != 0)
@ -1567,12 +1400,21 @@ static void K_drawKartItem(void)
}
// Then, the numbers:
if (stplyr->itemamount >= numberdisplaymin && !stplyr->itemroulette)
if (stplyr->itemamount >= K_GetItemNumberDisplayMin(stplyr->itemtype, tiny) && !stplyr->itemroulette)
{
localbg = K_getItemMulPatch((boolean)offset);
localbg = K_getItemMulPatch(tiny);
V_DrawMappedPatch(fx + (flipamount ? 48 : 0), fy, V_HUDTRANS|fflags|(flipamount ? V_FLIP : 0), localbg, colormap); // flip this graphic for p2 and p4 in split and shift it.
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, FRACUNIT, V_HUDTRANS|fflags, localpatch, colmap);
if (offset)
// draw minecraft-style cooldown
K_DrawItemCooldown(fx, fy, V_HUDTRANSHALF|fflags, stplyr->itemusecooldown, stplyr->itemusecooldownmax);
if (isalt)
{
V_DrawFixedPatch(fx<<FRACBITS, fy<<FRACBITS, FRACUNIT, V_HUDTRANS|fflags, K_getItemAltPatch(tiny, true), colmap);
}
if (tiny)
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|fflags, va("x%d", stplyr->itemamount));
else
@ -1584,7 +1426,16 @@ static void K_drawKartItem(void)
}
}
else
{
V_DrawFixedPatch(fx<<FRACBITS, rfy, FRACUNIT, fancyflags, localpatch, colmap);
// draw minecraft-style cooldown
K_DrawItemCooldown(fx, fy, V_HUDTRANSHALF|fflags, stplyr->itemusecooldown, stplyr->itemusecooldownmax);
// TODO: Some proper check for if an alt has unique graphics
if (isalt)
V_DrawFixedPatch(fx<<FRACBITS, rfy, FRACUNIT, fancyflags, K_getItemAltPatch(tiny, false), colmap);
}
//V_ClearClipRect();
@ -1598,7 +1449,7 @@ static void K_drawKartItem(void)
// Quick Eggman numbers
if (stplyr->eggmanexplode > 1)
V_DrawScaledPatch(fx+17, fy+13-offset, V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->eggmanexplode))]);
V_DrawScaledPatch(fx+17, fy+13-(tiny ? 1 : 0), V_HUDTRANS|fflags, kp_eggnum[min(3, G_TicsToSeconds(stplyr->eggmanexplode))]);
}
void K_drawKartTimestamp(tic_t drawtime, INT32 TX, INT32 TY, INT16 emblemmap, UINT8 mode)
@ -2102,7 +1953,7 @@ static boolean K_drawKartPositionFaces(void)
V_DrawMappedPatch(FACE_X + offsets.x, Y + offsets.y, V_HUDTRANS|V_SNAPTOLEFT, facerank, colormap);
if ((players[rankplayer[i]].invincibilitytimer) && (K_GetKartInvinType() == KARTINVIN_ALTERN))
if ((players[rankplayer[i]].invincibilitytimer) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)))
{
colormap = R_GetTranslationColormap(TC_BLINK, K_AltInvincibilityColor(leveltime / 2), GTC_CACHE);
invinchudtrans = K_InvincibilityHUDVisibility(players[rankplayer[i]].invincibilitytimer);
@ -2488,7 +2339,7 @@ static void K_DrawServerMods(INT32 x, INT32 y)
{"Bump Drift", 0, NULL, K_GetBumpSpark() > 0, true},
{"Bump Spark", 0, NULL, K_GetBumpSpark() > BUMPSPARK_NOCHARGE, true},
{"Bump Spring", 0, &cv_kartbumpspring, -1, true},
{"Alt. Invin.", 0, NULL, K_GetKartInvinType() == KARTINVIN_ALTERN, true}
{"Alt. Invin.", 0, NULL, K_IsKartItemAlternate(KITEM_INVINCIBILITY), true}
};
for (j = 0; j < 2; j++)
@ -3414,7 +3265,15 @@ static void K_drawKartPlayerCheck(void)
pnum++; // white frames
}
if (checkplayer->itemtype == KITEM_GROW || checkplayer->growshrinktimer > 0)
if (checkplayer->itemtype == KITEM_FLAMESHIELD || checkplayer->flametimer > 0)
{
pnum += 8;
}
else if (K_IsAltShrunk(checkplayer) && (checkplayer->itemtype == KITEM_SHRINK || checkplayer->growshrinktimer < 0))
{
pnum += 6;
}
else if (checkplayer->itemtype == KITEM_GROW || checkplayer->growshrinktimer > 0)
{
pnum += 4;
}
@ -4335,9 +4194,9 @@ static void K_drawKartMinimap(void)
invingradient = K_InvincibilityGradient(players[i].invincibilitytimer);
if ((players[i].invincibilitytimer) && ((invingradient > (FRACUNIT/2)) || (K_GetKartInvinType() == KARTINVIN_LEGACY)))
if ((players[i].invincibilitytimer) && ((invingradient > (FRACUNIT/2)) || (!K_IsKartItemAlternate(KITEM_INVINCIBILITY))))
{
usecolor = ((K_GetKartInvinType() == KARTINVIN_ALTERN) ? K_AltInvincibilityColor(leveltime / 2) : K_RainbowColor(leveltime / 2));
usecolor = ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) ? K_AltInvincibilityColor(leveltime / 2) : K_RainbowColor(leveltime / 2));
colorizeplayer = true;
}
else
@ -4370,7 +4229,7 @@ static void K_drawKartMinimap(void)
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, &iconoffsets);
#ifdef ROTSPRITE
if ((K_GetKartInvinType() == KARTINVIN_ALTERN) &&
if ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) &&
(players[i].invincibilitytimer) && (invingradient))
{
// Draw Alt. Invin. sparkles
@ -4665,7 +4524,7 @@ static void K_drawKartMinimap(void)
if ((players[localplayers[i]].invincibilitytimer) &&
((invingradient > (FRACUNIT / 2)) ||
(K_GetKartInvinType() == KARTINVIN_LEGACY)))
(!K_IsKartItemAlternate(KITEM_INVINCIBILITY))))
{
usecolor = (K_RainbowColor(leveltime / 2));
colorizeplayer = true;
@ -4735,7 +4594,7 @@ static void K_drawKartMinimap(void)
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, workingPic, colormap, &iconoffsets);
#ifdef ROTSPRITE
if ((!nocontest) && (K_GetKartInvinType() == KARTINVIN_ALTERN) &&
if ((!nocontest) && (K_IsKartItemAlternate(KITEM_INVINCIBILITY)) &&
(players[localplayers[i]].invincibilitytimer) && (invingradient))
{
// Draw Alt. Invin. sparkles
@ -5758,48 +5617,12 @@ K_drawMiniPing (void)
}
}
static patch_t *K_GetSmallStaticCachedItemPatch(kartitems_t item)
{
UINT8 offset;
item = K_ItemResultToType(item);
switch (item)
{
case KITEM_INVINCIBILITY:
offset = 7;
break;
case KITEM_BANANA:
offset = 4;
break;
case KITEM_ORBINAUT:
offset = 4;
break;
case KITEM_JAWZ:
offset = 2;
break;
case KITEM_SNEAKER:
offset = 3;
break;
default:
offset = 1;
}
return K_GetCachedItemPatch(item, offset);
}
static void K_drawDistributionDebugger(void)
{
UINT8 useodds = 0;
UINT8 pingame = 0, bestbumper = 0;
UINT32 pdis = 0;
INT32 i;
INT32 item;
INT32 x = -9, y = -9;
//boolean dontforcespb = false;
boolean spbrush = false;
@ -5825,41 +5648,43 @@ static void K_drawDistributionDebugger(void)
if (pingame == 1)
{
if (stplyr->itemroulette && (stplyr->cmd.buttons & BT_ATTACK) && cv_superring.value && (K_RingsActive() == true))
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SUPERRING));
if (stplyr->itemroulette && stplyr->cmd.buttons & BT_ATTACK && K_ItemResultEnabled(K_GetKartResult("superring")))
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetCachedItemPatch(KITEM_SUPERRING, true, 0));
else
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(KITEM_SNEAKER));
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetCachedItemPatch(KITEM_SNEAKER, true, 0));
V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", 200));
}
else
{
for (item = 1; item < NUMKARTRESULTS; item++)
INT32 itemodds[MAXKARTRESULTS];
kartroulette_t roulette = {
.pdis = pdis,
.playerpos = stplyr->position,
.pos = useodds,
.ourDist = stplyr->distancetofinish,
.clusterDist = stplyr->distancefromcluster,
.mashed = 0,
.spbrush = spbrush,
.bot = stplyr->bot,
.rival = stplyr->bot && stplyr->botvars.rival,
.inBottom = K_IsPlayerLosing(stplyr),
};
K_KartGetItemOdds(&roulette, itemodds);
for (i = 0; i < numkartresults; i++)
{
INT32 itemodds;
INT32 amount;
kartresult_t *result = &kartresults[i];
itemodds = K_KartGetItemOdds(
useodds, item,
stplyr->distancetofinish,
stplyr->distancefromcluster,
0,
spbrush, stplyr->bot, (stplyr->bot && stplyr->botvars.rival),
K_IsPlayerLosing(stplyr)
);
if (itemodds <= 0)
if (itemodds[i] <= 0 && roulette.forceme[i] == 0) // At the very least display forced items; that info's also important.
continue;
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetSmallStaticCachedItemPatch(item));
V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, va("%d", itemodds));
// Display amount for multi-items
amount = K_ItemResultToAmount(item);
if (amount > 1)
{
V_DrawString(x+24, y+31, V_SPLITSCREEN|V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOTOP, va("x%d", amount));
}
V_DrawScaledPatch(x, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, K_GetCachedItemPatch(result->type, true, 0));
if (result->isalt)
V_DrawScaledPatch(x+2, y, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, W_CachePatchName("K_ALTITS", PU_CACHE));
V_DrawThinString(x+11, y+31, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, roulette.forceme[i] ? va("\x85" "FRC(%d)" "\x80 ", roulette.forceme[i]) : va("%d", itemodds[i]));
if (result->amount > 1)
V_DrawString(x+24, y+31, V_SPLITSCREEN|V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOTOP, va("x%d", result->amount));
x += 32;
if (x >= 297)
@ -5880,6 +5705,22 @@ static void K_drawDistributionDebugger(void)
if (K_LegacyOddsMode())
V_DrawSmallString(70, 0, V_SPLITSCREEN|V_HUDTRANS|V_SNAPTOTOP, "Legacy Distance Mode");
// cooldown timer debugging
x = 240;
y = 160;
for (i = 0; i < numkartresults; i++)
{
kartresult_t *result = &kartresults[i];
if (result->cooldown > 0 && result->isalt == K_IsKartItemAlternate(result->type))
{
INT32 color = result->flags & KRF_INDIRECTITEM ? V_ORANGEMAP : K_GetItemFlags(result->type) & KIF_UNIQUE ? V_YELLOWMAP : 0;
V_DrawScaledPatch(x, y, V_HUDTRANS|V_SNAPTOBOTTOM, K_GetCachedItemPatch(result->type, true, 0));
if (result->amount > 1)
V_DrawThinString(x+30, y+30, V_ALLOWLOWERCASE|V_HUDTRANS|V_SNAPTOBOTTOM|V_6WIDTHSPACE, va("x%d", result->amount));
V_DrawString(x+11, y+31, V_HUDTRANS|V_SNAPTOBOTTOM|color, va("%u", result->cooldown/TICRATE));
x -= 32;
}
}
}
static void K_drawCheckpointDebugger(void)

View file

@ -89,13 +89,13 @@ typedef struct
patch_t *K_getItemBoxPatch(boolean small, boolean dark);
patch_t *K_getItemMulPatch(boolean small);
patch_t *K_getItemAltPatch(boolean small, boolean multimode);
void K_getItemBoxDrawinfo(drawinfo_t *out);
void K_getLapsDrawinfo(drawinfo_t *out);
void K_getRingsDrawinfo(drawinfo_t *out);
void K_getMinimapDrawinfo(drawinfo_t *out);
void K_getSlipstreamDrawinfo(drawinfo_t *out);
void K_getLivesnStatsDrawinfo(drawinfo_t *out);
const char *K_GetItemPatch(UINT8 item, boolean tiny);
void K_ReloadHUDColorCvar(void);
boolean K_UseColorHud(void);
UINT8 K_GetHudColor(void);

2414
src/k_items.c Normal file

File diff suppressed because it is too large Load diff

217
src/k_items.h Normal file
View file

@ -0,0 +1,217 @@
// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2025 by Kart Krew.
// Copyright (C) 2025 by "yama".
// Copyright (C) 2025 Blankart Team.
//
// 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_items.h
/// \brief Kart item systems.
#ifndef __K_ITEMS__
#define __K_ITEMS__
#include "doomdef.h"
#include "doomtype.h"
#include "r_defs.h"
#ifdef __cplusplus
extern "C" {
#endif
// Max odds count
#define MAXODDS 16
// Distance variables
#define DISTVAR CV_Get(&cv_kartoddsdist)
#define DISTVAR_LEGACY CV_Get(&cv_kartlegacyoddsdist)
#define SPBDISTVAR CV_Get(&cv_kartspbdist)
#define SPBDISTVAR_LEGACY CV_Get(&cv_kartlegacyspbdist)
typedef enum
{
#define _(name, ...) KITEM_##name,
#include "info/kartitems.h"
#undef _
KITEM_FIRSTFREESLOT,
KITEM_LASTFREESLOT = 126,
MAXKARTITEMS
} ATTRPACK kartitemtype_e;
#define MAXKARTRESULTS 255
typedef enum
{
KITEMBLINK_NORMAL,
KITEMBLINK_MASHED,
KITEMBLINK_KARMA,
KITEMBLINK_DEBUG,
} kartitemblink_e;
typedef enum
{
KROULETTETYPE_NORMAL,
KROULETTETYPE_KARMA,
KROULETTETYPE_EGGMAN,
} kartroulettetype_e;
typedef enum
{
ODDS_RACE,
ODDS_BATTLE,
ODDS_SPECIAL,
MAXODDSTABLES
} ATTRPACK kartoddstable_e;
// item flags for usage and HUD
typedef enum
{
KIF_UNIQUESLOT = 1<<0, // Prevents the item from being rolled if in a player's item slot
KIF_UNIQUEDROP = 1<<1, // Prevents the item from being rolled if it exists as a dropped item
KIF_UNIQUE = KIF_UNIQUESLOT|KIF_UNIQUEDROP,
KIF_ANIMATED = 1<<2, // animate patches instead of using diffrent patches for different amounts (inversion of xItemLib's XIF_ICONFORAMT)
KIF_DARKBG = 1<<3, // use dark item roulette BG
KIF_COLPATCH2PLAYER = 1<<4, // colourize patch to player
KIF_HIDEFROMROULETTE = 1<<5, // don't show this item in the roulette (inversion of xItem's showInRoulette item flag)
} ATTRPACK kartitemflags_e;
// result flags relevant to the roulette
typedef enum
{
KRF_INDIRECTITEM = 1<<0, // This result's item affects others indirectly. All results with this flag share a single cooldown timer.
KRF_POWERITEM = 1<<1, // This result is a "power item". This activates "frantic item" toggle related functionality.
KRF_COOLDOWNONSTART = 1<<2, // This result should not appear at the beginning of a race. (Usually really powerful crowd-breaking items)
KRF_NOTNEAREND = 1<<3, // This result should not appear at the end of a race. (Usually trap items that lose their effectiveness)
KRF_NOTFORBOTTOM = 1<<4, // After the first 30 seconds, this result stops appearing for losing players. (Usually items that feel less effective at these positions)
KRF_RUNNERAUGMENT = 1<<5, // This result's odds are affected by the severity of 1st place's frontrun. (Very likely only for SPBs, but who knows?)
KRF_HIDEFROMSPB = 1<<6, // This result refuses to appear when a Self-Propelled Bomb is active in a race or battle.
} ATTRPACK kartresultflags_e;
// Unique useodds function
typedef INT32 (useoddsfunc_f)(INT32 odds, const kartroulette_t *roulette, const kartresult_t *result, UINT8 *forceme);
#define MAXITEMPATCHES 10
struct kartitemgraphics_t
{
UINT8 numpatches;
char *patchnames[MAXITEMPATCHES];
patch_t *patches[MAXITEMPATCHES];
};
struct kartitem_t
{
dehinfo_t info;
kartitemflags_e flags[2];
kartitemgraphics_t graphics[2];
spritedef_t spritedef;
consvar_t *altcvar; // if not NULL, an altitem exists
boolean altenabled;
// note: could be how we do this?
// int (*oddsOverrideFunc)(player_t *p, int pos, int mashed, boolean spbrush, fixed_t seconddist, int pingame, int pexiting);
// int (*resultOverrideFunc)(player_t *p);
};
struct kartresult_t
{
// this block is shared by all item variants
consvar_t *cvar; // contains name
kartitemtype_e type;
UINT8 amount;
char *displayname;
boolean isalt; // is alt (i salt)
kartresultflags_e flags;
UINT8 odds[MAXODDSTABLES][MAXODDS];
// Functions that tell the game to use unique means of rolling these items.
// If NULL, the functions never execute.
useoddsfunc_f *unique_odds[MAXODDSTABLES];
tic_t basecooldown, cooldown;
};
// contains all data for a call to K_KartGetItemOdds
struct kartroulette_t
{
UINT32 pdis; // the player's PDIS value
SINT8 playerpos; // the player's position
UINT8 pos; // position in the odds table (why is this just "pos"???)
UINT32 ourDist; // the player's finish line distance
UINT32 clusterDist; // distance to cluster
fixed_t mashed;
boolean spbrush;
boolean bot;
boolean rival;
boolean inBottom;
// output: which results are being forced into a player's item slot for one reason or another. Higher value = higher priority.
UINT8 forceme[MAXKARTRESULTS];
// extras for useodds functions
UINT8 pingame;
UINT8 pexiting;
UINT32 firstDist;
};
extern kartitem_t kartitems[MAXKARTITEMS];
extern UINT8 numkartitems;
extern kartresult_t kartresults[MAXKARTRESULTS];
extern UINT8 numkartresults;
extern UINT8 oddstablemax[MAXODDSTABLES];
void K_RegisterItem(kartitemtype_e itemtype);
kartresult_t *K_RegisterResult(const char *name, boolean alternate);
kartresult_t *K_GetKartResultAlt(const char *name, boolean alternate);
#define K_GetKartResult(name) K_GetKartResultAlt(name, false)
void K_SetupItemOdds(void);
boolean K_ItemResultEnabled(const kartresult_t *result);
boolean K_IsKartItemAlternate(kartitemtype_e itemtype);
kartitemflags_e K_GetItemFlags(kartitemtype_e itemtype);
UINT8 K_GetItemNumberDisplayMin(kartitemtype_e type, boolean tiny);
patch_t *K_GetCachedItemPatch(kartitemtype_e type, boolean tiny, UINT8 amount);
void K_AwardPlayerItem(player_t *player, kartitemtype_e type, UINT8 amount, kartitemblink_e blink);
void K_UpdateMobjItemOverlay(mobj_t *part, kartitemtype_e itemType, UINT8 itemCount);
void K_UpdateItemCooldown(void);
tic_t K_GetIndirectItemCooldown(void);
void K_SetIndirectItemCooldown(tic_t cooldown);
boolean K_LegacyOddsMode(void);
UINT32 K_GetCongaLineDistance(const player_t *player, UINT8 startPos);
UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame);
UINT32 K_CalculatePDIS(const player_t *player, UINT8 numPlayers, boolean *spbrush);
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush);
INT32 K_GetRollingRouletteItem(player_t *player);
void K_KartItemRoulette(player_t *player, ticcmd_t *cmd);
void K_StartRoulette(player_t *player, kartroulettetype_e roulettetype);
void K_SetPlayerItemCooldown(player_t *player, tic_t timer, boolean force);
useoddsfunc_f KO_AltInvinOdds;
useoddsfunc_f KO_SPBRaceOdds;
void K_DoThunderShield(player_t *player);
void K_BreakBubbleShield(player_t* player);
INT16 K_GetShrinkTime(const player_t *player);
boolean K_IsAltShrunk(const player_t *player);
void K_AltShrinkPityIncrease(player_t *player);
void K_PlayerItemThink(player_t *player, boolean onground);
#ifdef __cplusplus
} // extern "C"
#endif
#ifndef __cplusplus
void K_KartGetItemOdds(kartroulette_t *roulette, INT32 outodds[static MAXKARTRESULTS]);
#endif
#endif // __K_ITEMS__

File diff suppressed because it is too large Load diff

View file

@ -33,6 +33,7 @@ Make sure this matches the actual number of states
#define SHRINK_SCALE ((6*FRACUNIT)/8)
#define BASEINVINTIME (10 * TICRATE)
#define MININVINTIME (7 * TICRATE)
#define AUTORESPAWN_TIME (TICRATE/2)
#define AUTORESPAWN_THRESHOLD (TICRATE/4)
@ -126,6 +127,11 @@ extern vector3_t clusterpoint, clusterdtf;
#define FLAMEACCELBOOST CV_Get(&cv_kartstacking_flame_accelboost)
#define FLAMESTACKABLE CV_Get(&cv_kartstacking_flame_stackable)
#define ALTSHRINKTIME CV_Get(&cv_kartaltshrinktime)
#define SHRINKSPEEDBOOST CV_Get(&cv_kartstacking_altshrink_speedboost)
#define SHRINKACCELBOOST CV_Get(&cv_kartstacking_altshrink_accelboost)
#define SHRINKSTACKABLE CV_Get(&cv_kartstacking_altshrink_stackable)
#define STARTSPEEDBOOST CV_Get(&cv_kartstacking_start_speedboost)
#define STARTACCELBOOST CV_Get(&cv_kartstacking_start_accelboost)
#define STARTSTACKABLE CV_Get(&cv_kartstacking_start_stackable)
@ -254,12 +260,14 @@ void K_DoSneaker(player_t *player, INT32 type);
void K_DoPogoSpring(mobj_t *mo, fixed_t vertispeed, UINT8 sound);
fixed_t K_InvincibilityGradient(UINT16 time);
UINT16 K_GetInvincibilityTime(player_t *player);
fixed_t K_GetInvincibilitySpeed(UINT16 time);
fixed_t K_GetInvincibilityAccel(UINT16 time);
void K_DoInvincibility(player_t *player, tic_t time);
void K_KillBananaChain(mobj_t *banana, mobj_t *inflictor, mobj_t *source);
void K_UpdateHnextList(player_t *player, boolean clean);
void K_DropHnextList(player_t *player);
void K_PopPlayerShield(player_t *player);
boolean K_IsBubbleDefending(player_t *player);
boolean K_IsBubbleDefending(const player_t *player);
void K_RemoveBubbleHealth(player_t *player, INT16 sub);
boolean K_CheckBubbleChip(const mobj_t *mobj);
void K_RepairOrbitChain(mobj_t *orbit);
@ -295,6 +303,7 @@ void K_SpawnWaterTrail(mobj_t *mobj);
boolean K_ItemMobjAllowedtoWaterRun(mobj_t *item);
void K_SetTireGrease(player_t *player, tic_t tics);
boolean K_SlopeResistance(const player_t *player);
void K_RemoveGrowShrink(player_t *player);
void K_SquishPlayer(player_t *player, mobj_t *inflictor, mobj_t *source);
void K_ApplyTripWire(player_t *player, tripwirestate_t state);
fixed_t K_GetKartSpeedFromStat(UINT8 kartspeed, boolean karmabomb);
@ -313,8 +322,6 @@ SINT8 K_Sliptiding(const player_t *player);
fixed_t K_PlayerBaseFriction(const player_t *player, fixed_t original);
void K_MoveKartPlayer(player_t *player, boolean onground);
void K_CheckSpectateStatus(boolean considermapreset);
UINT8 K_GetInvincibilityItemFrame(void);
UINT8 K_GetMultItemFrame(UINT8 count, UINT8 max);
boolean K_IsSPBInGame(void);
// sound stuff for lua
@ -344,7 +351,6 @@ boolean K_DraftingActive(void);
boolean K_AirDropActive(void);
boolean K_ItemLitterActive(void);
boolean K_ItemPushingActive(void);
boolean K_GetKartInvinType(void);
INT32 K_GetBumpSpark(void);
boolean K_BoostChain(player_t *player, INT32 timer, boolean chainsound);
INT32 K_ChainOrDeincrementTime(player_t *player, INT32 timer, INT32 deincrement, boolean chainsound);
@ -352,8 +358,6 @@ boolean K_UsingLegacyCheckpoints(void);
boolean K_UsingPatchedMap(void);
INT32 K_CheckpointThreshold(boolean roundup);
void K_UpdateMobjItemOverlay(mobj_t *part, SINT8 itemType, UINT8 itemCount);
fixed_t K_BoostRescale(fixed_t value,fixed_t oldmin,fixed_t oldmax,fixed_t newmin,fixed_t newmax);
void K_DoBoost(player_t *player, fixed_t speedboost, fixed_t accelboost, boolean stack, boolean visible);
void K_ClearBoost(player_t *player);

File diff suppressed because it is too large Load diff

View file

@ -1,72 +0,0 @@
// BLANKART
//-----------------------------------------------------------------------------
// Copyright (C) 2018-2025 by Kart Krew.
// Copyright (C) 2025 by "Anonimus".
// Copyright (C) 2025 Blankart Team.
//
// 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_odds.hpp
/// \brief Kart item odds systems.
#ifndef __K_ODDS__
#define __K_ODDS__
#include "command.h" // Need for player_t
#include "doomdef.h"
#include "doomtype.h"
#include "d_player.h" // Need for player_t
#include "d_ticcmd.h"
#include "m_fixed.h"
#ifdef __cplusplus
extern "C" {
#endif
// Max odds count
#define MAXODDS 16
// Distance variables
#define DISTVAR CV_Get(&cv_kartoddsdist)
#define DISTVAR_LEGACY CV_Get(&cv_kartlegacyoddsdist)
#define SPBDISTVAR CV_Get(&cv_kartspbdist)
#define SPBDISTVAR_LEGACY CV_Get(&cv_kartlegacyspbdist)
extern consvar_t *KartItemCVars[NUMKARTRESULTS-1];
// Goner; tracks how long an item should be "gone" for.
// AKA a time-based cooldown so Hyudoro and whatever else piss off to prevent
// spamming.
typedef enum goner_sect_e {
GONER_BASECOOLDOWN = 0,
GONER_CURRCOOLDOWN = 1,
} goner_sect_t;
extern tic_t ItemBGone[NUMKARTRESULTS][2];
void K_SetBGone(SINT8 item, tic_t time);
void K_SetBGoneToBase(SINT8 item);
tic_t K_GetBGone(SINT8 item, boolean base);
void K_KartHandleShieldCooldown(SINT8 item);
boolean K_LegacyOddsMode(void);
UINT32 K_GetCongaLineDistance(const player_t *player, UINT8 startPos);
UINT32 K_CalculateInitalPDIS(const player_t *player, UINT8 pingame);
UINT32 K_CalculatePDIS(const player_t *player, UINT8 numPlayers, boolean *spbrush);
UINT8 K_FindUseodds(const player_t *player, fixed_t mashed, UINT32 pdis, UINT8 bestbumper, boolean spbrush);
UINT32 K_ScaleItemDistance(UINT32 distance, UINT8 numPlayers, boolean spbrush);
INT32 K_KartGetItemOdds(UINT8 pos, SINT8 item, UINT32 ourDist, UINT32 clusterDist, fixed_t mashed, boolean spbrush, boolean bot, boolean rival, boolean inBottom);
INT32 K_GetRollingRouletteItem(player_t *player);
SINT8 K_ItemResultToType(SINT8 getitem);
UINT8 K_ItemResultToAmount(SINT8 getitem);
void K_KartItemRoulette(player_t *player, ticcmd_t *cmd);
#ifdef __cplusplus
} // extern "C"
#endif
#endif // __K_ODDS__

View file

@ -33,7 +33,7 @@
#include "k_color.h"
#include "k_hud.h"
#include "k_waypoint.h"
#include "k_odds.h"
#include "k_items.h"
#include "d_netcmd.h" // IsPlayerAdmin
#include "m_menu.h" // Player Setup menu color stuff
#include "p_spec.h" // P_StartQuake
@ -1418,7 +1418,7 @@ static int lib_pMovePlayer(lua_State *L)
static int lib_pDoPlayerExit(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
pflags_t flags = luaL_checkinteger(L, 2);
pflags_t flags = lua_isnoneornil(L, 2) ? 0 : luaL_checkinteger(L, 2);
NOHUD
INLEVEL
if (!player)
@ -4026,10 +4026,44 @@ static int lib_kGetKartFlashing(lua_State *L)
static int lib_kGetItemPatch(lua_State *L)
{
UINT8 item = (UINT8)luaL_optinteger(L, 1, KITEM_NONE);
kartitemtype_e item = (kartitemtype_e)luaL_optinteger(L, 1, KITEM_NONE);
boolean tiny = lua_optboolean(L, 2);
//HUDSAFE
lua_pushstring(L, K_GetItemPatch(item, tiny));
// TODO: compatmode KRITEM
const char *sad = tiny ? "K_ISSAD" : "K_ITSAD";
if (item <= 0 || item >= numkartitems)
{
lua_pushstring(L, sad);
return 1;
}
kartitemgraphics_t *graphics = &kartitems[item].graphics[tiny ? 1 : 0];
lua_pushstring(L, graphics->numpatches == 0 ? sad : graphics->patchnames[0]);
return 1;
}
static int lib_kIsKartItemAlternate(lua_State *L)
{
kartitemtype_e item = (kartitemtype_e)luaL_optinteger(L, 1, KITEM_NONE);
// HUDSAFE
if (item <= 0 || item >= numkartitems)
return luaL_error(L, "item number %d out of range (0 - %d)", item, numkartitems-1);
lua_pushboolean(L, K_IsKartItemAlternate(item));
return 1;
}
static int lib_kIsAltShrunk(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
//HUDSAFE
if (!player)
return LUA_ErrInvalid(L, "player_t");
lua_pushboolean(L, K_IsAltShrunk(player));
return 1;
}
@ -4102,7 +4136,7 @@ static int lib_kSetIndirectItemCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
NOHUD
indirectitemcooldown = c;
K_SetIndirectItemCooldown(c);
return 0;
}
@ -4111,48 +4145,10 @@ static int lib_kSetHyuCountdown(lua_State *L)
{
tic_t c = (tic_t)luaL_checkinteger(L, 1);
NOHUD
K_SetBGone(KITEM_HYUDORO, c);
K_GetKartResult("hyudoro")->cooldown = c;
return 0;
}
static int lib_kSetBGone(lua_State *L)
{
SINT8 item = (SINT8)luaL_checkinteger(L, 1);
tic_t c = (tic_t)luaL_checkinteger(L, 2);
NOHUD
if (item < KITEM_SNEAKER || item > (NUMKARTRESULTS - 1))
{
luaL_error(L, "given item ID is outside bgone range");
}
K_SetBGone(item, c);
return 0;
}
static int lib_kSetBGoneToBase(lua_State *L)
{
SINT8 item = (SINT8)luaL_checkinteger(L, 1);
NOHUD
if (item < KITEM_SNEAKER || item > (NUMKARTRESULTS - 1))
{
luaL_error(L, "given item ID is outside bgone range");
}
K_SetBGoneToBase(item);
return 0;
}
static int lib_kGetBGone(lua_State *L)
{
SINT8 item = (SINT8)luaL_checkinteger(L, 1);
boolean base = lua_isnoneornil(L, 2) ? false : luaL_checkboolean(L, 2);
NOHUD
if (item < KITEM_SNEAKER || item > (NUMKARTRESULTS - 1))
{
luaL_error(L, "given item ID is outside bgone range");
}
lua_pushinteger(L, K_GetBGone(item, base));
return 1;
}
// Checks if the floor closet floor under an object would be safe to respawn/land on.
static int lib_kSafeRespawnPosition(lua_State *L)
{
@ -4227,13 +4223,6 @@ static int lib_kItemLitterActive(lua_State *L)
return 1;
}
// Grabs the currently active invintype.
static int lib_kGetKartInvinType(lua_State *L)
{
lua_pushinteger(L, K_GetKartInvinType());
return 1;
}
// Gets the currently active bumpspark type.
static int lib_kGetBumpSpark(lua_State *L)
{
@ -4312,6 +4301,33 @@ static int lib_kGetNewSpeed(lua_State *L)
return 1;
}
static int lib_kInvincibilityGradient(lua_State *L)
{
UINT16 time = (UINT16)luaL_checkinteger(L, 1);
// HUDSAFE
lua_pushinteger(L, K_InvincibilityGradient(time));
return 1;
}
static int lib_kGetInvincibilitySpeed(lua_State *L)
{
UINT16 time = (UINT16)luaL_checkinteger(L, 1);
// HUDSAFE
lua_pushinteger(L, K_GetInvincibilitySpeed(time));
return 1;
}
static int lib_kGetInvincibilityAccel(lua_State *L)
{
UINT16 time = (UINT16)luaL_checkinteger(L, 1);
// HUDSAFE
lua_pushinteger(L, K_GetInvincibilityAccel(time));
return 1;
}
static int lib_k3dKartMovement(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
@ -5053,6 +5069,17 @@ static int lib_kTerrainHasAffect(lua_State *L)
return 1;
}
static int lib_kSetPlayerItemCooldown(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
tic_t c = (tic_t)luaL_checkinteger(L, 2);
boolean force = lua_optboolean(L, 3);
if (!player)
return LUA_ErrInvalid(L, "player_t");
K_SetPlayerItemCooldown(player, c, force);
return 0;
}
static luaL_Reg lib[] = {
{"print", lib_print},
{"chatprint", lib_chatprint},
@ -5337,13 +5364,12 @@ static luaL_Reg lib[] = {
{"K_GetKartAccel",lib_kGetKartAccel},
{"K_GetKartFlashing",lib_kGetKartFlashing},
{"K_GetItemPatch",lib_kGetItemPatch},
{"K_IsKartItemAlternate",lib_kIsKartItemAlternate},
{"K_IsAltShrunk", lib_kIsAltShrunk},
{"K_SetRaceCountdown",lib_kSetRaceCountdown},
{"K_SetExitCountdown",lib_kSetExitCountdown},
{"K_SetIndirectItemCooldown",lib_kSetIndirectItemCountdown},
{"K_SetHyudoroCooldown",lib_kSetHyuCountdown},
{"K_SetBGone", lib_kSetBGone},
{"K_SetBGoneToBase", lib_kSetBGoneToBase},
{"K_GetBGone", lib_kGetBGone},
{"K_SafeRespawnPosition",lib_kSafeRespawnPosition},
{"K_GetCollideAngle",lib_kGetCollideAngle},
@ -5358,13 +5384,15 @@ static luaL_Reg lib[] = {
{"K_AirDropActive",lib_kAirDropActive},
{"K_ItemLitterActive",lib_kItemLitterActive},
{"K_GetBumpSpark",lib_kGetBumpSpark},
{"K_GetKartInvinType",lib_kGetKartInvinType},
{"K_UsingLegacyCheckpoints",lib_kUsingLegacyCheckpoints},
{"K_DoBoost",lib_kDoBoost},
{"K_ClearBoost",lib_kClearBoost},
{"K_BoostChain",lib_kBoostChain},
{"K_ChainOrDeincrementTime",lib_kChainOrDeincrementTime},
{"K_GetNewSpeed", lib_kGetNewSpeed},
{"K_InvincibilityGradient", lib_kInvincibilityGradient},
{"K_GetInvincibilitySpeed", lib_kGetInvincibilitySpeed},
{"K_GetInvincibilityAccel", lib_kGetInvincibilityAccel},
{"K_3dKartMovement", lib_k3dKartMovement},
{"K_MomentumAngle", lib_kMomentumAngle},
{"K_GetKartSpeedFromStat", lib_kGetKartSpeedFromStat},
@ -5435,6 +5463,9 @@ static luaL_Reg lib[] = {
{"K_HandleFootstepParticles", lib_kHandleFootstepParticles},
{"K_UpdateTerrainOverlay", lib_kUpdateTerrainOverlay},
{"K_TerrainHasAffect", lib_kTerrainHasAffect},
// k_items
{"K_SetPlayerItemCooldown", lib_kSetPlayerItemCooldown},
{NULL, NULL}
};

View file

@ -1,4 +1,3 @@
//-----------------------------------------------------------------------------
// Copyright (C) 2012-2016 by John "JTE" Muniz.
// Copyright (C) 2012-2022 by Sonic Team Junior.
@ -40,6 +39,7 @@ automatically.
X (MobjFuse),/* when mobj->fuse runs out */\
X (MobjThinker),/* P_MobjThinker, P_SceneryThinker */\
X (BossThinker),/* P_GenericBossThinker */\
X (MobjScaleChange),/*SRB2KART*/\
X (ShouldDamage),/* P_DamageMobj (Should mobj take damage?) */\
X (ShouldSpin),/* P_DamageMobj (Should mobj take spinout damage?) */\
X (ShouldExplode),/* P_DamageMobj (Should mobj take explosion damage?) */\
@ -86,6 +86,9 @@ automatically.
X (BotJoin),\
X (GPRankPoints),/* K_CalculateGPRankPoints */\
X (AddonLoaded),\
X (PlayerItem),/*SRB2KART*/\
X (KartHyudoro),/*SRB2KART*/\
X (KartSneaker),/*SRB2KART*/\
#define STRING_HOOK_LIST(X) \
X (SpecialExecute),\
@ -171,6 +174,12 @@ int LUA_HookGPRankPoints(UINT8 position, UINT8 numplayers, INT16 *points);
int LUA_HookShouldJingleContinue(player_t *, const char *musname);
int LUA_HookMusicChange(const char *oldname, struct MusicChange *);
// Item shit
boolean LUA_HookPlayerItem(player_t *player, UINT8 itemType, boolean wasHoldingItem, boolean *force);
boolean LUA_HookKartHyudoro(player_t *player, INT32 *target, boolean sink); // SRB2Kart: Hook for K_DoHyudoroSteal and overriding its results.
boolean LUA_HookMobjScaleChange(mobj_t *target, fixed_t newscale, fixed_t oldscale); // SRB2Kart: Hook for P_SetScale.
boolean LUA_HookKartSneaker(player_t *player, int type); // SRB2Kart: Hook for K_DoSneaker.
#ifdef __cplusplus
} // extern "C"
#endif

View file

@ -1260,3 +1260,115 @@ int LUA_HookMusicChange(const char *oldname, struct MusicChange *param)
return hook.status;
}
// Allows to both override default behavior and force action. I don't like it but thats how it works
// in CEP and neptune. Fuckal whyyyyyyyyy
typedef struct {
boolean override;
boolean force;
} TrueForce_State;
static void res_trueforce(Hook_State *hook)
{
TrueForce_State *state = (TrueForce_State*)hook->userdata;
if (lua_isboolean(gL, -2))
state->override = lua_toboolean(gL, -2);
if (lua_isboolean(gL, -1))
state->force = lua_toboolean(gL, -1);
};
boolean LUA_HookPlayerItem(player_t *player, UINT8 itemType, boolean wasHoldingItem, boolean *force)
{
Hook_State hook;
TrueForce_State state = {0};
if (prepare_hook(&hook, 0, HOOK(PlayerItem)))
{
LUA_PushUserdata(gL, player, META_PLAYER);
lua_pushinteger(gL, itemType);
lua_pushboolean(gL, wasHoldingItem);
hook.userdata = &state;
call_hooks(&hook, 2, res_trueforce);
}
*force = state.force;
return state.override;
}
typedef struct {
INT32 *target;
boolean force_sink;
} KartHyudoro_State;
static void res_karthyudoro(Hook_State *hook)
{
KartHyudoro_State *state = (KartHyudoro_State*)hook->userdata;
if (lua_isnumber(gL, -2))
*state->target = lua_tonumber(gL, -2);
else if (lua_isuserdata(gL, -2))
{
player_t *player = *(player_t**)luaL_checkudata(gL, -2, META_PLAYER);
*state->target = player - players;
}
if (lua_isboolean(gL, -1))
state->force_sink = lua_toboolean(gL, -1);
}
boolean LUA_HookKartHyudoro(player_t *player, INT32 *target, boolean sink)
{
Hook_State hook;
KartHyudoro_State state = {0};
state.target = target;
if (prepare_hook(&hook, 0, HOOK(KartHyudoro)))
{
LUA_PushUserdata(gL, player, META_PLAYER);
if (*target >= 0)
LUA_PushUserdata(gL, &players[*target], META_PLAYER);
else
lua_pushnil(gL);
lua_pushboolean(gL, sink);
hook.userdata = &state;
call_hooks(&hook, 2, res_karthyudoro);
}
return state.force_sink;
}
boolean LUA_HookMobjScaleChange(mobj_t *target, fixed_t newscale, fixed_t oldscale)
{
Hook_State hook;
if (prepare_mobj_hook(&hook, false, MOBJ_HOOK(MobjScaleChange), target->type))
{
LUA_PushUserdata(gL, target, META_MOBJ);
lua_pushfixed(gL, newscale);
lua_pushfixed(gL, oldscale);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}
boolean LUA_HookKartSneaker(player_t *player, int type)
{
Hook_State hook;
if (prepare_hook(&hook, false, HOOK(KartSneaker)))
{
LUA_PushUserdata(gL, player, META_PLAYER);
// Type of sneaker: 0 - perfect/panel, 1 - regular sneaker, 2 - rocket sneaker.
lua_pushinteger(gL, type);
call_hooks(&hook, 1, res_true);
}
return hook.status;
}

View file

@ -178,7 +178,8 @@ static const char *const camera_opt[] = {
enum hudpatch {
hudpatch_item = 0,
hudpatch_itemmul
hudpatch_itemmul,
hudpatch_itemalt
};
static const char *const hud_patch_options[] = {
@ -411,6 +412,9 @@ static int libd_getSpritePatch(lua_State *L)
if (i == SPR_PLAY) // Use getSprite2Patch instead!
return 0;
if (i == SPR_ITEM) // Use... uhhhhh...
return 0;
sprdef = &sprites[i];
// set frame number
@ -1184,7 +1188,7 @@ static int libd_getColorHudPatch(lua_State *L)
enum hudpatch option = luaL_checkoption(L, 1, NULL, hud_patch_options);
patch_t *patch;
UINT8 *colormap = R_GetTranslationColormap(TC_DEFAULT, K_GetHudColor(), GTC_CACHE);
boolean small, dark;
boolean small, dark, multi;
switch (option) {
case hudpatch_item:
@ -1198,6 +1202,11 @@ static int libd_getColorHudPatch(lua_State *L)
small = lua_optboolean(L, 2);
patch = K_getItemMulPatch(small);
break;
case hudpatch_itemalt:
small = lua_optboolean(L, 2);
multi = lua_optboolean(L, 3);
patch = K_getItemAltPatch(small, multi);
break;
default:
return 0; // you shouldn't be here
}

View file

@ -249,6 +249,8 @@ enum player_e
player_roulettetype,
player_itemtype,
player_itemamount,
player_itemusecooldown,
player_itemusecooldownmax,
player_throwdir,
player_sadtimer,
player_rings,
@ -285,6 +287,10 @@ enum player_e
player_squishedtimer,
player_rocketsneakertimer,
player_invincibilitytimer,
player_maxinvincibilitytime,
player_invincibilitybottleneck,
player_invincibilitycancel,
player_invincibilitywarning,
player_eggmanexplode,
player_eggmanblame,
player_bananadrag,
@ -453,6 +459,8 @@ static const char *const player_opt[] = {
"roulettetype",
"itemtype",
"itemamount",
"itemusecooldown",
"itemusecooldownmax",
"throwdir",
"sadtimer",
"rings",
@ -489,6 +497,10 @@ static const char *const player_opt[] = {
"squishedtimer",
"rocketsneakertimer",
"invincibilitytimer",
"maxinvincibilitytime",
"invincibilitybottleneck",
"invincibilitycancel",
"invincibilitywarning", // This gets cast to a boolean in Lua.
"eggmanexplode",
"eggmanblame",
"bananadrag",
@ -855,6 +867,12 @@ static int player_get(lua_State *L)
case player_itemamount:
lua_pushinteger(L, plr->itemamount);
break;
case player_itemusecooldown:
lua_pushinteger(L, plr->itemusecooldown);
break;
case player_itemusecooldownmax:
lua_pushinteger(L, plr->itemusecooldownmax);
break;
case player_throwdir:
lua_pushinteger(L, plr->throwdir);
break;
@ -963,6 +981,19 @@ static int player_get(lua_State *L)
case player_invincibilitytimer:
lua_pushinteger(L, plr->invincibilitytimer);
break;
case player_maxinvincibilitytime:
lua_pushinteger(L, plr->maxinvincibilitytime);
break;
case player_invincibilitybottleneck:
// Push as an INT16 due to the negative value signal systems.
lua_pushinteger(L, (INT16)plr->invincibilitybottleneck);
break;
case player_invincibilitycancel:
lua_pushinteger(L, plr->invincibilitycancel);
break;
case player_invincibilitywarning:
lua_pushboolean(L, (boolean)plr->invincibilitywarning);
break;
case player_eggmanexplode:
lua_pushinteger(L, plr->eggmanexplode);
break;
@ -1568,6 +1599,12 @@ static int player_set(lua_State *L)
case player_itemamount:
plr->itemamount = luaL_checkinteger(L, 3);
break;
case player_itemusecooldown:
plr->itemusecooldown = luaL_checkinteger(L, 3);
break;
case player_itemusecooldownmax:
plr->itemusecooldownmax = luaL_checkinteger(L, 3);
break;
case player_throwdir:
plr->throwdir = luaL_checkinteger(L, 3);
break;
@ -1667,14 +1704,34 @@ static int player_set(lua_State *L)
plr->growcancel = luaL_checkinteger(L, 3);
break;
case player_squishedtimer:
plr->squishedtimer = luaL_checkinteger(L, 3);
{
// Unsquish for the ease of Lua programmers
INT16 squishtimer = (INT16)luaL_checkinteger(L, 3);
if (squishtimer == 0)
plr->mo->spriteyscale = FRACUNIT;
plr->squishedtimer = squishtimer;
break;
}
case player_rocketsneakertimer:
plr->rocketsneakertimer = luaL_checkinteger(L, 3);
break;
case player_invincibilitytimer:
plr->invincibilitytimer = luaL_checkinteger(L, 3);
break;
case player_maxinvincibilitytime:
// For most other cases, I'd just say: "it's your funeral". Not for this one.
return NOSET;
case player_invincibilitybottleneck:
plr->invincibilitybottleneck = (UINT16)luaL_checkinteger(L, 3);
break;
case player_invincibilitycancel:
plr->invincibilitycancel = (INT16)luaL_checkinteger(L, 3);
break;
case player_invincibilitywarning:
plr->invincibilitywarning = (UINT8)luaL_checkboolean(L, 3);
break;
case player_eggmanexplode:
plr->eggmanexplode = luaL_checkinteger(L, 3);
break;
@ -2455,8 +2512,14 @@ static int kartstuff_set(lua_State *L)
plr->growshrinktimer = CLAMP(i, INT16_MIN, INT16_MAX);
break;
case k_squishedtimer:
{
// Unsquish for the ease of Lua programmers
if (i == 0)
plr->mo->spriteyscale = FRACUNIT;
plr->squishedtimer = CLAMP(i, INT16_MIN, INT16_MAX);
break;
}
case k_rocketsneakertimer:
plr->rocketsneakertimer = CLAMP(i, 0, UINT16_MAX);
break;

View file

@ -27,7 +27,7 @@
#include "p_slopes.h" // for P_SlopeById and slopelist
#include "p_polyobj.h" // polyobj_t, PolyObjects
#include "k_battle.h"
#include "k_odds.h"
#include "k_items.h"
#include "k_waypoint.h"
#ifdef LUA_ALLOW_BYTECODE
#include "d_netfil.h" // for LUA_DumpFile
@ -417,11 +417,8 @@ int LUA_PushGlobals(lua_State *L, const char *word)
} else if (fastcmp(word,"itempushing")) {
lua_pushboolean(L, itempushing); // hmm... i think this should be a boolean
return 1;
} else if (fastcmp(word,"invintype")) {
lua_pushinteger(L, invintype);
return 1;
} else if (fastcmp(word,"hyubgone")) {
lua_pushinteger(L, K_GetBGone(KITEM_HYUDORO, false));
lua_pushinteger(L, K_GetKartResult("hyudoro")->cooldown);
return 1;
} else if (fastcmp(word,"encoremode")) {
lua_pushboolean(L, encoremode);
@ -436,7 +433,7 @@ int LUA_PushGlobals(lua_State *L, const char *word)
lua_pushinteger(L, wantedcalcdelay);
return 1;
} else if (fastcmp(word,"indirectitemcooldown")) {
lua_pushinteger(L, indirectitemcooldown);
lua_pushinteger(L, K_GetIndirectItemCooldown());
return 1;
} else if (fastcmp(word,"thwompsactive")) {
lua_pushboolean(L, thwompsactive);
@ -562,11 +559,9 @@ int LUA_WriteGlobals(lua_State *L, const char *word)
else if (fastcmp(word,"exitcountdown"))
exitcountdown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"indirectitemcooldown"))
indirectitemcooldown = (tic_t)luaL_checkinteger(L, 2);
K_SetIndirectItemCooldown(luaL_checkinteger(L, 2));
else if (fastcmp(word,"hyubgone"))
{
K_SetBGone(KITEM_HYUDORO, (tic_t)luaL_checkinteger(L, 2));
}
K_GetKartResult("hyudoro")->cooldown = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"starttime"))
starttime = (tic_t)luaL_checkinteger(L, 2);
else if (fastcmp(word,"introtime"))

View file

@ -16,6 +16,8 @@
#define __M_FIXED__
#include "doomtype.h"
#include "doomdef.h"
#ifdef __GNUC__
#include <stdlib.h>
#endif
@ -84,6 +86,53 @@ FUNCMATH FUNCINLINE static ATTRINLINE fixed_t DoubleToFixed(double f)
return (fixed_t)(f * FRACUNIT);
}
/** \brief Converts seconds (in tics) to fixed-point number values; 1 second is 1 fracunit.
\param t (tic_t) time
\return (fixed_t) seconds as fracunits
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t SecsToFixed(tic_t t)
{
return (fixed_t)(((UINT64)t * FRACUNIT) / (TICRATE));
}
/** \brief Converts tens of seconds (in tics) to fixed-point number values; 10 seconds is 1
fracunit.
\param t (tic_t) time
\return (fixed_t) tens of seconds as fracunits
*/
FUNCMATH FUNCINLINE static ATTRINLINE fixed_t SecsToFixedTens(tic_t t)
{
return (fixed_t)(((UINT64)t * FRACUNIT) / (10 * TICRATE));
}
/** \brief 64-bit version of SecsToFixed. Converts seconds (in tics) to fixed-point number values; 1
second is 1 fracunit.
\param t (tic_t) time
\return (sint64_t) seconds as fracunits
*/
FUNCMATH FUNCINLINE static ATTRINLINE INT64 SecsToFixed64(tic_t t)
{
return (INT64)(((UINT64)t * FRACUNIT) / (TICRATE));
}
/** \brief 64-bit version of SecsToFixedTens. Converts tens of seconds (in tics) to fixed-point
number values; 10 seconds is 1 fracunit.
\param t (tic_t) time
\return (sint64_t) tens of seconds as fracunits
*/
FUNCMATH FUNCINLINE static ATTRINLINE INT64 SecsToFixedTens64(tic_t t)
{
return (INT64)(((UINT64)t * FRACUNIT) / (10 * TICRATE));
}
// for backwards compat
#define FIXED_TO_FLOAT(x) FixedToFloat(x) // (((float)(x)) / ((float)FRACUNIT))
#define FLOAT_TO_FIXED(f) FloatToFixed(f) // (fixed_t)((f) * ((float)FRACUNIT))

View file

@ -67,7 +67,7 @@
#include "i_sound.h"
#include "k_hud.h" // SRB2kart
#include "k_kart.h"
#include "k_odds.h" // KartItemCVars
#include "k_items.h" // KartItemCVars
#include "k_pwrlv.h"
#include "k_stats.h" // SRB2kart
#include "d_player.h" // KITEM_ constants
@ -8317,6 +8317,56 @@ INT32 MR_CameraSetup(INT32 arg)
static tic_t shitsfree = 0;
INT32 MR_SetupMonitorToggles(INT32 choice)
{
(void)choice;
const INT32 height = 4;
menu_t *menudef = &menudefs[MN_OP_MONITORTOGGLE];
// in the interest of not rushing the implementation of menu frames...
// leak the memory. every single time.
// (i dont think this actually leaks anything lol)
// (unless someone adds menuitems to this menu for some stupid reason)
menudef->numitems = 0;
for (UINT8 i = 0; i <= numkartresults; i++)
{
kartresult_t *result = i < 3 ? &kartresults[i] : i == 3 ? NULL : &kartresults[i - 1];
if (result != NULL && result->isalt)
continue;
menudef->menuitems = Z_Realloc(menudef->menuitems, sizeof(menuitem_t)*(menudef->numitems+1), PU_STATIC, NULL);
menuitem_t *item = menudef->menuitems + menudef->numitems++;
if (result == NULL)
{
item->argument = 1;
item->patch = "";
}
else
{
item->argument = 0;
item->patch = result->cvar->name;
if (kartitems[result->type].altcvar != NULL)
item->tooltip = "Press BACKSPACE to swap variants.";
else if (result->type == KITEM_SUPERRING && cv_kartrings.value == 0)
item->tooltip = "Rings must be enabled in Gameplay Mods!";
}
}
while (menudef->numitems % height != 0)
{
menudef->menuitems = Z_Realloc(menudef->menuitems, sizeof(menuitem_t)*(menudef->numitems+1), PU_STATIC, NULL);
menuitem_t *item = menudef->menuitems + menudef->numitems++;
item->argument = 2;
item->patch = "";
}
menudef->x = 136 - FixedMul(max(0, min((menudef->numitems - 1) / height, 7)), TICRATE*FRACUNIT/2);
return true;
}
void MD_DrawMonitorToggles(void)
{
const INT32 edges = 4;
@ -8327,8 +8377,18 @@ void MD_DrawMonitorToggles(void)
INT32 leftdraw, rightdraw, totaldraw;
INT32 x = currentMenu->x, y = currentMenu->y+(spacing/4);
INT32 onx = 0, ony = 0;
consvar_t *cv;
INT32 i, translucent, drawnum;
INT32 i, translucent;
const char *displayname;
// INCREDIBLY goofy hack, but I don't wanna have to pass a "use cvar or altenabled"
// flag to literally ALL of the item functions just for the sake of the menu
boolean oldalt[MAXKARTITEMS];
for (i = 0; i < numkartitems; i++)
{
kartitem_t *item = &kartitems[i];
oldalt[i] = item->altenabled;
item->altenabled = item->altcvar != NULL && item->altcvar->value == 1;
}
M_DrawMenuTitle();
@ -8353,7 +8413,7 @@ void MD_DrawMonitorToggles(void)
{
INT32 j;
for (j = 0; j < height; j++)
for (j = 0; j < height; j++, y += spacing)
{
const INT32 thisitem = (i*height)+j;
@ -8364,74 +8424,56 @@ void MD_DrawMonitorToggles(void)
{
onx = x;
ony = y;
y += spacing;
continue;
}
#ifdef ITEMTOGGLEBOTTOMRIGHT
if (currentMenu->menuitems[thisitem].argument == 255)
switch (currentMenu->menuitems[thisitem].argument)
{
case 2:
V_DrawScaledPatch(x, y, V_TRANSLUCENT, W_CachePatchName("K_ISBG", PU_CACHE));
continue;
}
#endif
if (currentMenu->menuitems[thisitem].argument == 0)
{
case 1:
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE));
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISTOGL", PU_CACHE));
continue;
}
cv = KartItemCVars[currentMenu->menuitems[thisitem].argument-1];
translucent = (cv->value ? 0 : V_TRANSLUCENT);
const kartresult_t *result = K_GetKartResult(currentMenu->menuitems[thisitem].patch);
const kartitem_t *item = &kartitems[result->type];
boolean enabled = result->cvar->value == 1;
switch (currentMenu->menuitems[thisitem].argument)
{
case KRITEM_DUALSNEAKER:
case KRITEM_DUALJAWZ:
drawnum = 2;
break;
case KRITEM_TRIPLESNEAKER:
case KRITEM_TRIPLEBANANA:
case KRITEM_TRIPLEORBINAUT:
drawnum = 3;
break;
case KRITEM_QUADORBINAUT:
drawnum = 4;
break;
case KRITEM_TENFOLDBANANA:
drawnum = 10;
break;
default:
drawnum = 0;
break;
}
if (result->type == KITEM_SUPERRING && cv_kartrings.value == 0)
enabled = false;
if (cv->value)
translucent = enabled ? 0 : V_TRANSLUCENT;
if (enabled)
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBG", PU_CACHE));
else
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISBGD", PU_CACHE));
if (drawnum != 0)
if (result->amount >= K_GetItemNumberDisplayMin(result->type, true))
{
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ISMUL", PU_CACHE));
V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].argument, true), PU_CACHE));
V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|translucent, va("x%d", drawnum));
V_DrawScaledPatch(x, y, translucent, K_GetCachedItemPatch(result->type, true, result->amount));
V_DrawString(x+24, y+31, V_ALLOWLOWERCASE|translucent, va("x%d", result->amount));
}
else
V_DrawScaledPatch(x, y, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[thisitem].argument, true), PU_CACHE));
V_DrawScaledPatch(x, y, translucent, K_GetCachedItemPatch(result->type, true, result->amount));
y += spacing;
if (item->altenabled)
V_DrawScaledPatch(x, y, 0, W_CachePatchName("K_ALTITS", PU_CACHE));
}
x += spacing;
y = currentMenu->y+(spacing/4);
}
switch (currentMenu->menuitems[itemOn].argument)
{
#ifdef ITEMTOGGLEBOTTOMRIGHT
if (currentMenu->menuitems[itemOn].argument == 255)
case 2:
{
displayname = "---";
V_DrawScaledPatch(onx-1, ony-2, V_TRANSLUCENT, W_CachePatchName("K_ITBG", PU_CACHE));
if (shitsfree)
{
@ -8442,58 +8484,69 @@ void MD_DrawMonitorToggles(void)
trans = (10-shitsfree)<<V_ALPHASHIFT;
V_DrawScaledPatch(onx-1, ony-2, trans, W_CachePatchName("K_ITFREE", PU_CACHE));
}
break;
}
else
#endif
if (currentMenu->menuitems[itemOn].argument == 0)
case 1:
{
displayname = "Toggle All";
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE));
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITTOGL", PU_CACHE));
break;
}
else
default:
{
cv = KartItemCVars[currentMenu->menuitems[itemOn].argument-1];
translucent = (cv->value ? 0 : V_TRANSLUCENT);
const kartresult_t *result = K_GetKartResult(currentMenu->menuitems[itemOn].patch);
const kartitem_t *item = &kartitems[result->type];
boolean enabled = result->cvar->value == 1;
switch (currentMenu->menuitems[itemOn].argument)
{
case KRITEM_TENFOLDBANANA:
drawnum = 10;
break;
default:
drawnum = 0;
break;
}
if (result->type == KITEM_SUPERRING && cv_kartrings.value == 0)
enabled = false;
if (cv->value)
displayname = result->displayname;
translucent = enabled ? 0 : V_TRANSLUCENT;
if (enabled)
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBG", PU_CACHE));
else
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITBGD", PU_CACHE));
if (drawnum != 0)
if (result->amount >= K_GetItemNumberDisplayMin(result->type, false))
{
V_DrawScaledPatch(onx-1, ony-2, 0, W_CachePatchName("K_ITMUL", PU_CACHE));
V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].argument, false), PU_CACHE));
V_DrawScaledPatch(onx-1, ony-2, translucent, K_GetCachedItemPatch(result->type, false, result->amount));
V_DrawScaledPatch(onx+27, ony+39, translucent, W_CachePatchName("K_ITX", PU_CACHE));
V_DrawKartString(onx+37, ony+34, translucent, va("%d", drawnum));
V_DrawKartString(onx+37, ony+34, translucent, va("%d", result->amount));
}
else
V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName(K_GetItemPatch(currentMenu->menuitems[itemOn].argument, false), PU_CACHE));
V_DrawScaledPatch(onx-1, ony-2, translucent, K_GetCachedItemPatch(result->type, false, result->amount));
if (item->altcvar != NULL)
{
translucent = item->altenabled ? 0 : V_TRANSLUCENT;
V_DrawScaledPatch(onx-1, ony-2, translucent, W_CachePatchName("K_ALTITM", PU_CACHE));
}
break;
}
}
if (shitsfree)
if (renderisnewtic && shitsfree)
shitsfree--;
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, MENUCAPS|highlightflags, va("* %s *", currentMenu->menuitems[itemOn].text));
V_DrawCenteredString(BASEVIDWIDTH/2, currentMenu->y, MENUCAPS|highlightflags, va("* %s *", displayname));
M_DrawMenuTooltips();
for (i = 0; i < numkartitems; i++)
kartitems[i].altenabled = oldalt[i];
}
INT32 MR_HandleMonitorToggles(INT32 choice)
{
const INT32 width = 6, height = 4;
const INT32 height = 4;
const INT32 width = currentMenu->numitems/height;
INT32 column = itemOn/height, row = itemOn%height;
INT16 next;
UINT8 i;
kartresult_t *result = K_GetKartResult(currentMenu->menuitems[itemOn].patch);
switch (choice)
{
@ -8542,8 +8595,7 @@ INT32 MR_HandleMonitorToggles(INT32 choice)
break;
case KEY_ENTER:
#ifdef ITEMTOGGLEBOTTOMRIGHT
if (currentMenu->menuitems[itemOn].argument == 255)
if (currentMenu->menuitems[itemOn].argument == 2)
{
//S_StartSound(NULL, sfx_s26d);
if (!shitsfree)
@ -8552,29 +8604,41 @@ INT32 MR_HandleMonitorToggles(INT32 choice)
S_StartSound(NULL, sfx_itfree);
}
}
else
#endif
if (currentMenu->menuitems[itemOn].argument == 0)
else if (currentMenu->menuitems[itemOn].argument == 1)
{
INT32 v = cv_sneaker.value;
INT32 v = K_ItemResultEnabled(K_GetKartResult("sneaker")) ? 1 : 0;
S_StartSound(NULL, sfx_s1b4);
for (i = 0; i < NUMKARTRESULTS-1; i++)
for (UINT8 i = 0; i < numkartresults; i++)
{
if (KartItemCVars[i]->value == v)
CV_AddValue(KartItemCVars[i], 1);
if (kartresults[i].cvar->value == v)
CV_AddValue(kartresults[i].cvar, 1);
}
}
else
else if (result != NULL)
{
S_StartSound(NULL, sfx_s1ba);
CV_AddValue(KartItemCVars[currentMenu->menuitems[itemOn].argument-1], 1);
if (result->type == KITEM_SUPERRING && cv_kartrings.value == 0)
{
S_StartSound(NULL, sfx_s231);
}
else
{
S_StartSound(NULL, sfx_s1ba);
CV_AddValue(result->cvar, 1);
}
}
break;
case KEY_BACKSPACE:
if (result != NULL && kartitems[result->type].altcvar != NULL)
{
S_StartSound(NULL, sfx_s3kb7);
CV_AddValue(kartitems[result->type].altcvar, 1);
}
break;
default:
return false;
}
return true;
}

View file

@ -323,6 +323,7 @@ INT32 MR_HandleMusicTest(INT32 choice);
INT32 MR_ResetControls(INT32 choice);
INT32 MR_ChangeControl(INT32 arg);
INT32 MR_AssignJoystick(INT32 arg);
INT32 MR_SetupMonitorToggles(INT32 choice);
INT32 MR_HandleMonitorToggles(INT32 choice);
INT32 MR_RestartAudio(INT32 choice);
INT32 MR_EnterViewServer(INT32 choice);

View file

@ -30,6 +30,7 @@
#include "k_waypoint.h"
#include "k_battle.h"
#include "k_collide.h"
#include "k_items.h"
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -10838,7 +10839,7 @@ void A_ItemPop(void *thing)
if (!((gametyperules & GTR_BUMPERS) && actor->target->player->bumper <= 0) && !itembreaker)
{
actor->target->player->itemroulette = KROULETTE_ACTIVE;
K_StartRoulette(actor->target->player, KROULETTETYPE_NORMAL);
}
else if (itembreaker)
{

View file

@ -39,7 +39,7 @@
#include "k_boss.h"
#include "p_spec.h"
#include "k_objects.h"
#include "k_odds.h"
#include "k_items.h"
#include "acs/interface.h"
// CTF player names
@ -147,7 +147,7 @@ boolean P_CanPickupItem(player_t *player, UINT8 weapon)
if (player->stealingtimer || player->stolentimer
|| player->rocketsneakertimer
|| player->eggmanexplode
|| ((K_GetKartInvinType() == KARTINVIN_ALTERN) && (player->invincibilitytimer))
|| ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (player->invincibilitytimer))
|| (player->growshrinktimer > 0)
|| player->flametimer)
return false;
@ -459,8 +459,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
special->target->player->karmadelay = comebacktime;
player->itemroulette = KROULETTE_ACTIVE;
player->roulettetype = KROULETTETYPE_KARMA;
K_StartRoulette(player, KROULETTETYPE_KARMA);
}
else if (special->target->player->karmamode == 2 && P_CanPickupItem(player, 2))
{
@ -495,11 +494,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
special->target->player->karmadelay = comebacktime;
K_DropItems(player); //K_StripItems(player);
//K_StripOther(player);
player->itemroulette = KROULETTE_ACTIVE;
player->roulettetype = KROULETTETYPE_EGGMAN;
K_StartRoulette(player, KROULETTETYPE_EGGMAN);
if (special->target->player->eggmanblame >= 0
&& special->target->player->eggmanblame < MAXPLAYERS
@ -591,8 +586,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
if (special->fuse || !P_CanPickupItem(player, 1) || ((gametyperules & GTR_BUMPERS) && player->bumper <= 0))
return;
player->itemroulette = KROULETTE_ACTIVE;
player->roulettetype = KROULETTETYPE_KARMA;
K_StartRoulette(player, KROULETTETYPE_KARMA);
// Karma fireworks
for (i = 0; i < 5; i++)
@ -1742,25 +1736,7 @@ void P_KillMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 damaget
break;
}
if (target->threshold < 1 || target->threshold >= NUMKARTITEMS) // bruh moment prevention
{
player->itemtype = KITEM_SAD;
player->itemamount = 1;
}
else
{
player->itemtype = target->threshold;
if (K_GetShieldFromPlayer(player) != KSHIELD_NONE) // never give more than 1 shield
player->itemamount = 1;
else
player->itemamount = max(1, target->movecount);
}
player->itemblink = TICRATE;
player->itemblinkmode = KITEMBLINKMODE_NORMAL;
player->itemroulette = KROULETTE_DISABLED;
player->roulettetype = KROULETTETYPE_NORMAL;
if (P_IsDisplayPlayer(player))
S_StartSound(NULL, sfx_itrolf);
K_AwardPlayerItem(player, target->threshold, max(1, target->movecount), KITEMBLINK_NORMAL);
}
break;
}

View file

@ -15,6 +15,7 @@
#include "d_netcmd.h"
#include "d_think.h"
#include "dehacked.h"
#include "deh_tables.h"
#include "doomdef.h"
#include "doomstat.h"
#include "doomtype.h"
@ -51,7 +52,7 @@
#include "k_terrain.h"
#include "k_collide.h"
#include "k_objects.h"
#include "k_odds.h"
#include "k_items.h"
#include "k_waypoint.h"
// BlanKart
@ -1228,6 +1229,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
case MT_EGGMANITEM:
case MT_SSMINE:
case MT_LANDMINE:
// case MT_EGGMINE_CAPSULE:
case MT_SINK:
if (mo->extravalue2 > 0)
{
@ -4164,8 +4166,8 @@ static void P_RefreshItemCapsuleParts(mobj_t *mobj)
mobj_t *part;
UINT32 newRenderFlags = 0;
if (itemType < 1 || itemType >= NUMKARTITEMS)
itemType = KITEM_SAD;
if (itemType < 1 || itemType >= numkartitems)
itemType = MAXKARTITEMS;
part = mobj;
while (!P_MobjWasRemoved(part->hnext))
@ -4185,40 +4187,8 @@ static void P_RefreshItemCapsuleParts(mobj_t *mobj)
K_UpdateMobjItemOverlay(part, itemType, mobj->movecount);
// update number frame
if (K_GetShieldFromItem(itemType) != KSHIELD_NONE) // shields don't stack, so don't show a number
;
else
{
switch (itemType)
{
case KITEM_SNEAKER:
if (mobj->movecount - 1 > K_GetMultItemFrame(mobj->movecount, 2))
count = mobj->movecount;
break;
case KITEM_ORBINAUT: // only display the number when the sprite no longer changes
if (mobj->movecount - 1 > K_GetMultItemFrame(mobj->movecount, 3))
count = mobj->movecount;
break;
case KITEM_BANANA: // only display the number when the sprite no longer changes
if (mobj->movecount - 1 > K_GetMultItemFrame(mobj->movecount, 3))
count = mobj->movecount;
break;
case KITEM_JAWZ: // only display the number when the sprite no longer changes
if (mobj->movecount - 1 > K_GetMultItemFrame(mobj->movecount, 1))
count = mobj->movecount;
break;
case KITEM_SUPERRING: // always display the number, and multiply it by 5
count = mobj->movecount * 5;
break;
case KITEM_SAD: // never display the number
case KITEM_SPB:
break;
default:
if (mobj->movecount > 1)
count = mobj->movecount;
break;
}
}
if (mobj->movecount >= K_GetItemNumberDisplayMin(itemType, false))
count = mobj->movecount;
while (count > 0)
{
@ -6192,6 +6162,9 @@ void P_SetScale2(mobj_t *mobj, fixed_t newscale, boolean compat)
oldscale = mobj->scale; //keep for adjusting stuff below
if (LUA_HookMobjScaleChange(mobj, newscale, oldscale) || P_MobjWasRemoved(mobj))
return;
mobj->scale = newscale;
if (compat)
@ -6513,6 +6486,7 @@ boolean P_IsKartFieldItem(INT32 type)
case MT_JAWZ_DUD:
case MT_SSMINE:
case MT_LANDMINE:
// case MT_EGGMINE_CAPSULE:
case MT_BALLHOG:
case MT_BUBBLESHIELDTRAP:
case MT_SINK:
@ -7408,6 +7382,19 @@ static void P_MobjSceneryThink(mobj_t *mobj)
return;
}
break;
case MT_BUBBLESHIELD_DEBRIS:
mobj->rollangle += ANG1 * 4;
if (P_IsObjectOnGround(mobj) && mobj->health > 0)
{
// "Despawn" and play the glass landing sound.
if (mobj->extravalue1 == 0)
S_StartSoundAtVolume(mobj, mobj->info->deathsound, 192);
P_KillMobj(mobj, NULL, NULL, DMG_NORMAL);
mobj->fuse = TICRATE;
}
goto dofuse;
case MT_SMOLDERING:
if (leveltime % 2 == 0)
{
@ -7607,101 +7594,79 @@ static void P_MobjSceneryThink(mobj_t *mobj)
if (!(mobj->renderflags & RF_DONTDRAW))
{
const INT32 numberdisplaymin = ((mobj->target->player->itemtype == KITEM_ORBINAUT) ? 5 : 2);
statenum_t statenum = S_PLAYERARROW_BOX;
kartitemtype_e itemtype = mobj->target->player->itemtype;
UINT8 itemamount = 0;
boolean hide = false;
// Set it to use the correct states for its condition
if (mobj->target->player->itemroulette)
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = K_GetRollingRouletteItem(mobj->target->player) | FF_FULLBRIGHT;
mobj->tracer->renderflags &= ~RF_DONTDRAW;
itemtype = K_GetRollingRouletteItem(mobj->target->player);
}
else if (mobj->target->player->stealingtimer < 0)
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO;
if (leveltime & 2)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
itemtype = KITEM_HYUDORO;
hide = leveltime & 2;
}
else if ((mobj->target->player->stealingtimer > 0) && (leveltime & 2))
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_HYUDORO;
mobj->tracer->renderflags &= ~RF_DONTDRAW;
itemtype = KITEM_HYUDORO;
}
else if (mobj->target->player->eggmanexplode > 1)
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_EGGMAN;
if (leveltime & 1)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
itemtype = KITEM_EGGMAN;
hide = leveltime & 1;
}
else if (mobj->target->player->rocketsneakertimer > 1)
{
//itembar = mobj->target->player->rocketsneakertimer; -- not today satan
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_ROCKETSNEAKER;
if (leveltime & 1)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
itemtype = KITEM_ROCKETSNEAKER;
hide = leveltime & 1;
}
else if (mobj->target->player->flametimer > 1)
{
//itembar = mobj->target->player->flametimer; -- not today satan
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_FLAMESHIELD;
if (leveltime & 1)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
itemtype = KITEM_FLAMESHIELD;
hide = leveltime & 1;
}
else if (mobj->target->player->growshrinktimer > 0)
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
mobj->tracer->sprite = SPR_ITEM;
mobj->tracer->frame = FF_FULLBRIGHT|KITEM_GROW;
if (leveltime & 1)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
itemtype = KITEM_GROW;
hide = leveltime & 1;
}
else if (mobj->target->player->itemtype && mobj->target->player->itemamount > 0)
{
P_SetMobjState(mobj, S_PLAYERARROW_BOX);
itemtype = mobj->target->player->itemtype;
itemamount = mobj->target->player->itemamount;
hide = mobj->target->player->itemflags & IF_ITEMOUT && leveltime & 1;
}
else
{
statenum = S_PLAYERARROW;
}
K_UpdateMobjItemOverlay(mobj->tracer, mobj->target->player->itemtype,mobj->target->player->itemamount);
if (mobj->target->player->itemflags & IF_ITEMOUT)
{
if (leveltime & 1)
mobj->tracer->renderflags &= ~RF_DONTDRAW;
else
mobj->tracer->renderflags |= RF_DONTDRAW;
}
P_SetMobjState(mobj, statenum);
if (statenum == S_PLAYERARROW_BOX)
{
mobj->tracer->sprite = SPR_ITEM;
K_UpdateMobjItemOverlay(mobj->tracer, itemtype, itemamount);
mobj->tracer->threshold = itemtype; // sorry, i have to
mobj->tracer->frame &= ~FF_PAPERSPRITE;
if (hide)
mobj->tracer->renderflags |= RF_DONTDRAW;
else
mobj->tracer->renderflags &= ~RF_DONTDRAW;
}
else
{
P_SetMobjState(mobj, S_PLAYERARROW);
P_SetMobjState(mobj->tracer, S_PLAYERARROW_ITEM);
mobj->tracer->renderflags &= ~RF_DONTDRAW;
}
mobj->tracer->destscale = scale;
if (mobj->target->player->itemamount >= numberdisplaymin
if (mobj->target->player->itemamount >= K_GetItemNumberDisplayMin(mobj->target->player->itemtype, false)
&& mobj->target->player->itemamount <= 10) // Meh, too difficult to support greater than this; convert this to a decent HUD object and then maybe :V
{
mobj_t *number = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_OVERLAY);
@ -7717,6 +7682,10 @@ static void P_MobjSceneryThink(mobj_t *mobj)
P_SetMobjState(numx, S_PLAYERARROW_X);
P_SetScale(numx, mobj->scale);
numx->destscale = scale;
// ugh... overlays....
number->old_z = number->z += FixedMul(number->state->var2 * FRACUNIT, mobj->scale);
numx->old_z = numx->z += FixedMul(number->state->var2 * FRACUNIT, mobj->scale);
}
if (K_IsPlayerWanted(mobj->target->player) && mobj->movecount != 1)
@ -7847,6 +7816,7 @@ static void P_MobjSceneryThink(mobj_t *mobj)
}
/* FALLTHRU */
default:
dofuse:
if (mobj->fuse)
{ // Scenery object fuse! Very basic!
mobj->fuse--;
@ -8013,6 +7983,7 @@ static boolean P_MobjDeadThink(mobj_t *mobj)
case MT_BANANA:
case MT_EGGMANITEM:
case MT_LANDMINE:
// case MT_EGGMINE_CAPSULE:
case MT_SPB:
if (P_IsObjectOnGround(mobj))
{
@ -8440,11 +8411,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
}
if (mobj->threshold == KITEM_SPB || mobj->threshold == KITEM_SHRINK)
{
indirectitemcooldown = 20*TICRATE;
}
K_UpdateMobjItemOverlay(mobj, mobj->threshold, mobj->movecount);
break;
}
@ -8480,12 +8446,10 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
|| mobj->movecount != part->movecount) // change the capsule properties if the item type or amount is updated
P_RefreshItemCapsuleParts(mobj);
// animate invincibility capsules
K_UpdateMobjItemOverlay(part, mobj->threshold, mobj->movecount);
if (mobj->threshold == KITEM_INVINCIBILITY)
{
mobj->color = K_RainbowColor(leveltime);
part->frame = FF_FULLBRIGHT|FF_PAPERSPRITE|K_GetInvincibilityItemFrame();
}
}
break;
case MT_ORBINAUT:
@ -8715,8 +8679,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->threshold--;
break;
case MT_SPB:
indirectitemcooldown = 20*TICRATE;
/* FALLTHRU */
case MT_BALLHOG:
{
mobj_t *ghost = P_SpawnGhostMobj(mobj);
@ -8805,6 +8767,11 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (mobj->threshold > 0)
mobj->threshold--;
break;
// case MT_EGGMINE_CAPSULE:
// todo
// decrement fuse while on ground
// when fuse runs out pop open and spawn a land mine
break;
case MT_SPBEXPLOSION:
mobj->health--;
break;
@ -9218,18 +9185,17 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
for (i = 0; i < 2; i++)
{
angle_t a = mobj->angle + ((i & 1) ? ANGLE_180 : 0);
fixed_t ws = player->mo->scale/4 + scale/4;
mobj_t *wave;
wave = P_SpawnMobj(
(player->mo->x - player->mo->momx) + P_ReturnThrustX(NULL, a, mobj->radius - (21*ws)),
(player->mo->y - player->mo->momy) + P_ReturnThrustY(NULL, a, mobj->radius - (21*ws)),
(player->mo->x - player->mo->momx) + P_ReturnThrustX(NULL, a, mobj->radius - (5*scale)),
(player->mo->y - player->mo->momy) + P_ReturnThrustY(NULL, a, mobj->radius - (5*scale)),
(player->mo->z - player->mo->momz), MT_THOK);
wave->colorized = true;
wave->color = SKINCOLOR_BLUE;
wave->flags &= ~(MF_NOCLIPHEIGHT|MF_NOGRAVITY);
P_SetScale(wave, (wave->destscale = ws));
P_SetScale(wave, (wave->destscale = scale/3));
P_SetMobjState(wave, S_SPLISH1);
@ -9300,45 +9266,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
mobj->flags |= MF_NOCLIP|MF_NOCLIPTHING;
break;
}
case MT_BUBBLESHLD_DEBRIS:
{
statenum_t curstate;
curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states)));
if (curstate != S_INVISIBLE)
{
mobj->rollangle += ANG1 * 4;
}
else
{
mobj->rollangle = 0;
}
if ((P_IsObjectOnGround(mobj)) && (!mobj->threshold))
{
mobj->threshold = (TICRATE / 2);
if (curstate != S_INVISIBLE)
{
// "Despawn" and play the glass landing sound.
if (mobj->extravalue1 == 0)
S_StartSoundAtVolume(mobj, mobj->info->activesound, 128);
P_SetMobjState(mobj, S_INVISIBLE);
}
}
if (mobj->threshold)
{
mobj->threshold--;
if (!mobj->threshold)
{
P_RemoveMobj(mobj);
}
}
break;
}
case MT_FLAMESHIELD:
{
statenum_t curstate;
@ -10926,6 +10853,8 @@ static void P_DefaultMobjShadowScale(mobj_t *thing)
case MT_SSMINE:
case MT_SSMINE_SHIELD:
case MT_LANDMINE:
// case MT_EGGMINE_CAPSULE:
// case MT_EGGMINE_SHIELD:
case MT_BALLHOG:
case MT_SINK:
case MT_ROCKETSNEAKER:
@ -11352,7 +11281,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
P_SetTarget(&spawn->target, mobj);
break;
}
case MT_BUBBLESHLD_DEBRIS:
case MT_BUBBLESHIELD_DEBRIS:
{
statenum_t shardset[] = {S_BUBBLEDEBRIS_1, S_BUBBLEDEBRIS_2, S_BUBBLEDEBRIS_3, S_BUBBLEDEBRIS_4, S_BUBBLEDEBRIS_5};
P_SetMobjState(mobj, shardset[P_RandomRange(0, 4)]);
@ -11370,7 +11299,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
else if (P_RandomChance(FRACUNIT/3))
mobj->threshold = KITEM_ORBINAUT;
else
mobj->threshold = P_RandomRange(1, NUMKARTITEMS - 1);
mobj->threshold = P_RandomRange(1, numkartitems - 1);
mobj->movecount = P_RandomChance(FRACUNIT/3) ? 1 : P_RandomKey(32) + 1;
#else
mobj->threshold = KITEM_SUPERRING; // default item is super ring
@ -12787,7 +12716,7 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
}
case MT_ITEMCAPSULE:
{
boolean isRingCapsule = (mthing->args[0] < 1 || mthing->args[0] == KITEM_SUPERRING || mthing->args[0] >= NUMKARTITEMS);
boolean isRingCapsule = mthing->args[0] < 1 || mthing->args[0] == KITEM_SUPERRING || mthing->args[0] >= numkartitems;
// don't spawn ring capsules in with rings off.
if (isRingCapsule && (K_RingsActive() == false))
@ -13645,9 +13574,39 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
if (!P_IsObjectOnGround(mobj))
mobj->flags |= MF_NOGRAVITY;
// Angle = item type
if (mthing->args[0] > 0 && mthing->args[0] < NUMKARTITEMS)
mobj->threshold = mthing->args[0];
// Item type
static kartitemtype_e rrtypes[] = {
KITEM_SNEAKER,
KITEM_ROCKETSNEAKER,
KITEM_INVINCIBILITY,
KITEM_BANANA,
KITEM_EGGMAN,
KITEM_ORBINAUT,
KITEM_JAWZ,
KITEM_MINE,
MAXKARTITEMS, // LANDMINE
KITEM_BALLHOG,
KITEM_SPB,
KITEM_GROW,
KITEM_SHRINK,
KITEM_THUNDERSHIELD,
KITEM_BUBBLESHIELD,
KITEM_FLAMESHIELD,
KITEM_HYUDORO,
KITEM_POGOSPRING,
KITEM_SUPERRING,
KITEM_KITCHENSINK,
MAXKARTITEMS, // DROPTARGET
MAXKARTITEMS, // GARDENTOP
MAXKARTITEMS, // GACHABOM
MAXKARTITEMS, // STONESHOE
MAXKARTITEMS, // TOXOMISTER
};
if (mthing->stringargs[0] != NULL)
mobj->threshold = DEH_FindKartItem(mthing->stringargs[0]);
else if (mapnamespace == MNS_RINGRACERS && mthing->args[0] > 0 && (size_t)mthing->args[0] < sizeof(rrtypes)/sizeof(*rrtypes))
mobj->threshold = rrtypes[mthing->args[0] - 1];
// Parameter = extra items (x5 for rings)
mobj->movecount += mthing->args[1];

View file

@ -41,7 +41,7 @@
#include "k_battle.h"
#include "k_pwrlv.h"
#include "k_terrain.h"
#include "k_odds.h"
#include "k_items.h"
#include "acs/interface.h"
#include "g_party.h"
#include "k_waypoint.h"
@ -776,6 +776,9 @@ static void P_NetSyncPlayers(savebuffer_t *save)
// Wall Transfer bonus
SYNCBOOLEAN(players[i].walltransfered);
SYNC(players[i].walltransferboost);
SYNC(players[i].itemusecooldown);
SYNC(players[i].itemusecooldownmax);
}
TracyCZoneEnd(__zone);
}
@ -3939,6 +3942,10 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending)
SYNC(gametype);
#if MAXPLAYERS > 32
#error Update playeringame syncing please
#endif
if (save->write)
{
UINT32 pig = 0;
@ -4182,7 +4189,6 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending)
SYNCBOOLEAN(itemlittering);
SYNCBOOLEAN(itempushing);
SYNC(bumpsparkactive);
SYNC(invintype);
SYNC(antibumptime);
for (i = 0; i < sizeof(votelevels)/sizeof(*votelevels); i++)
@ -4267,14 +4273,12 @@ static boolean P_NetSyncMisc(savebuffer_t *save, boolean resending)
SYNC(battlewanted[i]);
SYNC(wantedcalcdelay);
SYNC(indirectitemcooldown);
for (i = 0; i < NUMKARTRESULTS; i++)
{
// hyubgone
//SYNC(ItemBGone[i][GONER_BASECOOLDOWN]);
SYNC(ItemBGone[i][GONER_CURRCOOLDOWN]);
}
for (i = 0; i < numkartitems; i++)
SYNC(kartitems[i].altenabled);
for (i = 0; i < numkartresults; i++)
SYNC(kartresults[i].cooldown);
SYNC(mapreset);

View file

@ -103,7 +103,7 @@
#include "k_terrain.h" // TRF_TRIPWIRE
#include "k_brightmap.h"
#include "k_director.h" // K_InitDirector
#include "k_odds.h" // ItemBGone
#include "k_items.h"
#include "acs/interface.h"
#include "doomstat.h" // MAXMUSNAMES
#include "k_mapuser.h"
@ -8071,7 +8071,6 @@ static void P_InitLevelSettings(boolean reloadinggamestate)
itempushing = true;
bumpsparkactive = (UINT8)cv_kartbumpspark.value;
invintype = (UINT8)cv_kartinvintype.value;
antibumptime = (tic_t)cv_kartantibump.value * TICRATE;
@ -8398,13 +8397,8 @@ static void P_InitGametype(void)
numlaps = K_RaceLapCount(gamemap - 1);
wantedcalcdelay = wantedfrequency*2;
indirectitemcooldown = 0;
for (i = 0; i < NUMKARTRESULTS; i++)
{
// hyubgone
ItemBGone[i][GONER_CURRCOOLDOWN] = 0;
}
K_SetupItemOdds();
mapreset = 0;

View file

@ -45,6 +45,7 @@
// SRB2kart
#include "k_kart.h"
#include "k_items.h"
#include "console.h" // CON_LogMessage
#include "k_terrain.h"
#include "acs/interface.h"
@ -9222,7 +9223,8 @@ boolean P_AllowFriction(mobj_t *mobj)
if (mobj->player->invincibilitytimer
|| mobj->player->hyudorotimer
|| mobj->player->sneakertimer
|| mobj->player->growshrinktimer > 0)
|| mobj->player->growshrinktimer > 0
|| K_IsAltShrunk(mobj->player))
return false;
return true;

View file

@ -42,7 +42,7 @@
#include "k_director.h"
#include "acs/interface.h"
#include "k_bot.h" // K_BotTicker
#include "k_odds.h" // ItemBGone
#include "k_items.h" // ItemBGone
#include "k_specialstage.h"
#ifdef PARANOIA
@ -897,25 +897,7 @@ void P_Ticker(boolean run)
if (exitcountdown > 1)
exitcountdown--;
if (indirectitemcooldown > 0)
indirectitemcooldown--;
for (i = 0; i < NUMKARTRESULTS; i++)
{
// hyubgone
if (K_GetBGone(i, false) > 0)
{
ItemBGone[i][GONER_CURRCOOLDOWN]--;
}
}
if (gametyperules & GTR_RACEODDS)
{
// Shield cooldowns
K_KartHandleShieldCooldown(KITEM_THUNDERSHIELD);
K_KartHandleShieldCooldown(KITEM_BUBBLESHIELD);
K_KartHandleShieldCooldown(KITEM_FLAMESHIELD);
}
K_UpdateItemCooldown();
K_BossInfoTicker();

View file

@ -61,7 +61,7 @@
#include "k_terrain.h" // K_SpawnSplashForMobj
#include "k_color.h"
#include "k_follower.h"
#include "k_odds.h"
#include "k_items.h"
#include "g_party.h"
#include "acs/interface.h"
@ -831,6 +831,9 @@ void P_RestoreMusic(player_t *player)
{ wantedmus = 1; bestlocaltimer = players[p].growshrinktimer; } \
else if (players[p].invincibilitytimer > bestlocaltimer) \
{ wantedmus = 2; bestlocaltimer = players[p].invincibilitytimer; } \
else if ((K_IsKartItemAlternate(KITEM_SHRINK)) && \
(K_GetShrinkTime(&players[p]) > bestlocaltimer)) \
{ wantedmus = 3; bestlocaltimer = K_GetShrinkTime(&players[p]); } \
}
setbests(localplayertable[0]);
setbests(localplayertable[1]);
@ -848,6 +851,9 @@ void P_RestoreMusic(player_t *player)
wantedmus = 1;
else if (player->invincibilitytimer > 1)
wantedmus = 2;
else if ((K_IsKartItemAlternate(KITEM_SHRINK)) &&
(K_GetShrinkTime(player) > 1))
wantedmus = 3;
}
}
@ -864,6 +870,12 @@ void P_RestoreMusic(player_t *player)
S_ChangeMusicInternal("kinvnc", true);
S_SetRestoreMusicFadeInCvar(&cv_invincmusicfade);
}
// Item - Shrink (Alternative)
else if ((wantedmus == 3) && cv_altshrinkmusic.value == 1)
{
S_ChangeMusicInternal("kshrnk", true);
S_SetRestoreMusicFadeInCvar(&cv_altshrinkmusicfade);
}
else
{
#if 0
@ -2286,7 +2298,7 @@ void P_MovePlayer(player_t *player)
if ((player->invincibilitytimer > 0) &&
(((leveltime %
max(1, 10 - FixedMul(9, K_InvincibilityGradient(player->invincibilitytimer)))) == 0) ||
(K_GetKartInvinType() == KARTINVIN_LEGACY)))
(!K_IsKartItemAlternate(KITEM_INVINCIBILITY))))
{
K_SpawnSparkleTrail(player->mo);
}
@ -2483,7 +2495,7 @@ void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius)
if (mo->type == MT_SPB) // If you destroy a SPB, you don't get the luxury of a cooldown.
{
spbplace = -1;
indirectitemcooldown = 0;
K_SetIndirectItemCooldown(0);
}
if (mo->flags & MF_BOSS) //don't OHKO bosses nor players!

View file

@ -140,6 +140,7 @@ static CV_PossibleValue_t fov_cons_t[] = {{60*FRACUNIT, "MIN"}, {179*FRACUNIT, "
static CV_PossibleValue_t translucenthud_cons_t[] = {{0, "MIN"}, {10, "MAX"}, {0, NULL}};
static CV_PossibleValue_t maxportals_cons_t[] = {{0, "MIN"}, {12, "MAX"}, {0, NULL}}; // lmao rendering 32 portals, you're a card
static CV_PossibleValue_t homremoval_cons_t[] = {{0, "No"}, {1, "Yes"}, {2, "Flash"}, {0, NULL}};
static CV_PossibleValue_t secbright_cons_t[] = {{0, "MIN"}, {255, "MAX"}, {0, NULL}};
static void Fov_OnChange(void);
@ -182,6 +183,8 @@ consvar_t cv_fov[MAXSPLITSCREENPLAYERS] = {
// Okay, whoever said homremoval causes a performance hit should be shot.
consvar_t cv_homremoval = CVAR_INIT ("homremoval", "Yes", CV_SAVE, homremoval_cons_t, NULL);
consvar_t cv_secbright = CVAR_INIT ("r_secbright", "0", CV_SAVE, secbright_cons_t, NULL);
consvar_t cv_maxportals = CVAR_INIT ("maxportals", "2", CV_SAVE, maxportals_cons_t, NULL);
consvar_t cv_renderstats = CVAR_INIT ("renderstats", "Off", 0, CV_OnOff, NULL);
@ -1780,6 +1783,7 @@ void R_RegisterEngineStuff(void)
CV_RegisterVar(&cv_shadow);
CV_RegisterVar(&cv_skybox);
CV_RegisterVar(&cv_ffloorclip);
CV_RegisterVar(&cv_secbright);
for (i = 0; i < MAXSPLITSCREENPLAYERS; i++)
{

View file

@ -154,6 +154,7 @@ extern consvar_t cv_fov[MAXSPLITSCREENPLAYERS];
extern consvar_t cv_skybox;
extern consvar_t cv_tailspickup;
extern consvar_t cv_debugfinishline;
extern consvar_t cv_secbright;
extern consvar_t cv_sloperoll;
extern consvar_t cv_sliptidetilt;

View file

@ -18,6 +18,7 @@
#include "p_tick.h"
#include "typedef.h"
#include "r_fps.h"
#include "k_items.h"
#ifdef ROTSPRITE
fixed_t rollcosang[ROTANGLES];
@ -84,7 +85,7 @@ static angle_t R_PlayerSpriteRotation(player_t *player, player_t *viewPlayer)
// Hacky boolean to check if we're the rainbow Invincibility overlay
boolean R_IsOverlayingInvinciblePlayer(mobj_t* mobj)
{
return ((K_GetKartInvinType() == KARTINVIN_ALTERN) && (mobj->type == MT_OVERLAY) &&
return ((K_IsKartItemAlternate(KITEM_INVINCIBILITY)) && (mobj->type == MT_OVERLAY) &&
(mobj->target) && (mobj->extravalue2) && (mobj->target->player) &&
(mobj->target->player->invincibilitytimer));
}

View file

@ -1038,7 +1038,7 @@ void R_DrawSinglePlane(drawspandata_t *ds, visplane_t *pl, boolean allow_paralle
spanfunctype = SPANDRAWFUNC_SPLAT;
if (pl->polyobj->translucency == 0 || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG)))
light = (pl->lightlevel >> LIGHTSEGSHIFT);
light = std::max((pl->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
else
light = LIGHTLEVELS-1;
}
@ -1079,16 +1079,17 @@ void R_DrawSinglePlane(drawspandata_t *ds, visplane_t *pl, boolean allow_paralle
}
if ((spanfunctype == SPANDRAWFUNC_SPLAT) || (pl->extra_colormap && (pl->extra_colormap->flags & CMF_FOG)))
light = (pl->lightlevel >> LIGHTSEGSHIFT);
light = std::max((pl->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
else
light = LIGHTLEVELS-1;
}
else if (pl->ffloor->fofflags & FOF_FOG)
{
spanfunctype = SPANDRAWFUNC_FOG;
light = (pl->lightlevel >> LIGHTSEGSHIFT);
light = std::max((pl->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
}
else light = (pl->lightlevel >> LIGHTSEGSHIFT);
else
light = std::max((pl->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
debug = SW_HI_FOFPLANES;
}
@ -1147,6 +1148,8 @@ void R_DrawSinglePlane(drawspandata_t *ds, visplane_t *pl, boolean allow_paralle
vidwidth, vidwidth);
}
}
else
light = std::max((pl->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
}
ds->currentplane = pl;

View file

@ -274,7 +274,7 @@ static void R_RenderMaskedSegLoop(drawcolumndata_t* dc, drawseg_t *drawseg, INT3
if ((R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == false)
|| (rlight->flags & FOF_FOG)
|| (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((rlight->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
else
lightnum = LIGHTLEVELS - 1;
@ -919,9 +919,9 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
// Check if the current light effects the colormap/lightlevel
if (pfloor->fofflags & FOF_FOG)
rlight->lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
rlight->lightnum = std::max((pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
else
rlight->lightnum = (rlight->lightlevel >> LIGHTSEGSHIFT);
rlight->lightnum = std::max((rlight->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
if (pfloor->fofflags & FOF_FOG || rlight->flags & FOF_FOG || (rlight->extra_colormap && (rlight->extra_colormap->flags & CMF_FOG)))
;
@ -937,14 +937,14 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor)
{
// Get correct light level!
if ((frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((frontsector->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
else if (pfloor->fofflags & FOF_FOG)
lightnum = (pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((pfloor->master->frontsector->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
else if (R_CheckColumnFunc(COLDRAWFUNC_FUZZY) == true)
lightnum = LIGHTLEVELS-1;
else
lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)
->lightlevel >> LIGHTSEGSHIFT;
lightnum = std::max((R_FakeFlat(frontsector, &tempsec, &templight, &templight, false)
->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
if (pfloor->fofflags & FOF_FOG || (frontsector->extra_colormap && (frontsector->extra_colormap->flags & CMF_FOG)))
;
@ -1556,7 +1556,7 @@ static void R_RenderSegLoop (drawcolumndata_t* dc)
for (i = 0; i < dc->numlights; i++)
{
INT32 lightnum;
lightnum = (dc->lightlist[i].lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((dc->lightlist[i].lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
if (dc->lightlist[i].extra_colormap)
;
@ -2665,7 +2665,7 @@ void R_StoreWallRange(INT32 start, INT32 stop)
// use different light tables
// for horizontal / vertical / diagonal
// OPTIMIZE: get rid of LIGHTSEGSHIFT globally
lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((frontsector->lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
if (P_ApplyLightOffset(lightnum, frontsector))
lightnum += curline->lightOffset;

View file

@ -51,6 +51,7 @@
#include "k_color.h"
#include "k_kart.h"
#include "r_fps.h"
#include "k_items.h"
#define MINZ (FRACUNIT*16)
#define BASEYCENTER (BASEVIDHEIGHT/2)
@ -283,6 +284,57 @@ void R_AddKartFaces(skin_t *skin)
}
#undef NUMFACES
// dear god... what a mess...
void R_AddKartItemSprites(kartitem_t *item)
{
spritedef_t *spritedef = &item->spritedef;
memset(sprtemp, 0xff, sizeof(sprtemp));
spritename = "ITEM";
maxframe = spritedef->numframes - 1;
const kartitemgraphics_t *graphics = &item->graphics[0];
for (UINT8 i = 0; i < graphics->numpatches; i++)
{
lumpnum_t lumpnum = W_CheckNumForName(graphics->patchnames[i]);
if (lumpnum == LUMPERROR)
I_Error("R_AddKartItemSprites: missing patch %s", graphics->patchnames[i]);
spritecachedinfo[numspritelumps].width = graphics->patches[i]->width<<FRACBITS;
spritecachedinfo[numspritelumps].offset = graphics->patches[i]->leftoffset<<FRACBITS;
spritecachedinfo[numspritelumps].topoffset = graphics->patches[i]->topoffset<<FRACBITS;
spritecachedinfo[numspritelumps].height = graphics->patches[i]->height<<FRACBITS;
// center it... i think
spritecachedinfo[numspritelumps].offset += 25*FRACUNIT;
spritecachedinfo[numspritelumps].topoffset += 50*FRACUNIT;
// BP: we cannot use special tric in hardware mode because feet in ground caused by z-buffer
spritecachedinfo[numspritelumps].topoffset += FEETADJUST;
R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), numspritelumps, i, ROT_L, 0);
R_InstallSpriteLump(WADFILENUM(lumpnum), LUMPNUM(lumpnum), numspritelumps, i, ROT_R, 1);
R_IncrementSpriteLumps();
}
maxframe++;
// allocate space for the frames present and copy sprtemp to it
if (spritedef->numframes && // has been allocated
spritedef->numframes < maxframe) // more frames are defined ?
{
Z_Free(spritedef->spriteframes);
spritedef->spriteframes = NULL;
}
// allocate this sprite's frames
if (!spritedef->spriteframes)
spritedef->spriteframes =
static_cast<spriteframe_t*>(Z_Malloc(maxframe * sizeof (*spritedef->spriteframes), PU_STATIC, NULL));
spritedef->numframes = maxframe;
memcpy(spritedef->spriteframes, sprtemp, maxframe*sizeof (spriteframe_t));
}
// Install a single sprite, given its identifying name (4 chars)
//
// (originally part of R_AddSpriteDefs)
@ -1268,7 +1320,7 @@ static void R_SplitSprite(vissprite_t *sprite)
newsprite->cut = static_cast<spritecut_e>(newsprite->cut | SC_TOP);
if (!(sector->lightlist[i].caster->fofflags & FOF_NOSHADE))
{
lightnum = (*sector->lightlist[i].lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((*sector->lightlist[i].lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
if (lightnum < 0)
spritelights = scalelight[0];
@ -1787,6 +1839,22 @@ static void R_ProjectSprite(mobj_t *thing)
sprdef = &sprites[thing->sprite];
#ifdef ROTSPRITE
sprinfo = &spriteinfo[thing->sprite];
#endif
frame = thing->frame&FF_FRAMEMASK;
}
}
else if (thing->sprite == SPR_ITEM)
{
sprdef = &kartitems[thing->threshold > 0 && thing->threshold < numkartitems ? thing->threshold : 0].spritedef;
sprinfo = &spriteinfo[SPR_UNKN];
if (frame >= sprdef->numframes) {
CONS_Alert(CONS_ERROR, M_GetText("R_ProjectSprite: invalid kartitem sprite frame %zu\n"), frame);
thing->sprite = states[S_UNKNOWN].sprite;
thing->frame = states[S_UNKNOWN].frame;
sprdef = &sprites[thing->sprite];
#ifdef ROTSPRITE
sprinfo = &spriteinfo[thing->sprite];
#endif
frame = thing->frame&FF_FRAMEMASK;
}
@ -1932,9 +2000,9 @@ static void R_ProjectSprite(mobj_t *thing)
const fixed_t visoffymul = (vflip ? -FRACUNIT : FRACUNIT);
if (R_ThingIsUsingBakedOffsets(thing))
if (R_ThingIsUsingBakedOffsets(interptarg))
{
R_RotateSpriteOffsetsByPitchRoll(thing,
R_RotateSpriteOffsetsByPitchRoll(interptarg,
vflip,
hflip,
&interp,
@ -2286,7 +2354,7 @@ static void R_ProjectSprite(mobj_t *thing)
lightnum = thing->subsector->sector->lightlevel;
}
lightnum = (lightnum + R_ThingLightLevel(thing)) >> LIGHTSEGSHIFT;
lightnum = std::max((lightnum + R_ThingLightLevel(thing)) >> LIGHTSEGSHIFT, cv_secbright.value);
if (maplighting.directional == true && P_SectorUsesDirectionalLighting(thing->subsector->sector))
{
@ -2712,7 +2780,7 @@ void R_AddSprites(sector_t *sec, INT32 lightlevel)
{
if (sec->heightsec == -1) lightlevel = sec->lightlevel;
lightnum = (lightlevel >> LIGHTSEGSHIFT);
lightnum = std::max((lightlevel >> LIGHTSEGSHIFT), cv_secbright.value);
if (lightnum < 0)
spritelights = scalelight[0];

View file

@ -32,6 +32,7 @@ extern "C" {
#define FEETADJUST (4<<FRACBITS) // R_AddSingleSpriteDef
void R_AddKartFaces(skin_t *skin);
void R_AddKartItemSprites(kartitem_t *item);
boolean R_AddSingleSpriteDef(const char *sprname, spritedef_t *spritedef, UINT16 wadnum, UINT16 startlump, UINT16 endlump);
//faB: find sprites in wadfile, replace existing, add new ones

View file

@ -208,6 +208,12 @@ TYPEDEF (waypoint_t);
TYPEDEF (mapUserProperty_t);
TYPEDEF (mapUserProperties_t);
// k_items.h
TYPEDEF (kartitem_t);
TYPEDEF (kartresult_t);
TYPEDEF (kartitemgraphics_t);
TYPEDEF (kartroulette_t);
// lua_hudlib_drawlist.h
typedef struct huddrawlist_s *huddrawlist_h;