Merge branch 'battle-recommendations' into 'master'

Battle Recommendations

Closes #569

See merge request KartKrew/Kart!1318
This commit is contained in:
Oni 2023-07-01 20:19:18 +00:00
commit afc474461f
15 changed files with 189 additions and 39 deletions

View file

@ -71,7 +71,8 @@ typedef enum
PF_GAINAX = 1<<3,
PF_KICKSTARTACCEL = 1<<4, // Accessibility feature: Is accelerate in kickstart mode?
// 1<<5 free
PF_POINTME = 1<<5, // An object is calling for my attention (via Obj_PointPlayersToMobj). Unset every frame!
// 1<<6 free
PF_WANTSTOJOIN = 1<<7, // Spectator that wants to join

View file

@ -3405,7 +3405,7 @@ static gametype_t defaultgametypes[] =
TOL_BATTLE,
int_scoreortimeattack,
0,
2,
3,
},
// GT_SPECIAL

View file

@ -29308,7 +29308,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY|MF_DONTENCOREMAP, // flags
MF_NOBLOCKMAP|MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_DRAWFROMFARAWAY|MF_SCENERY|MF_DONTENCOREMAP, // flags
S_NULL // raisestate
},

View file

@ -500,7 +500,7 @@ void K_RunPaperItemSpawners(void)
const UINT8 r = spotMap[P_RandomKey(PR_ITEM_ROULETTE, spotAvailable)];
Obj_ItemSpotAssignMonitor(spotList[r], Obj_SpawnMonitor(
spotList[r], 1 + pcount, firstUnspawnedEmerald));
spotList[r], 3, firstUnspawnedEmerald));
}
for (i = 0; i < spotCount; ++i)
@ -570,6 +570,8 @@ void K_RunPaperItemSpawners(void)
static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
{
const fixed_t heightPadding = 346 * scale;
UINT8 i, j;
for (i = 0; i <= r_splitscreen; i++)
@ -586,10 +588,12 @@ static void K_SpawnOvertimeLaser(fixed_t x, fixed_t y, fixed_t scale)
if (player->mo->eflags & MFE_VERTICALFLIP)
{
zpos = player->mo->z + player->mo->height;
zpos = min(zpos + heightPadding, player->mo->ceilingz);
}
else
{
zpos = player->mo->z;
zpos = max(zpos - heightPadding, player->mo->floorz);
}
flip = P_MobjFlip(player->mo);
@ -665,9 +669,17 @@ void K_RunBattleOvertime(void)
const fixed_t minradius = 768 * mapobjectscale;
if (battleovertime.radius > minradius)
battleovertime.radius -= 2*mapobjectscale;
else
battleovertime.radius -= (battleovertime.initial_radius / (30*TICRATE));
if (battleovertime.radius < minradius)
battleovertime.radius = minradius;
// Subtract the 10 second grace period of the barrier
if (battleovertime.enabled < 25*TICRATE)
{
battleovertime.enabled++;
Obj_PointPlayersToXY(battleovertime.x, battleovertime.y);
}
}
if (battleovertime.radius > 0)

View file

@ -10,8 +10,8 @@ extern "C" {
#define BATTLE_SPAWN_INTERVAL (4*TICRATE)
#define BATTLE_DESPAWN_TIME (15*TICRATE)
#define BATTLE_POWERUP_TIME (20*TICRATE)
#define BATTLE_UFO_TIME (25*TICRATE)
#define BATTLE_POWERUP_TIME (30*TICRATE)
#define BATTLE_UFO_TIME (20*TICRATE)
#define BATTLE_MONITOR_SPAWN_LIMIT (3)
@ -19,6 +19,7 @@ extern struct battleovertime
{
UINT16 enabled; ///< Has this been initalized yet?
fixed_t radius; ///< Radius of kill field
fixed_t initial_radius; ///< Starting radius of kill field
fixed_t x, y, z; ///< Position to center on
} battleovertime;

View file

@ -113,6 +113,7 @@ static patch_t *kp_battleinfo;
static patch_t *kp_wanted;
static patch_t *kp_wantedsplit;
static patch_t *kp_wantedreticle;
static patch_t *kp_minimapdot;
static patch_t *kp_itembg[4];
static patch_t *kp_ringbg[4];
@ -445,6 +446,7 @@ void K_LoadKartHUDGraphics(void)
HU_UpdatePatch(&kp_wanted, "K_WANTED");
HU_UpdatePatch(&kp_wantedsplit, "4PWANTED");
HU_UpdatePatch(&kp_wantedreticle, "MMAPWANT");
HU_UpdatePatch(&kp_minimapdot, "MMAPDOT");
// Kart Item Windows
HU_UpdatePatch(&kp_itembg[0], "K_ITBG");
@ -2219,7 +2221,7 @@ static boolean K_drawKartPositionFaces(void)
if ((gametyperules & GTR_BUMPERS) && (players[rankplayer[i]].pflags & PF_ELIMINATED))
V_DrawScaledPatch(FACE_X-4, Y-3, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_ranknobumpers);
else
else if (gametyperules & GTR_CIRCUIT)
{
INT32 pos = players[rankplayer[i]].position;
if (pos < 0 || pos > MAXPLAYERS)
@ -2227,6 +2229,34 @@ static boolean K_drawKartPositionFaces(void)
// Draws the little number over the face
V_DrawScaledPatch(FACE_X-5, Y+10, V_HUDTRANS|V_SLIDEIN|V_SNAPTOLEFT, kp_facenum[pos]);
}
else
{
INT32 flags = V_HUDTRANS | V_SLIDEIN | V_SNAPTOLEFT;
colormap = NULL;
if (g_pointlimit <= players[rankplayer[i]].roundscore)
{
if (leveltime % 8 < 4)
{
colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_TANGERINE, GTC_CACHE);
}
flags |= V_STRINGDANCE;
}
V_DrawStringScaled(
(FACE_X - 5) * FRACUNIT,
(Y + 10) * FRACUNIT,
FRACUNIT,
FRACUNIT,
FRACUNIT,
flags,
colormap,
PINGF_FONT,
va("%d", players[rankplayer[i]].roundscore)
);
}
Y -= 18;
}
@ -3712,6 +3742,8 @@ static void K_drawKartMinimapWaypoint(waypoint_t *wp, INT32 hudx, INT32 hudy, IN
K_drawKartMinimapDot(wp->mobj->x, wp->mobj->y, hudx, hudy, flags | V_NOSCALESTART, pal, size);
}
#define ICON_DOT_RADIUS (10)
static void K_drawKartMinimap(void)
{
patch_t *workingPic;
@ -3894,6 +3926,8 @@ static void K_drawKartMinimap(void)
{
for (i = MAXPLAYERS-1; i >= 0; i--)
{
boolean nocontest = false;
if (!playeringame[i])
continue;
if (!players[i].mo || players[i].spectator || !players[i].mo->skin
@ -3937,6 +3971,8 @@ static void K_drawKartMinimap(void)
colormap = R_GetTranslationColormap(TC_DEFAULT, mobj->color, GTC_CACHE);
mobj = mobj->tracer;
nocontest = true;
}
else
{
@ -3957,6 +3993,8 @@ static void K_drawKartMinimap(void)
if (doprogressionbar == false)
{
angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle);
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
@ -3968,6 +4006,19 @@ static void K_drawKartMinimap(void)
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
}
if (!nocontest)
{
K_drawKartMinimapIcon(
interpx,
interpy,
x + FixedMul(FCOS(ang), ICON_DOT_RADIUS),
y - FixedMul(FSIN(ang), ICON_DOT_RADIUS),
splitflags,
kp_minimapdot,
colormap
);
}
}
else
{
@ -4098,6 +4149,8 @@ static void K_drawKartMinimap(void)
for (i = 0; i < numlocalplayers; i++)
{
boolean nocontest = false;
if (localplayers[i] == -1)
continue; // this doesn't interest us
@ -4122,6 +4175,8 @@ static void K_drawKartMinimap(void)
colormap = R_GetTranslationColormap(TC_DEFAULT, mobj->color, GTC_CACHE);
mobj = mobj->tracer;
nocontest = true;
}
else
{
@ -4142,6 +4197,8 @@ static void K_drawKartMinimap(void)
if (doprogressionbar == false)
{
angle_t ang = R_InterpolateAngle(mobj->old_angle, mobj->angle);
interpx = R_InterpolateFixed(mobj->old_x, mobj->x);
interpy = R_InterpolateFixed(mobj->old_y, mobj->y);
@ -4153,6 +4210,19 @@ static void K_drawKartMinimap(void)
{
K_drawKartMinimapIcon(interpx, interpy, x, y, splitflags, kp_wantedreticle, NULL);
}
if (!nocontest)
{
K_drawKartMinimapIcon(
interpx,
interpy,
x + FixedMul(FCOS(ang), ICON_DOT_RADIUS),
y - FixedMul(FSIN(ang), ICON_DOT_RADIUS),
splitflags,
kp_minimapdot,
colormap
);
}
}
else
{

View file

@ -3837,13 +3837,14 @@ void K_BattleAwardHit(player_t *player, player_t *victim, mobj_t *inflictor, UIN
}
}
P_AddPlayerScore(player, points);
K_SpawnBattlePoints(player, victim, points);
// Check this before adding to player score
if ((gametyperules & GTR_BUMPERS) && finishOff && g_pointlimit <= player->roundscore)
{
P_DoAllPlayersExit(0, false);
}
P_AddPlayerScore(player, points);
K_SpawnBattlePoints(player, victim, points);
}
void K_SpinPlayer(player_t *player, mobj_t *inflictor, mobj_t *source, INT32 type)
@ -7635,7 +7636,7 @@ static inline BlockItReturn_t PIT_AttractingRings(mobj_t *thing)
return BMIT_CONTINUE; // invalid
}
if (!(thing->type == MT_RING || thing->type == MT_FLINGRING))
if (!(thing->type == MT_RING || thing->type == MT_FLINGRING || thing->type == MT_EMERALD))
{
return BMIT_CONTINUE; // not a ring
}
@ -7645,7 +7646,7 @@ static inline BlockItReturn_t PIT_AttractingRings(mobj_t *thing)
return BMIT_CONTINUE; // dead
}
if (thing->extravalue1)
if (thing->extravalue1 && thing->type != MT_EMERALD)
{
return BMIT_CONTINUE; // in special ring animation
}
@ -8424,6 +8425,8 @@ void K_KartPlayerThink(player_t *player, ticcmd_t *cmd)
}
K_HandleDelayedHitByEm(player);
player->pflags &= ~PF_POINTME;
}
void K_KartResetPlayerColor(player_t *player)
@ -8648,7 +8651,7 @@ void K_KartPlayerAfterThink(player_t *player)
player->jawztargetdelay = 0;
}
if (player->itemtype == KITEM_LIGHTNINGSHIELD)
if (player->itemtype == KITEM_LIGHTNINGSHIELD || ((gametyperules & GTR_POWERSTONES) && K_IsPlayerWanted(player)))
{
K_LookForRings(player->mo);
}

View file

@ -145,6 +145,7 @@ void Obj_SpawnGachaBomRebound(mobj_t *source, mobj_t *target);
/* Servant Hand */
void Obj_ServantHandHandling(player_t *player);
void Obj_PointPlayersToXY(fixed_t x, fixed_t y);
/* Super Flicky Controller */
void Obj_SpawnSuperFlickySwarm(player_t *owner, tic_t time);

View file

@ -7,7 +7,7 @@
// terms of the GNU General Public License, version 2.
// See the 'LICENSE' file for more details.
//-----------------------------------------------------------------------------
/// \file k_roulette.c
/// \file 0
/// \brief Item roulette code.
#include "k_roulette.h"
@ -111,36 +111,36 @@ static UINT8 K_KartItemOddsRace[NUMKARTRESULTS-1][8] =
static UINT8 K_KartItemOddsBattle[NUMKARTRESULTS-1][2] =
{
{ 2, 1 }, // Sneaker
{ 0, 1 }, // Sneaker
{ 0, 0 }, // Rocket Sneaker
{ 4, 1 }, // Invincibility
{ 0, 1 }, // Invincibility
{ 0, 0 }, // Banana
{ 1, 0 }, // Eggman Monitor
{ 8, 0 }, // Orbinaut
{ 8, 1 }, // Jawz
{ 6, 1 }, // Mine
{ 2, 0 }, // Land Mine
{ 0, 0 }, // Eggman Monitor
{ 2, 0 }, // Orbinaut
{ 3, 1 }, // Jawz
{ 2, 1 }, // Mine
{ 0, 0 }, // Land Mine
{ 2, 1 }, // Ballhog
{ 0, 0 }, // Self-Propelled Bomb
{ 2, 1 }, // Grow
{ 1, 1 }, // Grow
{ 0, 0 }, // Shrink
{ 4, 0 }, // Lightning Shield
{ 0, 0 }, // Lightning Shield
{ 1, 0 }, // Bubble Shield
{ 1, 0 }, // Flame Shield
{ 2, 0 }, // Hyudoro
{ 3, 0 }, // Pogo Spring
{ 0, 0 }, // Flame Shield
{ 0, 0 }, // Hyudoro
{ 0, 0 }, // Pogo Spring
{ 0, 0 }, // Super Ring
{ 0, 0 }, // Kitchen Sink
{ 2, 0 }, // Drop Target
{ 4, 0 }, // Garden Top
{ 0, 0 }, // Gachabom
{ 0, 0 }, // Drop Target
{ 0, 0 }, // Garden Top
{ 5, 0 }, // Gachabom
{ 0, 0 }, // Sneaker x2
{ 0, 1 }, // Sneaker x3
{ 0, 0 }, // Banana x3
{ 2, 0 }, // Orbinaut x3
{ 1, 1 }, // Orbinaut x4
{ 5, 1 }, // Jawz x2
{ 0, 0 } // Gachabom x3
{ 2, 1 }, // Orbinaut x4
{ 2, 1 }, // Jawz x2
{ 2, 0 } // Gachabom x3
};
static UINT8 K_KartItemOddsSpecial[NUMKARTRESULTS-1][4] =

View file

@ -132,6 +132,11 @@ void Obj_BattleUFOThink(mobj_t *mobj)
{
ufo->spawn_beam();
}
if (!battleovertime.enabled)
{
Obj_PointPlayersToXY(mobj->x, mobj->y);
}
}
void Obj_BattleUFODeath(mobj_t *mobj)

View file

@ -5,10 +5,12 @@
#include "../k_kart.h"
#include "../k_objects.h"
#include "../v_video.h"
#include "../r_main.h"
#include "../g_game.h"
void Obj_ServantHandHandling(player_t *player)
{
if (player->pflags & PF_WRONGWAY)
if (player->pflags & PF_WRONGWAY || player->pflags & PF_POINTME)
{
if (player->handtimer < TICRATE)
{
@ -101,3 +103,18 @@ void Obj_ServantHandHandling(player_t *player)
player->hand->renderflags |= (RF_DONTDRAW & ~K_GetPlayerDontDrawFlag(player));
}
}
void Obj_PointPlayersToXY(fixed_t x, fixed_t y)
{
for(int i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator || !players[i].mo)
continue;
angle_t angletotarget = R_PointToAngle2(
players[i].mo->x, players[i].mo->y,
x, y);
players[i].pflags |= PF_POINTME;
players[i].besthanddirection = angletotarget;
}
}

View file

@ -3800,7 +3800,7 @@ void A_AttractChase(mobj_t *actor)
if (actor->flags2 & MF2_NIGHTSPULL || !actor->health)
return;
if (actor->extravalue1) // SRB2Kart
if (actor->extravalue1 && actor->type != MT_EMERALD) // SRB2Kart
{
if (!actor->target || P_MobjWasRemoved(actor->target) || !actor->target->player)
{

View file

@ -453,7 +453,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
return;
}
case MT_EMERALD:
if (!P_CanPickupItem(player, 0))
if (!P_CanPickupItem(player, 0) || P_PlayerInPain(player))
return;
if (special->threshold > 0)
@ -829,6 +829,8 @@ void P_CheckTimeLimit(void)
thinker_t *th;
mobj_t *center = NULL;
fixed_t rx, ry;
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
{
mobj_t *thismo;
@ -860,7 +862,26 @@ void P_CheckTimeLimit(void)
battleovertime.z = center->z;
}
battleovertime.radius = 4096 * mapobjectscale;
// Get largest radius from center point to minimap edges
rx = max(
abs(battleovertime.x - (minimapinfo.min_x * FRACUNIT)),
abs(battleovertime.x - (minimapinfo.max_x * FRACUNIT))
);
ry = max(
abs(battleovertime.y - (minimapinfo.min_y * FRACUNIT)),
abs(battleovertime.y - (minimapinfo.max_y * FRACUNIT))
);
battleovertime.initial_radius = min(
max(max(rx, ry), 4096 * mapobjectscale),
// Prevent overflow in K_RunBattleOvertime
FixedDiv(INT32_MAX, M_PI_FIXED) / 2
);
battleovertime.radius = battleovertime.initial_radius;
battleovertime.enabled = 1;
S_StartSound(NULL, sfx_kc47);
@ -2447,7 +2468,10 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da
K_BattleAwardHit(source->player, player, inflictor, damage);
}
K_TakeBumpersFromPlayer(source->player, player, damage);
if (K_Bumpers(source->player) < K_StartingBumperCount() || (damagetype & DMG_STEAL))
{
K_TakeBumpersFromPlayer(source->player, player, damage);
}
if (damagetype & DMG_STEAL)
{

View file

@ -7538,6 +7538,8 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
{
if (mobj->threshold > 0)
mobj->threshold--;
A_AttractChase(mobj);
}
/*FALLTHRU*/
case MT_MONITOR:
@ -8448,6 +8450,18 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
}
case MT_BATTLEUFO:
{
if (battleovertime.enabled >= 10*TICRATE)
{
fixed_t distance = R_PointToDist2(mobj->x, mobj->y, battleovertime.x, battleovertime.y);
if (distance > battleovertime.radius)
{
// Delete emeralds to let them reappear
P_KillMobj(mobj, NULL, NULL, DMG_NORMAL);
return false;
}
}
Obj_BattleUFOThink(mobj);
break;
}

View file

@ -5734,6 +5734,7 @@ static void P_NetArchiveMisc(savebuffer_t *save, boolean resending)
// battleovertime_t
WRITEUINT16(save->p, battleovertime.enabled);
WRITEFIXED(save->p, battleovertime.radius);
WRITEFIXED(save->p, battleovertime.initial_radius);
WRITEFIXED(save->p, battleovertime.x);
WRITEFIXED(save->p, battleovertime.y);
WRITEFIXED(save->p, battleovertime.z);
@ -5908,6 +5909,7 @@ static boolean P_NetUnArchiveMisc(savebuffer_t *save, boolean reloading)
// battleovertime_t
battleovertime.enabled = READUINT16(save->p);
battleovertime.radius = READFIXED(save->p);
battleovertime.initial_radius = READFIXED(save->p);
battleovertime.x = READFIXED(save->p);
battleovertime.y = READFIXED(save->p);
battleovertime.z = READFIXED(save->p);