From f210b4a417cbe99696ace6b6f38ef125e02122ff Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 8 May 2020 19:38:51 -0400 Subject: [PATCH 01/34] Sprite offset code --- src/lua_mobjlib.c | 26 +++++++++++++++++++++++++- src/p_mobj.h | 2 ++ src/p_user.c | 4 ++++ src/r_things.c | 32 ++++++++++++++++++-------------- 4 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 47efd729f..cd5f4d267 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -87,7 +87,10 @@ enum mobj_e { #endif mobj_colorized, mobj_shadowscale, - mobj_whiteshadow + mobj_whiteshadow, + mobj_sprxoff, + mobj_spryoff, + mobj_sprzoff }; static const char *const mobj_opt[] = { @@ -153,6 +156,9 @@ static const char *const mobj_opt[] = { "colorized", "shadowscale", "whiteshadow", + "sprxoff", + "spryoff", + "sprzoff", NULL}; #define UNIMPLEMENTED luaL_error(L, LUA_QL("mobj_t") " field " LUA_QS " is not implemented for Lua and cannot be accessed.", mobj_opt[field]) @@ -370,6 +376,15 @@ static int mobj_get(lua_State *L) case mobj_whiteshadow: lua_pushboolean(L, mo->whiteshadow); break; + case mobj_sprxoff: + lua_pushfixed(L, mo->sprxoff); + break; + case mobj_spryoff: + lua_pushfixed(L, mo->spryoff); + break; + case mobj_sprzoff: + lua_pushfixed(L, mo->sprzoff); + break; default: // extra custom variables in Lua memory lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); @@ -693,6 +708,15 @@ static int mobj_set(lua_State *L) case mobj_whiteshadow: mo->whiteshadow = luaL_checkboolean(L, 3); break; + case mobj_sprxoff: + mo->sprxoff = luaL_checkfixed(L, 3); + break; + case mobj_spryoff: + mo->spryoff = luaL_checkfixed(L, 3); + break; + case mobj_sprzoff: + mo->sprzoff = luaL_checkfixed(L, 3); + break; default: lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS); I_Assert(lua_istable(L, -1)); diff --git a/src/p_mobj.h b/src/p_mobj.h index 5cc93a56d..746529360 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -378,6 +378,8 @@ typedef struct mobj_s fixed_t shadowscale; // If this object casts a shadow, and the size relative to radius boolean whiteshadow; // Use white shadow, set to true by default for fullbright objects + fixed_t sprxoff, spryoff, sprzoff; // Sprite offsets in real space, does NOT affect position or collision + // WARNING: New fields must be added separately to savegame and Lua. } mobj_t; diff --git a/src/p_user.c b/src/p_user.c index 6a6125990..5493ed46f 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -1674,6 +1674,10 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj) ghost->modeltilt = mobj->modeltilt; #endif + ghost->sprxoff = mobj->sprxoff; + ghost->spryoff = mobj->spryoff; + ghost->sprzoff = mobj->sprzoff; + if (mobj->flags2 & MF2_OBJECTFLIP) ghost->flags |= MF2_OBJECTFLIP; diff --git a/src/r_things.c b/src/r_things.c index 587be375d..384c8fa28 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -1435,6 +1435,10 @@ static void R_ProjectDropShadow(mobj_t *thing, vissprite_t *vis, fixed_t scale, // static void R_ProjectSprite(mobj_t *thing) { + const fixed_t thingxpos = thing->x + thing->sprxoff; + const fixed_t thingypos = thing->y + thing->spryoff; + const fixed_t thingzpos = thing->z + thing->sprzoff; + fixed_t tr_x, tr_y; fixed_t gxt, gyt; fixed_t tx, tz; @@ -1471,8 +1475,8 @@ static void R_ProjectSprite(mobj_t *thing) fixed_t this_scale = thing->scale; // transform the origin point - tr_x = thing->x - viewx; - tr_y = thing->y - viewy; + tr_x = thingxpos - viewx; + tr_y = thingypos - viewy; gxt = FixedMul(tr_x, viewcos); gyt = -FixedMul(tr_y, viewsin); @@ -1538,9 +1542,9 @@ static void R_ProjectSprite(mobj_t *thing) if (sprframe->rotate != SRF_SINGLE || papersprite) { if (thing->player) - ang = R_PointToAngle (thing->x, thing->y) - thing->player->frameangle; + ang = R_PointToAngle (thingxpos, thingypos) - thing->player->frameangle; else - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + ang = R_PointToAngle (thingxpos, thingypos) - thing->angle; } if (sprframe->rotate == SRF_SINGLE) @@ -1553,7 +1557,7 @@ static void R_ProjectSprite(mobj_t *thing) else { // choose a different rotation based on player view - //ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + //ang = R_PointToAngle (thingxpos, thingypos) - thing->angle; if ((ang < ANGLE_180) && (sprframe->rotate & SRF_RIGHT)) // See from right rot = 6; // F7 slot @@ -1700,7 +1704,7 @@ static void R_ProjectSprite(mobj_t *thing) if (x2 < portalclipstart || x1 > portalclipend) return; - if (P_PointOnLineSide(thing->x, thing->y, portalclipline) != 0) + if (P_PointOnLineSide(thingxpos, thingypos, portalclipline) != 0) return; } @@ -1710,12 +1714,12 @@ static void R_ProjectSprite(mobj_t *thing) // When vertical flipped, draw sprites from the top down, at least as far as offsets are concerned. // sprite height - sprite topoffset is the proper inverse of the vertical offset, of course. // remember gz and gzt should be seperated by sprite height, not thing height - thing height can be shorter than the sprite itself sometimes! - gz = thing->z + thing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale); + gz = thingzpos + thing->height - FixedMul(spritecachedinfo[lump].topoffset, this_scale); gzt = gz + FixedMul(spritecachedinfo[lump].height, this_scale); } else { - gzt = thing->z + FixedMul(spritecachedinfo[lump].topoffset, this_scale); + gzt = thingzpos + FixedMul(spritecachedinfo[lump].topoffset, this_scale); gz = gzt - FixedMul(spritecachedinfo[lump].height, this_scale); } @@ -1732,7 +1736,7 @@ static void R_ProjectSprite(mobj_t *thing) light = thing->subsector->sector->numlights - 1; for (lightnum = 1; lightnum < thing->subsector->sector->numlights; lightnum++) { - fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thing->x, thing->y) + fixed_t h = thing->subsector->sector->lightlist[lightnum].slope ? P_GetZAt(thing->subsector->sector->lightlist[lightnum].slope, thingxpos, thingypos) : thing->subsector->sector->lightlist[lightnum].height; if (h <= gzt) { light = lightnum - 1; @@ -1761,12 +1765,12 @@ static void R_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { if (viewz < sectors[phs].floorheight ? - thing->z >= sectors[heightsec].floorheight : + thingzpos >= sectors[heightsec].floorheight : gzt < sectors[heightsec].floorheight) return; if (viewz > sectors[phs].ceilingheight ? gzt < sectors[heightsec].ceilingheight && viewz >= sectors[heightsec].ceilingheight : - thing->z >= sectors[heightsec].ceilingheight) + thingzpos >= sectors[heightsec].ceilingheight) return; } @@ -1777,12 +1781,12 @@ static void R_ProjectSprite(mobj_t *thing) vis->scale = yscale; //<sortscale = sortscale; vis->dispoffset = thing->info->dispoffset; // Monster Iestyn: 23/11/15 - vis->gx = thing->x; - vis->gy = thing->y; + vis->gx = thingxpos; + vis->gy = thingypos; vis->gz = gz; vis->gzt = gzt; vis->thingheight = thing->height; - vis->pz = thing->z; + vis->pz = thingzpos; vis->pzt = vis->pz + vis->thingheight; vis->texturemid = vis->gzt - viewz; vis->scalestep = scalestep; From b97f3cdcce139b2237ad22b22e789a40dd640200 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 9 May 2020 02:17:35 -0400 Subject: [PATCH 02/34] Horizontal springs offset the sprite --- src/p_mobj.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index aa04ccac9..54fcf0e08 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -12942,16 +12942,30 @@ ML_NOCLIMB : Direction not controllable mobj->angle = FixedAngle(mthing->angle*FRACUNIT); + if ((mobj->flags & MF_SPRING) + && mobj->info->damage != 0 + && mobj->info->mass == 0) + { + // Offset sprite of horizontal springs + angle_t a = mobj->angle + ANGLE_180; + mobj->sprxoff = FixedMul(mobj->radius, FINECOSINE(a >> ANGLETOFINESHIFT)); + mobj->spryoff = FixedMul(mobj->radius, FINESINE(a >> ANGLETOFINESHIFT)); + } + if ((mthing->options & MTF_AMBUSH) && (mthing->options & MTF_OBJECTSPECIAL) && (mobj->flags & MF_PUSHABLE)) + { mobj->flags2 |= MF2_CLASSICPUSH; + } else { if (mthing->options & MTF_AMBUSH) { - if (mobj->flags & MF_SPRING && mobj->info->damage) + if ((mobj->flags & MF_SPRING) && mobj->info->damage) + { mobj->angle += ANGLE_22h; + } if (mobj->flags & MF_NIGHTSITEM) { From b4f5d931cce122fb22b8d467efdf6bba49b17772 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 11 May 2020 02:28:25 -0400 Subject: [PATCH 03/34] Skincolor code cleanup Split everything off into its own file and turn SETBRIGHTNESS from a define into a function (K_ColorRelativeLuminance). --- src/CMakeLists.txt | 2 + src/Makefile | 1 + src/d_netcmd.c | 1 + src/g_game.c | 1 + src/hardware/hw_md2.c | 23 +- src/k_color.c | 526 ++++++++++++++++++++++++++++++++++++++++++ src/k_color.h | 87 +++++++ src/k_kart.c | 506 +--------------------------------------- src/k_kart.h | 6 - src/lua_baselib.c | 1 + src/lua_mathlib.c | 2 +- src/m_cond.c | 2 +- src/m_menu.c | 1 + src/p_mobj.c | 1 + src/r_draw.c | 2 +- src/r_things.c | 2 +- src/y_inter.c | 2 +- 17 files changed, 635 insertions(+), 531 deletions(-) create mode 100644 src/k_color.c create mode 100644 src/k_color.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 4447614d3..77bd64044 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -164,6 +164,7 @@ set(SRB2_CORE_GAME_SOURCES k_pathfind.c k_pwrlv.c k_waypoint.c + k_color.c p_local.h p_maputl.h @@ -182,6 +183,7 @@ set(SRB2_CORE_GAME_SOURCES k_pathfind.h k_pwrlv.h k_waypoint.h + k_color.h ) if(NOT (CMAKE_CXX_COMPILER_ID MATCHES "Clang")) diff --git a/src/Makefile b/src/Makefile index a6f18a72a..1620974ed 100644 --- a/src/Makefile +++ b/src/Makefile @@ -496,6 +496,7 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/st_stuff.o \ $(OBJDIR)/k_kart.o \ $(OBJDIR)/k_collide.o\ + $(OBJDIR)/k_color.o \ $(OBJDIR)/k_battle.o \ $(OBJDIR)/k_pwrlv.o \ $(OBJDIR)/k_waypoint.o\ diff --git a/src/d_netcmd.c b/src/d_netcmd.c index 7def24de5..1a7eb83e4 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -50,6 +50,7 @@ #include "k_battle.h" #include "k_pwrlv.h" #include "y_inter.h" +#include "k_color.h" #ifdef NETGAME_DEVMODE #define CV_RESTRICT CV_NETVAR diff --git a/src/g_game.c b/src/g_game.c index 30920108f..23228dff7 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -50,6 +50,7 @@ #include "k_kart.h" // SRB2kart #include "k_battle.h" #include "k_pwrlv.h" +#include "k_color.h" gameaction_t gameaction; gamestate_t gamestate = GS_NULL; diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 21deed84b..560b47ce6 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -42,7 +42,7 @@ #include "../r_things.h" #include "../r_draw.h" #include "../p_tick.h" -#include "../k_kart.h" // colortranslations +#include "../k_color.h" // colortranslations #include "hw_model.h" #include "hw_main.h" @@ -648,15 +648,6 @@ spritemd2found: fclose(f); } -// Define for getting accurate color brightness readings according to how the human eye sees them. -// https://en.wikipedia.org/wiki/Relative_luminance -// 0.2126 to red -// 0.7152 to green -// 0.0722 to blue -// (See this same define in hw_md2.c!) -#define SETBRIGHTNESS(brightness,r,g,b) \ - brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000)) - static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color) { UINT16 w = gpatch->width, h = gpatch->height; @@ -701,8 +692,10 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, else { UINT16 imagebright, blendbright; - SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue); - SETBRIGHTNESS(blendbright,blendimage->s.red,blendimage->s.green,blendimage->s.blue); + + imagebright = K_ColorRelativeLuminance(image->s.red, image->s.green, image->s.blue); + blendbright = K_ColorRelativeLuminance(blendimage->s.red, blendimage->s.green, blendimage->s.blue); + // slightly dumb average between the blend image color and base image colour, usually one or the other will be fully opaque anyway brightness = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255; } @@ -717,7 +710,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, } else { - SETBRIGHTNESS(brightness,blendimage->s.red,blendimage->s.green,blendimage->s.blue); + brightness = K_ColorRelativeLuminance(blendimage->s.red, blendimage->s.green, blendimage->s.blue); } } @@ -751,7 +744,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, for (i = 0; i < 16; i++) { RGBA_t tempc = V_GetColor(colortranslations[color][i]); - SETBRIGHTNESS(colorbrightnesses[i], tempc.s.red, tempc.s.green, tempc.s.blue); // store brightnesses for comparison + colorbrightnesses[i] = K_ColorRelativeLuminance(tempc.s.red, tempc.s.green, tempc.s.blue); } for (i = 0; i < 16; i++) @@ -828,7 +821,7 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, UINT32 tempcolor; UINT16 colorbright; - SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue); + colorbright = K_ColorRelativeLuminance(blendcolor.s.red, blendcolor.s.green, blendcolor.s.blue); if (colorbright == 0) colorbright = 1; // no dividing by 0 please diff --git a/src/k_color.c b/src/k_color.c new file mode 100644 index 000000000..a838f833a --- /dev/null +++ b/src/k_color.c @@ -0,0 +1,526 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2020 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_color.c +/// \brief Waypoint handling from the relevant mobjs +/// Setup and interfacing with waypoints for the main game + +#include "k_color.h" + +#include "doomdef.h" +#include "doomtype.h" +#include "r_draw.h" +#include "r_things.h" +#include "v_video.h" + +// These should be within 14 characters to fit on the character select screen +const char *KartColor_Names[MAXSKINCOLORS] = +{ + "None", // SKINCOLOR_NONE + "White", // SKINCOLOR_WHITE + "Silver", // SKINCOLOR_SILVER + "Grey", // SKINCOLOR_GREY + "Nickel", // SKINCOLOR_NICKEL + "Black", // SKINCOLOR_BLACK + "Fairy", // SKINCOLOR_FAIRY + "Popcorn", // SKINCOLOR_POPCORN + "Artichoke", // SKINCOLOR_ARTICHOKE + "Pigeon", // SKINCOLOR_PIGEON + "Sepia", // SKINCOLOR_SEPIA + "Beige", // SKINCOLOR_BEIGE + "Caramel", // SKINCOLOR_CARAMEL + "Peach", // SKINCOLOR_PEACH + "Brown", // SKINCOLOR_BROWN + "Leather", // SKINCOLOR_LEATHER + "Salmon", // SKINCOLOR_SALMON + "Pink", // SKINCOLOR_PINK + "Rose", // SKINCOLOR_ROSE + "Cinnamon", // SKINCOLOR_CINNAMON + "Ruby", // SKINCOLOR_RUBY + "Raspberry", // SKINCOLOR_RASPBERRY + "Red", // SKINCOLOR_RED + "Crimson", // SKINCOLOR_CRIMSON + "Maroon", // SKINCOLOR_MAROON + "Lemonade", // SKINCOLOR_LEMONADE + "Scarlet", // SKINCOLOR_SCARLET + "Ketchup", // SKINCOLOR_KETCHUP + "Dawn", // SKINCOLOR_DAWN + "Sunslam", // SKINCOLOR_SUNSLAM + "Creamsicle", // SKINCOLOR_CREAMSICLE + "Orange", // SKINCOLOR_ORANGE + "Rosewood", // SKINCOLOR_ROSEWOOD + "Tangerine", // SKINCOLOR_TANGERINE + "Tan", // SKINCOLOR_TAN + "Cream", // SKINCOLOR_CREAM + "Gold", // SKINCOLOR_GOLD + "Royal", // SKINCOLOR_ROYAL + "Bronze", // SKINCOLOR_BRONZE + "Copper", // SKINCOLOR_COPPER + "Yellow", // SKINCOLOR_YELLOW + "Mustard", // SKINCOLOR_MUSTARD + "Banana", // SKINCOLOR_BANANA + "Olive", // SKINCOLOR_OLIVE + "Crocodile", // SKINCOLOR_CROCODILE + "Peridot", // SKINCOLOR_PERIDOT + "Vomit", // SKINCOLOR_VOMIT + "Garden", // SKINCOLOR_GARDEN + "Lime", // SKINCOLOR_LIME + "Handheld", // SKINCOLOR_HANDHELD + "Tea", // SKINCOLOR_TEA + "Pistachio", // SKINCOLOR_PISTACHIO + "Moss", // SKINCOLOR_MOSS + "Camouflage", // SKINCOLOR_CAMOUFLAGE + "Robo-Hood", // SKINCOLOR_ROBOHOOD + "Mint", // SKINCOLOR_MINT + "Green", // SKINCOLOR_GREEN + "Pinetree", // SKINCOLOR_PINETREE + "Turtle", // SKINCOLOR_TURTLE + "Swamp", // SKINCOLOR_SWAMP + "Dream", // SKINCOLOR_DREAM + "Plague", // SKINCOLOR_PLAGUE + "Emerald", // SKINCOLOR_EMERALD + "Algae", // SKINCOLOR_ALGAE + "Caribbean", // SKINCOLOR_CARIBBEAN + "Azure", // SKINCOLOR_AZURE + "Aquamarine", // SKINCOLOR_AQUAMARINE + "Turquoise", // SKINCOLOR_TURQUOISE + "Teal", // SKINCOLOR_TEAL + "Cyan", // SKINCOLOR_CYAN + "Jawz", // SKINCOLOR_JAWZ + "Cerulean", // SKINCOLOR_CERULEAN + "Navy", // SKINCOLOR_NAVY + "Platinum", // SKINCOLOR_PLATINUM + "Slate", // SKINCOLOR_SLATE + "Steel", // SKINCOLOR_STEEL + "Thunder", // SKINCOLOR_THUNDER + "Nova", // SKINCOLOR_NOVA + "Rust", // SKINCOLOR_RUST + "Wristwatch", // SKINCOLOR_WRISTWATCH + "Jet", // SKINCOLOR_JET + "Sapphire", // SKINCOLOR_SAPPHIRE + "Ultramarine", // SKINCOLOR_ULTRAMARINE + "Periwinkle", // SKINCOLOR_PERIWINKLE + "Blue", // SKINCOLOR_BLUE + "Blueberry", // SKINCOLOR_BLUEBERRY + "Thistle", // SKINCOLOR_THISTLE + "Purple", // SKINCOLOR_PURPLE + "Pastel", // SKINCOLOR_PASTEL + "Moonset", // SKINCOLOR_MOONSET + "Dusk", // SKINCOLOR_DUSK + "Violet", // SKINCOLOR_VIOLET + "Magenta", // SKINCOLOR_MAGENTA + "Fuchsia", // SKINCOLOR_FUCHSIA + "Toxic", // SKINCOLOR_TOXIC + "Mauve", // SKINCOLOR_MAUVE + "Lavender", // SKINCOLOR_LAVENDER + "Byzantium", // SKINCOLOR_BYZANTIUM + "Pomegranate", // SKINCOLOR_POMEGRANATE + "Lilac", // SKINCOLOR_LILAC + "Taffy" // SKINCOLOR_TAFFY +}; + +// Color_Opposite replacement; frame setting has not been changed from 8 for most, should be done later +const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = +{ + SKINCOLOR_NONE,8, // SKINCOLOR_NONE + SKINCOLOR_BLACK,8, // SKINCOLOR_WHITE + SKINCOLOR_NICKEL,8, // SKINCOLOR_SILVER + SKINCOLOR_GREY,8, // SKINCOLOR_GREY + SKINCOLOR_SILVER,8, // SKINCOLOR_NICKEL + SKINCOLOR_WHITE,8, // SKINCOLOR_BLACK + SKINCOLOR_ARTICHOKE,12, // SKINCOLOR_FAIRY + SKINCOLOR_PIGEON,12, // SKINCOLOR_POPCORN + SKINCOLOR_FAIRY,12, // SKINCOLOR_ARTICHOKE + SKINCOLOR_POPCORN,12, // SKINCOLOR_PIGEON + SKINCOLOR_LEATHER,6, // SKINCOLOR_SEPIA + SKINCOLOR_BROWN,2, // SKINCOLOR_BEIGE + SKINCOLOR_CERULEAN,8, // SKINCOLOR_CARAMEL + SKINCOLOR_CYAN,8, // SKINCOLOR_PEACH + SKINCOLOR_BEIGE,8, // SKINCOLOR_BROWN + SKINCOLOR_SEPIA,8, // SKINCOLOR_LEATHER + SKINCOLOR_TEA,8, // SKINCOLOR_SALMON + SKINCOLOR_PISTACHIO,8, // SKINCOLOR_PINK + SKINCOLOR_MOSS,8, // SKINCOLOR_ROSE + SKINCOLOR_WRISTWATCH,6, // SKINCOLOR_CINNAMON + SKINCOLOR_SAPPHIRE,8, // SKINCOLOR_RUBY + SKINCOLOR_MINT,8, // SKINCOLOR_RASPBERRY + SKINCOLOR_GREEN,6, // SKINCOLOR_RED + SKINCOLOR_PINETREE,6, // SKINCOLOR_CRIMSON + SKINCOLOR_TOXIC,8, // SKINCOLOR_MAROON + SKINCOLOR_THUNDER,8, // SKINCOLOR_LEMONADE + SKINCOLOR_ALGAE,10, // SKINCOLOR_SCARLET + SKINCOLOR_MUSTARD,10, // SKINCOLOR_KETCHUP + SKINCOLOR_DUSK,8, // SKINCOLOR_DAWN + SKINCOLOR_MOONSET,8, // SKINCOLOR_SUNSLAM + SKINCOLOR_PERIWINKLE,8, // SKINCOLOR_CREAMSICLE + SKINCOLOR_BLUE,8, // SKINCOLOR_ORANGE + SKINCOLOR_BLUEBERRY,6, // SKINCOLOR_ROSEWOOD + SKINCOLOR_LIME,8, // SKINCOLOR_TANGERINE + SKINCOLOR_RUST,8, // SKINCOLOR_TAN + SKINCOLOR_COPPER,10, // SKINCOLOR_CREAM + SKINCOLOR_SLATE,8, // SKINCOLOR_GOLD + SKINCOLOR_PLATINUM,6, // SKINCOLOR_ROYAL + SKINCOLOR_STEEL,8, // SKINCOLOR_BRONZE + SKINCOLOR_CREAM,6, // SKINCOLOR_COPPER + SKINCOLOR_AQUAMARINE,8, // SKINCOLOR_YELLOW + SKINCOLOR_KETCHUP,8, // SKINCOLOR_MUSTARD + SKINCOLOR_EMERALD,8, // SKINCOLOR_BANANA + SKINCOLOR_TEAL,8, // SKINCOLOR_OLIVE + SKINCOLOR_VIOLET,8, // SKINCOLOR_CROCODILE + SKINCOLOR_NAVY,6, // SKINCOLOR_PERIDOT + SKINCOLOR_ROBOHOOD,8, // SKINCOLOR_VOMIT + SKINCOLOR_LAVENDER,6, // SKINCOLOR_GARDEN + SKINCOLOR_TANGERINE,8, // SKINCOLOR_LIME + SKINCOLOR_ULTRAMARINE,8, // SKINCOLOR_HANDHELD + SKINCOLOR_SALMON,8, // SKINCOLOR_TEA + SKINCOLOR_PINK,6, // SKINCOLOR_PISTACHIO + SKINCOLOR_ROSE,8, // SKINCOLOR_MOSS + SKINCOLOR_CAMOUFLAGE,8, // SKINCOLOR_CAMOUFLAGE + SKINCOLOR_VOMIT,8, // SKINCOLOR_ROBOHOOD + SKINCOLOR_RASPBERRY,8, // SKINCOLOR_MINT + SKINCOLOR_RED,8, // SKINCOLOR_GREEN + SKINCOLOR_CRIMSON,8, // SKINCOLOR_PINETREE + SKINCOLOR_MAGENTA,8, // SKINCOLOR_TURTLE + SKINCOLOR_BYZANTIUM,8, // SKINCOLOR_SWAMP + SKINCOLOR_POMEGRANATE,8, // SKINCOLOR_DREAM + SKINCOLOR_NOVA,8, // SKINCOLOR_PLAGUE + SKINCOLOR_BANANA,8, // SKINCOLOR_EMERALD + SKINCOLOR_SCARLET,10, // SKINCOLOR_ALGAE + SKINCOLOR_PURPLE,8, // SKINCOLOR_CARIBBEAN + SKINCOLOR_THISTLE,8, // SKINCOLOR_AZURE + SKINCOLOR_YELLOW,8, // SKINCOLOR_AQUAMARINE + SKINCOLOR_MAUVE,10, // SKINCOLOR_TURQUOISE + SKINCOLOR_OLIVE,8, // SKINCOLOR_TEAL + SKINCOLOR_PEACH,8, // SKINCOLOR_CYAN + SKINCOLOR_LILAC,10, // SKINCOLOR_JAWZ + SKINCOLOR_CARAMEL,8, // SKINCOLOR_CERULEAN + SKINCOLOR_PERIDOT,8, // SKINCOLOR_NAVY + SKINCOLOR_ROYAL,8, // SKINCOLOR_PLATINUM + SKINCOLOR_GOLD,10, // SKINCOLOR_SLATE + SKINCOLOR_BRONZE,10, // SKINCOLOR_STEEL + SKINCOLOR_LEMONADE,8, // SKINCOLOR_THUNDER + SKINCOLOR_PLAGUE,10, // SKINCOLOR_NOVA + SKINCOLOR_TAN,8, // SKINCOLOR_RUST + SKINCOLOR_CINNAMON,8, // SKINCOLOR_WRISTWATCH + SKINCOLOR_TAFFY,8, // SKINCOLOR_JET + SKINCOLOR_RUBY,6, // SKINCOLOR_SAPPHIRE + SKINCOLOR_HANDHELD,10, // SKINCOLOR_ULTRAMARINE + SKINCOLOR_CREAMSICLE,8, // SKINCOLOR_PERIWINKLE + SKINCOLOR_ORANGE,8, // SKINCOLOR_BLUE + SKINCOLOR_ROSEWOOD,8, // SKINCOLOR_BLUEBERRY + SKINCOLOR_AZURE,8, // SKINCOLOR_THISTLE + SKINCOLOR_CARIBBEAN,10, // SKINCOLOR_PURPLE + SKINCOLOR_FUCHSIA,11, // SKINCOLOR_PASTEL + SKINCOLOR_SUNSLAM,10, // SKINCOLOR_MOONSET + SKINCOLOR_DAWN,6, // SKINCOLOR_DUSK + SKINCOLOR_CROCODILE,8, // SKINCOLOR_VIOLET + SKINCOLOR_TURTLE,8, // SKINCOLOR_MAGENTA + SKINCOLOR_PASTEL,11, // SKINCOLOR_FUCHSIA + SKINCOLOR_MAROON,8, // SKINCOLOR_TOXIC + SKINCOLOR_TURQUOISE,8, // SKINCOLOR_MAUVE + SKINCOLOR_GARDEN,6, // SKINCOLOR_LAVENDER + SKINCOLOR_SWAMP,8, // SKINCOLOR_BYZANTIUM + SKINCOLOR_DREAM,8, // SKINCOLOR_POMEGRANATE + SKINCOLOR_JAWZ,6, // SKINCOLOR_LILAC + SKINCOLOR_JET,8 // SKINCOLOR_TAFFY +}; + +UINT8 colortranslations[MAXTRANSLATIONS][16] = { + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SKINCOLOR_NONE + { 0, 0, 0, 0, 1, 2, 5, 8, 9, 11, 14, 17, 20, 22, 25, 28}, // SKINCOLOR_WHITE + { 0, 1, 2, 3, 5, 7, 9, 12, 13, 15, 18, 20, 23, 25, 27, 30}, // SKINCOLOR_SILVER + { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // SKINCOLOR_GREY + { 3, 5, 8, 11, 15, 17, 19, 21, 23, 24, 25, 26, 27, 29, 30, 31}, // SKINCOLOR_NICKEL + { 4, 7, 11, 15, 20, 22, 24, 27, 28, 28, 28, 29, 29, 30, 30, 31}, // SKINCOLOR_BLACK + { 0, 0, 252, 252, 200, 201, 211, 14, 16, 18, 20, 22, 24, 26, 28, 31}, // SKINCOLOR_FAIRY + { 0, 80, 80, 81, 82, 218, 240, 11, 13, 16, 18, 21, 23, 26, 28, 31}, // SKINCOLOR_POPCORN + { 80, 88, 89, 98, 99, 91, 12, 14, 16, 18, 20, 22, 24, 26, 28, 31}, // SKINCOLOR_ARTICHOKE + { 0, 128, 129, 130, 146, 170, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // SKINCOLOR_PIGEON + { 0, 1, 3, 5, 7, 9, 241, 242, 243, 245, 247, 249, 236, 237, 238, 239}, // SKINCOLOR_SEPIA + { 0, 208, 216, 217, 240, 241, 242, 243, 245, 247, 249, 250, 251, 237, 238, 239}, // SKINCOLOR_BEIGE + {208, 48, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 232, 234, 236, 239}, // SKINCOLOR_CARAMEL + { 0, 208, 48, 216, 218, 221, 212, 213, 214, 215, 206, 207, 197, 198, 199, 254}, // SKINCOLOR_PEACH + {216, 217, 219, 221, 224, 225, 227, 229, 230, 232, 234, 235, 237, 239, 29, 30}, // SKINCOLOR_BROWN + {218, 221, 224, 227, 229, 231, 233, 235, 237, 239, 28, 28, 29, 29, 30, 31}, // SKINCOLOR_LEATHER + { 0, 0, 0, 208, 208, 209, 210, 32, 34, 35, 36, 38, 40, 42, 44, 46}, // SKINCOLOR_SALMON + { 0, 208, 208, 209, 209, 210, 211, 211, 212, 213, 214, 215, 41, 43, 45, 46}, // SKINCOLOR_PINK + {209, 210, 211, 211, 212, 213, 214, 215, 41, 42, 43, 44, 45, 71, 46, 47}, // SKINCOLOR_ROSE + {216, 221, 224, 226, 228, 60, 61, 43, 44, 45, 71, 46, 47, 29, 30, 31}, // SKINCOLOR_CINNAMON + { 0, 208, 209, 210, 211, 213, 39, 40, 41, 43, 186, 186, 169, 169, 253, 254}, // SKINCOLOR_RUBY + { 0, 208, 209, 210, 32, 33, 34, 35, 37, 39, 41, 43, 44, 45, 46, 47}, // SKINCOLOR_RASPBERRY + {209, 210, 32, 34, 36, 38, 39, 40, 41, 42, 43, 44 , 45, 71, 46, 47}, // SKINCOLOR_RED + {210, 33, 35, 38, 40, 42, 43, 45, 71, 71, 46, 46, 47, 47, 30, 31}, // SKINCOLOR_CRIMSON + { 32, 33, 35, 37, 39, 41, 43, 237, 26, 26, 27, 27, 28, 29, 30, 31}, // SKINCOLOR_MAROON + { 0, 80, 81, 82, 83, 216, 210, 211, 212, 213, 214, 215, 43, 44, 71, 47}, // SKINCOLOR_LEMONADE + { 48, 49, 50, 51, 53, 34, 36, 38, 184, 185, 168, 168, 169, 169, 254, 31}, // SKINCOLOR_SCARLET + { 72, 73, 64, 51, 52, 54, 34, 36, 38, 40, 42, 43, 44, 71, 46, 47}, // SKINCOLOR_KETCHUP + { 0, 208, 216, 209, 210, 211, 212, 57, 58, 59, 60, 61, 63, 71, 47, 31}, // SKINCOLOR_DAWN + { 82, 72, 73, 64, 51, 53, 55, 213, 214, 195, 195, 173, 174, 175, 253, 254}, // SKINCOLOR_SUNSLAM + { 0, 0, 208, 208, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 63}, // SKINCOLOR_CREAMSICLE + {208, 48, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 44, 71, 47}, // SKINCOLOR_ORANGE + { 50, 52, 55, 56, 58, 59, 60, 61, 62, 63, 44, 45, 71, 46, 47, 30}, // SKINCOLOR_ROSEWOOD + { 80, 81, 82, 83, 64, 51, 52, 54, 55, 57, 58, 60, 61, 63, 71, 47}, // SKINCOLOR_TANGERINE + { 0, 80, 81, 82, 83, 84, 85, 86, 87, 245, 246, 248, 249, 251, 237, 239}, // SKINCOLOR_TAN + { 0, 80, 80, 81, 81, 49, 51, 222, 224, 227, 230, 233, 236, 239, 29, 31}, // SKINCOLOR_CREAM + { 0, 80, 81, 83, 64, 65, 66, 67, 68, 215, 69, 70, 44, 71, 46, 47}, // SKINCOLOR_GOLD + { 80, 81, 83, 64, 65, 223, 229, 196, 196, 197, 197, 198, 199, 29, 30, 31}, // SKINCOLOR_ROYAL + { 83, 64, 65, 66, 67, 215, 69, 70, 44, 44, 45, 71, 46, 47, 29, 31}, // SKINCOLOR_BRONZE + { 0, 82, 64, 65, 67, 68, 70, 237, 239, 28, 28, 29, 29, 30, 30, 31}, // SKINCOLOR_COPPER + { 0, 80, 81, 82, 83, 73, 84, 74, 64, 65, 66, 67, 68, 69, 70, 71}, // SKINCOLOR_YELLOW + { 80, 81, 82, 83, 64, 65, 65, 76, 76, 77, 77, 78, 79, 237, 239, 29}, // SKINCOLOR_MUSTARD + { 80, 81, 83, 72, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 30}, // SKINCOLOR_BANANA + { 80, 82, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 28, 29, 31}, // SKINCOLOR_OLIVE + { 0, 80, 81, 88, 88, 188, 189, 76, 76, 77, 78, 79, 236, 237, 238, 239}, // SKINCOLOR_CROCODILE + { 0, 80, 81, 88, 188, 189, 190, 191, 94, 94, 95, 95, 109, 110, 111, 31}, // SKINCOLOR_PERIDOT + { 0, 208, 216, 209, 218, 51, 65, 76, 191, 191, 126, 143, 138, 175, 169, 254}, // SKINCOLOR_VOMIT + { 81, 82, 83, 73, 64, 65, 66, 92, 92, 93, 93, 94, 95, 109, 110, 111}, // SKINCOLOR_GARDEN + { 0, 80, 81, 82, 83, 88, 89, 99, 100, 102, 104, 126, 143, 138, 139, 31}, // SKINCOLOR_LIME + { 83, 72, 73, 74, 75, 76, 102, 104, 105, 106, 107, 108, 109, 110, 111, 31}, // SKINCOLOR_HANDHELD + { 0, 80, 80, 81, 88, 89, 90, 91, 92, 93, 94, 95, 109, 110, 111, 31}, // SKINCOLOR_TEA + { 0, 80, 88, 88, 89, 90, 91, 102, 103, 104, 105, 106, 107, 108, 109, 110}, // SKINCOLOR_PISTACHIO + { 88, 89, 90, 91, 91, 92, 93, 94, 107, 107, 108, 108, 109, 109, 110, 111}, // SKINCOLOR_MOSS + {208, 84, 85, 240, 241, 243, 245, 94, 107, 108, 108, 109, 109, 110, 110, 111}, // SKINCOLOR_CAMOUFLAGE + { 0, 88, 98, 101, 103, 104, 105, 94, 94, 107, 95, 109, 110, 111, 30, 31}, // SKINCOLOR_ROBOHOOD + { 0, 88, 88, 89, 89, 100, 101, 102, 125, 126, 143, 143, 138, 175, 169, 254}, // SKINCOLOR_MINT + { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}, // SKINCOLOR_GREEN + { 97, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 30, 30, 31}, // SKINCOLOR_PINETREE + { 96, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 119, 111}, // SKINCOLOR_TURTLE + { 96, 112, 113, 114, 115, 116, 117, 118, 119, 119, 29, 29, 30, 30, 31, 31}, // SKINCOLOR_SWAMP + { 0, 0, 208, 208, 48, 89, 98, 100, 148, 148, 172, 172, 173, 173, 174, 175}, // SKINCOLOR_DREAM + { 80, 88, 96, 112, 113, 124, 142, 149, 149, 173, 174, 175, 169, 253, 254, 31}, // SKINCOLOR_PLAGUE + { 0, 120, 121, 112, 113, 114, 115, 125, 125, 126, 126, 127, 138, 175, 253, 254}, // SKINCOLOR_EMERALD + {128, 128, 129, 129, 130, 140, 124, 103, 104, 116, 116, 117, 118, 119, 111, 31}, // SKINCOLOR_ALGAE + { 0, 88, 89, 97, 113, 141, 135, 136, 136, 173, 173, 174, 174, 175, 199, 31}, // SKINCOLOR_CARIBBEAN + { 0, 80, 81, 82, 89, 140, 134, 135, 136, 172, 196, 197, 198, 199, 30, 31}, // SKINCOLOR_AZURE + { 0, 128, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 118, 118, 119, 111}, // SKINCOLOR_AQUAMARINE + {128, 120, 121, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 31}, // SKINCOLOR_TURQUOISE + { 0, 120, 120, 121, 140, 141, 142, 143, 143, 138, 138, 139, 139, 254, 254, 31}, // SKINCOLOR_TEAL + { 0, 0, 128, 128, 255, 131, 132, 134, 142, 142, 143, 127, 118, 119, 110, 111}, // SKINCOLOR_CYAN + { 0, 0, 128, 128, 129, 146, 133, 134, 135, 149, 149, 173, 173, 174, 175, 31}, // SKINCOLOR_JAWZ + { 0, 128, 129, 130, 131, 132, 133, 135, 136, 136, 137, 137, 138, 138, 139, 31}, // SKINCOLOR_CERULEAN + {128, 129, 130, 132, 134, 135, 136, 137, 137, 138, 138, 139, 139, 29, 30, 31}, // SKINCOLOR_NAVY + { 0, 0, 0, 144, 144, 145, 9, 11, 14, 142, 136, 137, 138, 138, 139, 31}, // SKINCOLOR_PLATINUM + { 0, 0, 144, 144, 144, 145, 145, 145, 170, 170, 171, 171, 172, 173, 174, 175}, // SKINCOLOR_SLATE + { 0, 144, 144, 145, 145, 170, 170, 171, 171, 172, 172, 173, 173, 174, 175, 31}, // SKINCOLOR_STEEL + { 80, 81, 82, 83, 64, 65, 11, 171, 172, 173, 173, 157, 158, 159, 254, 31}, // SKINCOLOR_THUNDER + { 0, 83, 49, 50, 51, 32, 192, 148, 148, 172, 173, 174, 175, 29, 30, 31}, // SKINCOLOR_NOVA + {208, 48, 216, 217, 240, 241, 242, 171, 172, 173, 24, 25, 26, 28, 29, 31}, // SKINCOLOR_RUST + { 48, 218, 221, 224, 227, 231, 196, 173, 173, 174, 159, 159, 253, 253, 254, 31}, // SKINCOLOR_WRISTWATCH + {145, 146, 147, 148, 149, 173, 173, 174, 175, 175, 28, 28, 29, 29, 30, 31}, // SKINCOLOR_JET + { 0, 128, 129, 131, 133, 135, 149, 150, 152, 154, 156, 158, 159, 253, 254, 31}, // SKINCOLOR_SAPPHIRE + { 0, 0, 120, 120, 121, 133, 135, 149, 149, 166, 166, 167, 168, 169, 254, 31}, // SKINCOLOR_ULTRAMARINE + { 0, 0, 144, 144, 145, 146, 147, 149, 150, 152, 154, 155, 157, 159, 253, 254}, // SKINCOLOR_PERIWINKLE + {144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 158, 253, 254, 31}, // SKINCOLOR_BLUE + {146, 148, 149, 150, 152, 153, 155, 157, 159, 253, 253, 254, 254, 31, 31, 31}, // SKINCOLOR_BLUEBERRY + { 0, 0, 0, 252, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_THISTLE + { 0, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 169, 253, 254}, // SKINCOLOR_PURPLE + { 0, 128, 128, 129, 129, 146, 170, 162, 163, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_PASTEL + { 0, 144, 145, 146, 170, 162, 163, 184, 184, 207, 207, 44, 45, 46, 47, 31}, // SKINCOLOR_MOONSET + {252, 200, 201, 192, 193, 194, 172, 172, 173, 173, 174, 174, 175, 169, 253, 254}, // SKINCOLOR_DUSK + {176, 177, 178, 179, 180, 181, 182, 183, 184, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_VIOLET + {176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 185, 186, 187, 30, 31}, // SKINCOLOR_MAGENTA + {208, 209, 209, 32, 33, 182, 183, 184, 185, 185, 186, 186, 187, 253, 254, 31}, // SKINCOLOR_FUCHSIA + { 0, 0, 88, 88, 89, 6, 8, 10, 193, 194, 195, 184, 185, 186, 187, 31}, // SKINCOLOR_TOXIC + { 80, 81, 82, 83, 64, 50, 201, 192, 193, 194, 195, 173, 174, 175, 253, 254}, // SKINCOLOR_MAUVE + {252, 177, 179, 192, 193, 194, 195, 196, 196, 197, 197, 198, 198, 199, 30, 31}, // SKINCOLOR_LAVENDER + {145, 192, 193, 194, 195, 196, 197, 198, 199, 199, 29, 29, 30, 30, 31, 31}, // SKINCOLOR_BYZANTIUM + {208, 209, 210, 211, 212, 213, 214, 195, 195, 196, 196, 197, 198, 199, 29, 30}, // SKINCOLOR_POMEGRANATE + { 0, 0, 0, 252, 252, 176, 200, 201, 179, 192, 193, 194, 195, 196, 197, 198}, // SKINCOLOR_LILAC + { 0, 252, 252, 200, 200, 201, 202, 203, 204, 204, 205, 206, 207, 43, 45, 47}, // SKINCOLOR_TAFFY + + // THESE STILL NEED CONVERTED!!! + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 100, 104, 113, 116, 119}, // SKINCOLOR_SUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 96, 98, 101, 104, 113, 115, 117, 119}, // SKINCOLOR_SUPER2 + { 0, 0, 0, 0, 0, 0, 96, 98, 100, 102, 104, 113, 114, 116, 117, 119}, // SKINCOLOR_SUPER3 + { 0, 0, 0, 0, 96, 97, 99, 100, 102, 104, 113, 114, 115, 116, 117, 119}, // SKINCOLOR_SUPER4 + { 0, 0, 96, 0, 0, 0, 0, 0, 104, 113, 114, 115, 116, 117, 118, 119}, // SKINCOLOR_SUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 82, 85, 115, 117, 119}, // SKINCOLOR_TSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 83, 85, 115, 116, 117, 119}, // SKINCOLOR_TSUPER2 + { 0, 0, 0, 0, 0, 0, 80, 81, 82, 83, 85, 115, 116, 117, 118, 119}, // SKINCOLOR_TSUPER3 + { 0, 0, 0, 0, 80, 81, 82, 83, 84, 85, 115, 115, 116, 117, 118, 119}, // SKINCOLOR_TSUPER4 + { 0, 0, 80, 80, 81, 82, 83, 84, 85, 115, 115, 116, 117, 117, 118, 119}, // SKINCOLOR_TSUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 123, 125, 127, 129, 132}, // SKINCOLOR_KSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 121, 122, 124, 125, 127, 128, 130, 132}, // SKINCOLOR_KSUPER2 + { 0, 0, 0, 0, 0, 0, 121, 122, 123, 124, 125, 127, 128, 129, 130, 132}, // SKINCOLOR_KSUPER3 + { 0, 0, 0, 0, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, // SKINCOLOR_KSUPER4 + { 0, 0, 121, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 130, 131, 132}, // SKINCOLOR_KSUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 122, 124, 248, 251, 255}, // SKINCOLOR_PSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 1, 121, 122, 124, 248, 250, 252, 255}, // SKINCOLOR_PSUPER2 + { 0, 0, 0, 0, 0, 0, 1, 121, 122, 123, 124, 248, 249, 251, 253, 255}, // SKINCOLOR_PSUPER3 + { 0, 0, 0, 0, 1, 121, 122, 123, 124, 248, 249, 250, 251, 252, 253, 255}, // SKINCOLOR_PSUPER4 + { 0, 0, 1, 121, 122, 123, 124, 248, 248, 249, 250, 251, 252, 253, 254, 255}, // SKINCOLOR_PSUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 225, 227, 228, 230, 232}, // SKINCOLOR_BSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 224, 225, 226, 227, 228, 229, 230, 232}, // SKINCOLOR_BSUPER2 + { 0, 0, 0, 0, 0, 0, 224, 224, 225, 226, 227, 228, 229, 230, 231, 232}, // SKINCOLOR_BSUPER3 + { 0, 0, 0, 0, 224, 224, 225, 226, 226, 227, 228, 229, 229, 230, 231, 232}, // SKINCOLOR_BSUPER4 + { 0, 0, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 230, 230, 231, 232}, // SKINCOLOR_BSUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 210, 212, 215, 220, 222}, // SKINCOLOR_ASUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 208, 209, 211, 213, 215, 220, 221, 223}, // SKINCOLOR_ASUPER2 + { 0, 0, 0, 0, 0, 0, 208, 209, 210, 211, 212, 213, 215, 220, 221, 223}, // SKINCOLOR_ASUPER3 + { 0, 0, 0, 0, 208, 209, 210, 211, 212, 213, 214, 215, 220, 221, 222, 223}, // SKINCOLOR_ASUPER4 + { 0, 0, 208, 208, 209, 210, 211, 211, 212, 213, 214, 215, 220, 221, 222, 223}, // SKINCOLOR_ASUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 160, 163, 167, 171, 175}, // SKINCOLOR_GSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 176, 176, 160, 163, 166, 169, 172, 175}, // SKINCOLOR_GSUPER2 + { 0, 0, 0, 0, 0, 0, 176, 176, 160, 162, 164, 166, 168, 170, 172, 175}, // SKINCOLOR_GSUPER3 + { 0, 0, 0, 0, 176, 176, 176, 160, 161, 163, 165, 167, 169, 171, 173, 175}, // SKINCOLOR_GSUPER4 + { 0, 0, 176, 176, 176, 160, 161, 163, 164, 166, 167, 169, 170, 172, 173, 175}, // SKINCOLOR_GSUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SKINCOLOR_WSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 9}, // SKINCOLOR_WSUPER2 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 8, 11}, // SKINCOLOR_WSUPER3 + { 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 4, 6, 8, 9, 11, 13}, // SKINCOLOR_WSUPER4 + { 0, 0, 0, 0, 1, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 15}, // SKINCOLOR_WSUPER5 + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 98, 99, 81, 73, 79}, // SKINCOLOR_CSUPER1 + { 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 81, 81, 71, 75, 79}, // SKINCOLOR_CSUPER2 + { 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 81, 81, 70, 73, 76, 79}, // SKINCOLOR_CSUPER3 + { 0, 0, 0, 0, 96, 96, 97, 98, 99, 81, 81, 70, 72, 74, 76, 79}, // SKINCOLOR_CSUPER4 + { 0, 0, 96, 96, 97, 98, 98, 99, 81, 81, 69, 71, 73, 75, 77, 79}, // SKINCOLOR_CSUPER5 +}; + +/*-------------------------------------------------- + UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b) + + See header file for description. +--------------------------------------------------*/ + +UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b) +{ + UINT32 redweight = 1063 * r; + UINT32 greenweight = 3576 * g; + UINT32 blueweight = 361 * b; + UINT32 brightness = (redweight + greenweight + blueweight) / 5000; + return min(brightness, UINT8_MAX); +} + +/*-------------------------------------------------- + void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) + + See header file for description. +--------------------------------------------------*/ + +void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) +{ + INT32 i; + RGBA_t color; + UINT8 brightness; + INT32 j; + UINT8 colorbrightnesses[16]; + UINT16 brightdif; + INT32 temp; + + // first generate the brightness of all the colours of that skincolour + for (i = 0; i < 16; i++) + { + color = V_GetColor(colortranslations[skincolor][i]); + colorbrightnesses[i] = K_ColorRelativeLuminance(color.s.red, color.s.green, color.s.blue); + } + + // next, for every colour in the palette, choose the transcolor that has the closest brightness + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + { + if (i == 0 || i == 31) // pure black and pure white don't change + { + dest_colormap[i] = (UINT8)i; + continue; + } + + color = V_GetColor(i); + brightness = K_ColorRelativeLuminance(color.s.red, color.s.green, color.s.blue); + brightdif = 256; + + for (j = 0; j < 16; j++) + { + temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]); + + if (temp < brightdif) + { + brightdif = (UINT16)temp; + dest_colormap[i] = colortranslations[skincolor][j]; + } + } + } +} + +/** \brief Generates a translation colormap for Kart, to replace R_GenerateTranslationColormap in r_draw.c + + \param dest_colormap colormap to populate + \param skinnum number of skin, TC_DEFAULT or TC_BOSS + \param color translation color + + \return void +*/ +void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) +{ + INT32 i; + INT32 starttranscolor; + + // Handle a couple of simple special cases + if (skinnum == TC_BOSS + || skinnum == TC_ALLWHITE + || skinnum == TC_METALSONIC + || skinnum == TC_BLINK + || color == SKINCOLOR_NONE) + { + for (i = 0; i < NUM_PALETTE_ENTRIES; i++) + { + if (skinnum == TC_ALLWHITE) + dest_colormap[i] = 0; + else if (skinnum == TC_BLINK) + dest_colormap[i] = colortranslations[color][3]; + else + dest_colormap[i] = (UINT8)i; + } + + // White! + if (skinnum == TC_BOSS) + dest_colormap[31] = 0; + else if (skinnum == TC_METALSONIC) + dest_colormap[143] = 0; + + return; + } + else if (skinnum == TC_RAINBOW) + { + K_RainbowColormap(dest_colormap, color); + return; + } + + starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; + + // Fill in the entries of the palette that are fixed + for (i = 0; i < starttranscolor; i++) + dest_colormap[i] = (UINT8)i; + + for (i = (UINT8)(starttranscolor + 16); i < NUM_PALETTE_ENTRIES; i++) + dest_colormap[i] = (UINT8)i; + + // Build the translated ramp + for (i = 0; i < SKIN_RAMP_LENGTH; i++) + { + // Sryder 2017-10-26: What was here before was most definitely not particularly readable, check above for new color translation table + dest_colormap[starttranscolor + i] = colortranslations[color][i]; + } +} + +/** \brief Pulls kart color by name, to replace R_GetColorByName in r_draw.c + + \param name color name + + \return 0 +*/ +UINT8 K_GetKartColorByName(const char *name) +{ + UINT8 color = (UINT8)atoi(name); + if (color > 0 && color < MAXSKINCOLORS) + return color; + for (color = 1; color < MAXSKINCOLORS; color++) + if (!stricmp(KartColor_Names[color], name)) + return color; + return 0; +} + +//} diff --git a/src/k_color.h b/src/k_color.h new file mode 100644 index 000000000..2a21473e2 --- /dev/null +++ b/src/k_color.h @@ -0,0 +1,87 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2020 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_color.h +/// \brief Skincolor & colormapping code + +#ifndef __K_COLOR__ +#define __K_COLOR__ + +#include "doomdef.h" +#include "doomtype.h" + +#define SKIN_RAMP_LENGTH 16 +#define DEFAULT_STARTTRANSCOLOR 96 +#define NUM_PALETTE_ENTRIES 256 + +extern UINT8 colortranslations[MAXTRANSLATIONS][16]; +extern const char *KartColor_Names[MAXSKINCOLORS]; +extern const UINT8 KartColor_Opposite[MAXSKINCOLORS*2]; + +/*-------------------------------------------------- + UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b); + + Gives you the brightness value of the provided RGB value, based on how the human eye interprets it. + See https://en.wikipedia.org/wiki/Relative_luminance for more info. + + Input Arguments:- + r - Red component + g - Green component + b - Blue component + + Return:- + Brightness value from 0 to 255. +--------------------------------------------------*/ + +UINT8 K_ColorRelativeLuminance(UINT8 r, UINT8 g, UINT8 b); + +/*-------------------------------------------------- + void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor); + + Generates a colormap to "colorize" all palette indicies + to the provided skincolor. + + Input Arguments:- + dest_colormap - Colormap to populate. + skincolor - Translation color. + + Return:- + None +--------------------------------------------------*/ + +void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor); + +/*-------------------------------------------------- + void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); + + Generates a translation colormap for Kart, to replace R_GenerateTranslationColormap in r_draw.c + + Input Arguments:- + dest_colormap - Colormap to populate. + skinnum - Number of skin or translation mode (TC_ constants) + color - Translation color. + + Return:- + None +--------------------------------------------------*/ +void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); + +/*-------------------------------------------------- + UINT8 K_GetKartColorByName(const char *name); + + Finds the corresponding SKINCOLOR_ constant to the string provided. + + Input Arguments:- + name - The name of the color desired. + + Return:- + SKINCOLOR_ constant, SKINCOLOR_NONE if invalid +--------------------------------------------------*/ +UINT8 K_GetKartColorByName(const char *name); + +#endif diff --git a/src/k_kart.c b/src/k_kart.c index 997e48bc7..ef4d821fc 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -7,6 +7,7 @@ #include "k_kart.h" #include "k_battle.h" #include "k_pwrlv.h" +#include "k_color.h" #include "doomdef.h" #include "hu_stuff.h" #include "g_game.h" @@ -37,511 +38,6 @@ // indirectitemcooldown is timer before anyone's allowed another Shrink/SPB // mapreset is set when enough players fill an empty server -//{ SRB2kart Color Code - -#define SKIN_RAMP_LENGTH 16 -#define DEFAULT_STARTTRANSCOLOR 96 -#define NUM_PALETTE_ENTRIES 256 - -// These should be within 14 characters to fit on the character select screen -const char *KartColor_Names[MAXSKINCOLORS] = -{ - "None", // SKINCOLOR_NONE - "White", // SKINCOLOR_WHITE - "Silver", // SKINCOLOR_SILVER - "Grey", // SKINCOLOR_GREY - "Nickel", // SKINCOLOR_NICKEL - "Black", // SKINCOLOR_BLACK - "Fairy", // SKINCOLOR_FAIRY - "Popcorn", // SKINCOLOR_POPCORN - "Artichoke", // SKINCOLOR_ARTICHOKE - "Pigeon", // SKINCOLOR_PIGEON - "Sepia", // SKINCOLOR_SEPIA - "Beige", // SKINCOLOR_BEIGE - "Caramel", // SKINCOLOR_CARAMEL - "Peach", // SKINCOLOR_PEACH - "Brown", // SKINCOLOR_BROWN - "Leather", // SKINCOLOR_LEATHER - "Salmon", // SKINCOLOR_SALMON - "Pink", // SKINCOLOR_PINK - "Rose", // SKINCOLOR_ROSE - "Cinnamon", // SKINCOLOR_CINNAMON - "Ruby", // SKINCOLOR_RUBY - "Raspberry", // SKINCOLOR_RASPBERRY - "Red", // SKINCOLOR_RED - "Crimson", // SKINCOLOR_CRIMSON - "Maroon", // SKINCOLOR_MAROON - "Lemonade", // SKINCOLOR_LEMONADE - "Scarlet", // SKINCOLOR_SCARLET - "Ketchup", // SKINCOLOR_KETCHUP - "Dawn", // SKINCOLOR_DAWN - "Sunslam", // SKINCOLOR_SUNSLAM - "Creamsicle", // SKINCOLOR_CREAMSICLE - "Orange", // SKINCOLOR_ORANGE - "Rosewood", // SKINCOLOR_ROSEWOOD - "Tangerine", // SKINCOLOR_TANGERINE - "Tan", // SKINCOLOR_TAN - "Cream", // SKINCOLOR_CREAM - "Gold", // SKINCOLOR_GOLD - "Royal", // SKINCOLOR_ROYAL - "Bronze", // SKINCOLOR_BRONZE - "Copper", // SKINCOLOR_COPPER - "Yellow", // SKINCOLOR_YELLOW - "Mustard", // SKINCOLOR_MUSTARD - "Banana", // SKINCOLOR_BANANA - "Olive", // SKINCOLOR_OLIVE - "Crocodile", // SKINCOLOR_CROCODILE - "Peridot", // SKINCOLOR_PERIDOT - "Vomit", // SKINCOLOR_VOMIT - "Garden", // SKINCOLOR_GARDEN - "Lime", // SKINCOLOR_LIME - "Handheld", // SKINCOLOR_HANDHELD - "Tea", // SKINCOLOR_TEA - "Pistachio", // SKINCOLOR_PISTACHIO - "Moss", // SKINCOLOR_MOSS - "Camouflage", // SKINCOLOR_CAMOUFLAGE - "Robo-Hood", // SKINCOLOR_ROBOHOOD - "Mint", // SKINCOLOR_MINT - "Green", // SKINCOLOR_GREEN - "Pinetree", // SKINCOLOR_PINETREE - "Turtle", // SKINCOLOR_TURTLE - "Swamp", // SKINCOLOR_SWAMP - "Dream", // SKINCOLOR_DREAM - "Plague", // SKINCOLOR_PLAGUE - "Emerald", // SKINCOLOR_EMERALD - "Algae", // SKINCOLOR_ALGAE - "Caribbean", // SKINCOLOR_CARIBBEAN - "Azure", // SKINCOLOR_AZURE - "Aquamarine", // SKINCOLOR_AQUAMARINE - "Turquoise", // SKINCOLOR_TURQUOISE - "Teal", // SKINCOLOR_TEAL - "Cyan", // SKINCOLOR_CYAN - "Jawz", // SKINCOLOR_JAWZ - "Cerulean", // SKINCOLOR_CERULEAN - "Navy", // SKINCOLOR_NAVY - "Platinum", // SKINCOLOR_PLATINUM - "Slate", // SKINCOLOR_SLATE - "Steel", // SKINCOLOR_STEEL - "Thunder", // SKINCOLOR_THUNDER - "Nova", // SKINCOLOR_NOVA - "Rust", // SKINCOLOR_RUST - "Wristwatch", // SKINCOLOR_WRISTWATCH - "Jet", // SKINCOLOR_JET - "Sapphire", // SKINCOLOR_SAPPHIRE - "Ultramarine", // SKINCOLOR_ULTRAMARINE - "Periwinkle", // SKINCOLOR_PERIWINKLE - "Blue", // SKINCOLOR_BLUE - "Blueberry", // SKINCOLOR_BLUEBERRY - "Thistle", // SKINCOLOR_THISTLE - "Purple", // SKINCOLOR_PURPLE - "Pastel", // SKINCOLOR_PASTEL - "Moonset", // SKINCOLOR_MOONSET - "Dusk", // SKINCOLOR_DUSK - "Violet", // SKINCOLOR_VIOLET - "Magenta", // SKINCOLOR_MAGENTA - "Fuchsia", // SKINCOLOR_FUCHSIA - "Toxic", // SKINCOLOR_TOXIC - "Mauve", // SKINCOLOR_MAUVE - "Lavender", // SKINCOLOR_LAVENDER - "Byzantium", // SKINCOLOR_BYZANTIUM - "Pomegranate", // SKINCOLOR_POMEGRANATE - "Lilac", // SKINCOLOR_LILAC - "Taffy" // SKINCOLOR_TAFFY -}; - -// Color_Opposite replacement; frame setting has not been changed from 8 for most, should be done later -const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = -{ - SKINCOLOR_NONE,8, // SKINCOLOR_NONE - SKINCOLOR_BLACK,8, // SKINCOLOR_WHITE - SKINCOLOR_NICKEL,8, // SKINCOLOR_SILVER - SKINCOLOR_GREY,8, // SKINCOLOR_GREY - SKINCOLOR_SILVER,8, // SKINCOLOR_NICKEL - SKINCOLOR_WHITE,8, // SKINCOLOR_BLACK - SKINCOLOR_ARTICHOKE,12, // SKINCOLOR_FAIRY - SKINCOLOR_PIGEON,12, // SKINCOLOR_POPCORN - SKINCOLOR_FAIRY,12, // SKINCOLOR_ARTICHOKE - SKINCOLOR_POPCORN,12, // SKINCOLOR_PIGEON - SKINCOLOR_LEATHER,6, // SKINCOLOR_SEPIA - SKINCOLOR_BROWN,2, // SKINCOLOR_BEIGE - SKINCOLOR_CERULEAN,8, // SKINCOLOR_CARAMEL - SKINCOLOR_CYAN,8, // SKINCOLOR_PEACH - SKINCOLOR_BEIGE,8, // SKINCOLOR_BROWN - SKINCOLOR_SEPIA,8, // SKINCOLOR_LEATHER - SKINCOLOR_TEA,8, // SKINCOLOR_SALMON - SKINCOLOR_PISTACHIO,8, // SKINCOLOR_PINK - SKINCOLOR_MOSS,8, // SKINCOLOR_ROSE - SKINCOLOR_WRISTWATCH,6, // SKINCOLOR_CINNAMON - SKINCOLOR_SAPPHIRE,8, // SKINCOLOR_RUBY - SKINCOLOR_MINT,8, // SKINCOLOR_RASPBERRY - SKINCOLOR_GREEN,6, // SKINCOLOR_RED - SKINCOLOR_PINETREE,6, // SKINCOLOR_CRIMSON - SKINCOLOR_TOXIC,8, // SKINCOLOR_MAROON - SKINCOLOR_THUNDER,8, // SKINCOLOR_LEMONADE - SKINCOLOR_ALGAE,10, // SKINCOLOR_SCARLET - SKINCOLOR_MUSTARD,10, // SKINCOLOR_KETCHUP - SKINCOLOR_DUSK,8, // SKINCOLOR_DAWN - SKINCOLOR_MOONSET,8, // SKINCOLOR_SUNSLAM - SKINCOLOR_PERIWINKLE,8, // SKINCOLOR_CREAMSICLE - SKINCOLOR_BLUE,8, // SKINCOLOR_ORANGE - SKINCOLOR_BLUEBERRY,6, // SKINCOLOR_ROSEWOOD - SKINCOLOR_LIME,8, // SKINCOLOR_TANGERINE - SKINCOLOR_RUST,8, // SKINCOLOR_TAN - SKINCOLOR_COPPER,10, // SKINCOLOR_CREAM - SKINCOLOR_SLATE,8, // SKINCOLOR_GOLD - SKINCOLOR_PLATINUM,6, // SKINCOLOR_ROYAL - SKINCOLOR_STEEL,8, // SKINCOLOR_BRONZE - SKINCOLOR_CREAM,6, // SKINCOLOR_COPPER - SKINCOLOR_AQUAMARINE,8, // SKINCOLOR_YELLOW - SKINCOLOR_KETCHUP,8, // SKINCOLOR_MUSTARD - SKINCOLOR_EMERALD,8, // SKINCOLOR_BANANA - SKINCOLOR_TEAL,8, // SKINCOLOR_OLIVE - SKINCOLOR_VIOLET,8, // SKINCOLOR_CROCODILE - SKINCOLOR_NAVY,6, // SKINCOLOR_PERIDOT - SKINCOLOR_ROBOHOOD,8, // SKINCOLOR_VOMIT - SKINCOLOR_LAVENDER,6, // SKINCOLOR_GARDEN - SKINCOLOR_TANGERINE,8, // SKINCOLOR_LIME - SKINCOLOR_ULTRAMARINE,8, // SKINCOLOR_HANDHELD - SKINCOLOR_SALMON,8, // SKINCOLOR_TEA - SKINCOLOR_PINK,6, // SKINCOLOR_PISTACHIO - SKINCOLOR_ROSE,8, // SKINCOLOR_MOSS - SKINCOLOR_CAMOUFLAGE,8, // SKINCOLOR_CAMOUFLAGE - SKINCOLOR_VOMIT,8, // SKINCOLOR_ROBOHOOD - SKINCOLOR_RASPBERRY,8, // SKINCOLOR_MINT - SKINCOLOR_RED,8, // SKINCOLOR_GREEN - SKINCOLOR_CRIMSON,8, // SKINCOLOR_PINETREE - SKINCOLOR_MAGENTA,8, // SKINCOLOR_TURTLE - SKINCOLOR_BYZANTIUM,8, // SKINCOLOR_SWAMP - SKINCOLOR_POMEGRANATE,8, // SKINCOLOR_DREAM - SKINCOLOR_NOVA,8, // SKINCOLOR_PLAGUE - SKINCOLOR_BANANA,8, // SKINCOLOR_EMERALD - SKINCOLOR_SCARLET,10, // SKINCOLOR_ALGAE - SKINCOLOR_PURPLE,8, // SKINCOLOR_CARIBBEAN - SKINCOLOR_THISTLE,8, // SKINCOLOR_AZURE - SKINCOLOR_YELLOW,8, // SKINCOLOR_AQUAMARINE - SKINCOLOR_MAUVE,10, // SKINCOLOR_TURQUOISE - SKINCOLOR_OLIVE,8, // SKINCOLOR_TEAL - SKINCOLOR_PEACH,8, // SKINCOLOR_CYAN - SKINCOLOR_LILAC,10, // SKINCOLOR_JAWZ - SKINCOLOR_CARAMEL,8, // SKINCOLOR_CERULEAN - SKINCOLOR_PERIDOT,8, // SKINCOLOR_NAVY - SKINCOLOR_ROYAL,8, // SKINCOLOR_PLATINUM - SKINCOLOR_GOLD,10, // SKINCOLOR_SLATE - SKINCOLOR_BRONZE,10, // SKINCOLOR_STEEL - SKINCOLOR_LEMONADE,8, // SKINCOLOR_THUNDER - SKINCOLOR_PLAGUE,10, // SKINCOLOR_NOVA - SKINCOLOR_TAN,8, // SKINCOLOR_RUST - SKINCOLOR_CINNAMON,8, // SKINCOLOR_WRISTWATCH - SKINCOLOR_TAFFY,8, // SKINCOLOR_JET - SKINCOLOR_RUBY,6, // SKINCOLOR_SAPPHIRE - SKINCOLOR_HANDHELD,10, // SKINCOLOR_ULTRAMARINE - SKINCOLOR_CREAMSICLE,8, // SKINCOLOR_PERIWINKLE - SKINCOLOR_ORANGE,8, // SKINCOLOR_BLUE - SKINCOLOR_ROSEWOOD,8, // SKINCOLOR_BLUEBERRY - SKINCOLOR_AZURE,8, // SKINCOLOR_THISTLE - SKINCOLOR_CARIBBEAN,10, // SKINCOLOR_PURPLE - SKINCOLOR_FUCHSIA,11, // SKINCOLOR_PASTEL - SKINCOLOR_SUNSLAM,10, // SKINCOLOR_MOONSET - SKINCOLOR_DAWN,6, // SKINCOLOR_DUSK - SKINCOLOR_CROCODILE,8, // SKINCOLOR_VIOLET - SKINCOLOR_TURTLE,8, // SKINCOLOR_MAGENTA - SKINCOLOR_PASTEL,11, // SKINCOLOR_FUCHSIA - SKINCOLOR_MAROON,8, // SKINCOLOR_TOXIC - SKINCOLOR_TURQUOISE,8, // SKINCOLOR_MAUVE - SKINCOLOR_GARDEN,6, // SKINCOLOR_LAVENDER - SKINCOLOR_SWAMP,8, // SKINCOLOR_BYZANTIUM - SKINCOLOR_DREAM,8, // SKINCOLOR_POMEGRANATE - SKINCOLOR_JAWZ,6, // SKINCOLOR_LILAC - SKINCOLOR_JET,8 // SKINCOLOR_TAFFY -}; - -UINT8 colortranslations[MAXTRANSLATIONS][16] = { - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SKINCOLOR_NONE - { 0, 0, 0, 0, 1, 2, 5, 8, 9, 11, 14, 17, 20, 22, 25, 28}, // SKINCOLOR_WHITE - { 0, 1, 2, 3, 5, 7, 9, 12, 13, 15, 18, 20, 23, 25, 27, 30}, // SKINCOLOR_SILVER - { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // SKINCOLOR_GREY - { 3, 5, 8, 11, 15, 17, 19, 21, 23, 24, 25, 26, 27, 29, 30, 31}, // SKINCOLOR_NICKEL - { 4, 7, 11, 15, 20, 22, 24, 27, 28, 28, 28, 29, 29, 30, 30, 31}, // SKINCOLOR_BLACK - { 0, 0, 252, 252, 200, 201, 211, 14, 16, 18, 20, 22, 24, 26, 28, 31}, // SKINCOLOR_FAIRY - { 0, 80, 80, 81, 82, 218, 240, 11, 13, 16, 18, 21, 23, 26, 28, 31}, // SKINCOLOR_POPCORN - { 80, 88, 89, 98, 99, 91, 12, 14, 16, 18, 20, 22, 24, 26, 28, 31}, // SKINCOLOR_ARTICHOKE - { 0, 128, 129, 130, 146, 170, 14, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // SKINCOLOR_PIGEON - { 0, 1, 3, 5, 7, 9, 241, 242, 243, 245, 247, 249, 236, 237, 238, 239}, // SKINCOLOR_SEPIA - { 0, 208, 216, 217, 240, 241, 242, 243, 245, 247, 249, 250, 251, 237, 238, 239}, // SKINCOLOR_BEIGE - {208, 48, 216, 217, 218, 220, 221, 223, 224, 226, 228, 230, 232, 234, 236, 239}, // SKINCOLOR_CARAMEL - { 0, 208, 48, 216, 218, 221, 212, 213, 214, 215, 206, 207, 197, 198, 199, 254}, // SKINCOLOR_PEACH - {216, 217, 219, 221, 224, 225, 227, 229, 230, 232, 234, 235, 237, 239, 29, 30}, // SKINCOLOR_BROWN - {218, 221, 224, 227, 229, 231, 233, 235, 237, 239, 28, 28, 29, 29, 30, 31}, // SKINCOLOR_LEATHER - { 0, 0, 0, 208, 208, 209, 210, 32, 34, 35, 36, 38, 40, 42, 44, 46}, // SKINCOLOR_SALMON - { 0, 208, 208, 209, 209, 210, 211, 211, 212, 213, 214, 215, 41, 43, 45, 46}, // SKINCOLOR_PINK - {209, 210, 211, 211, 212, 213, 214, 215, 41, 42, 43, 44, 45, 71, 46, 47}, // SKINCOLOR_ROSE - {216, 221, 224, 226, 228, 60, 61, 43, 44, 45, 71, 46, 47, 29, 30, 31}, // SKINCOLOR_CINNAMON - { 0, 208, 209, 210, 211, 213, 39, 40, 41, 43, 186, 186, 169, 169, 253, 254}, // SKINCOLOR_RUBY - { 0, 208, 209, 210, 32, 33, 34, 35, 37, 39, 41, 43, 44, 45, 46, 47}, // SKINCOLOR_RASPBERRY - {209, 210, 32, 34, 36, 38, 39, 40, 41, 42, 43, 44 , 45, 71, 46, 47}, // SKINCOLOR_RED - {210, 33, 35, 38, 40, 42, 43, 45, 71, 71, 46, 46, 47, 47, 30, 31}, // SKINCOLOR_CRIMSON - { 32, 33, 35, 37, 39, 41, 43, 237, 26, 26, 27, 27, 28, 29, 30, 31}, // SKINCOLOR_MAROON - { 0, 80, 81, 82, 83, 216, 210, 211, 212, 213, 214, 215, 43, 44, 71, 47}, // SKINCOLOR_LEMONADE - { 48, 49, 50, 51, 53, 34, 36, 38, 184, 185, 168, 168, 169, 169, 254, 31}, // SKINCOLOR_SCARLET - { 72, 73, 64, 51, 52, 54, 34, 36, 38, 40, 42, 43, 44, 71, 46, 47}, // SKINCOLOR_KETCHUP - { 0, 208, 216, 209, 210, 211, 212, 57, 58, 59, 60, 61, 63, 71, 47, 31}, // SKINCOLOR_DAWN - { 82, 72, 73, 64, 51, 53, 55, 213, 214, 195, 195, 173, 174, 175, 253, 254}, // SKINCOLOR_SUNSLAM - { 0, 0, 208, 208, 48, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 63}, // SKINCOLOR_CREAMSICLE - {208, 48, 49, 50, 51, 52, 53, 54, 55, 57, 59, 60, 62, 44, 71, 47}, // SKINCOLOR_ORANGE - { 50, 52, 55, 56, 58, 59, 60, 61, 62, 63, 44, 45, 71, 46, 47, 30}, // SKINCOLOR_ROSEWOOD - { 80, 81, 82, 83, 64, 51, 52, 54, 55, 57, 58, 60, 61, 63, 71, 47}, // SKINCOLOR_TANGERINE - { 0, 80, 81, 82, 83, 84, 85, 86, 87, 245, 246, 248, 249, 251, 237, 239}, // SKINCOLOR_TAN - { 0, 80, 80, 81, 81, 49, 51, 222, 224, 227, 230, 233, 236, 239, 29, 31}, // SKINCOLOR_CREAM - { 0, 80, 81, 83, 64, 65, 66, 67, 68, 215, 69, 70, 44, 71, 46, 47}, // SKINCOLOR_GOLD - { 80, 81, 83, 64, 65, 223, 229, 196, 196, 197, 197, 198, 199, 29, 30, 31}, // SKINCOLOR_ROYAL - { 83, 64, 65, 66, 67, 215, 69, 70, 44, 44, 45, 71, 46, 47, 29, 31}, // SKINCOLOR_BRONZE - { 0, 82, 64, 65, 67, 68, 70, 237, 239, 28, 28, 29, 29, 30, 30, 31}, // SKINCOLOR_COPPER - { 0, 80, 81, 82, 83, 73, 84, 74, 64, 65, 66, 67, 68, 69, 70, 71}, // SKINCOLOR_YELLOW - { 80, 81, 82, 83, 64, 65, 65, 76, 76, 77, 77, 78, 79, 237, 239, 29}, // SKINCOLOR_MUSTARD - { 80, 81, 83, 72, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 30}, // SKINCOLOR_BANANA - { 80, 82, 73, 74, 75, 76, 77, 78, 79, 236, 237, 238, 239, 28, 29, 31}, // SKINCOLOR_OLIVE - { 0, 80, 81, 88, 88, 188, 189, 76, 76, 77, 78, 79, 236, 237, 238, 239}, // SKINCOLOR_CROCODILE - { 0, 80, 81, 88, 188, 189, 190, 191, 94, 94, 95, 95, 109, 110, 111, 31}, // SKINCOLOR_PERIDOT - { 0, 208, 216, 209, 218, 51, 65, 76, 191, 191, 126, 143, 138, 175, 169, 254}, // SKINCOLOR_VOMIT - { 81, 82, 83, 73, 64, 65, 66, 92, 92, 93, 93, 94, 95, 109, 110, 111}, // SKINCOLOR_GARDEN - { 0, 80, 81, 82, 83, 88, 89, 99, 100, 102, 104, 126, 143, 138, 139, 31}, // SKINCOLOR_LIME - { 83, 72, 73, 74, 75, 76, 102, 104, 105, 106, 107, 108, 109, 110, 111, 31}, // SKINCOLOR_HANDHELD - { 0, 80, 80, 81, 88, 89, 90, 91, 92, 93, 94, 95, 109, 110, 111, 31}, // SKINCOLOR_TEA - { 0, 80, 88, 88, 89, 90, 91, 102, 103, 104, 105, 106, 107, 108, 109, 110}, // SKINCOLOR_PISTACHIO - { 88, 89, 90, 91, 91, 92, 93, 94, 107, 107, 108, 108, 109, 109, 110, 111}, // SKINCOLOR_MOSS - {208, 84, 85, 240, 241, 243, 245, 94, 107, 108, 108, 109, 109, 110, 110, 111}, // SKINCOLOR_CAMOUFLAGE - { 0, 88, 98, 101, 103, 104, 105, 94, 94, 107, 95, 109, 110, 111, 30, 31}, // SKINCOLOR_ROBOHOOD - { 0, 88, 88, 89, 89, 100, 101, 102, 125, 126, 143, 143, 138, 175, 169, 254}, // SKINCOLOR_MINT - { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}, // SKINCOLOR_GREEN - { 97, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 30, 30, 31}, // SKINCOLOR_PINETREE - { 96, 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 119, 111}, // SKINCOLOR_TURTLE - { 96, 112, 113, 114, 115, 116, 117, 118, 119, 119, 29, 29, 30, 30, 31, 31}, // SKINCOLOR_SWAMP - { 0, 0, 208, 208, 48, 89, 98, 100, 148, 148, 172, 172, 173, 173, 174, 175}, // SKINCOLOR_DREAM - { 80, 88, 96, 112, 113, 124, 142, 149, 149, 173, 174, 175, 169, 253, 254, 31}, // SKINCOLOR_PLAGUE - { 0, 120, 121, 112, 113, 114, 115, 125, 125, 126, 126, 127, 138, 175, 253, 254}, // SKINCOLOR_EMERALD - {128, 128, 129, 129, 130, 140, 124, 103, 104, 116, 116, 117, 118, 119, 111, 31}, // SKINCOLOR_ALGAE - { 0, 88, 89, 97, 113, 141, 135, 136, 136, 173, 173, 174, 174, 175, 199, 31}, // SKINCOLOR_CARIBBEAN - { 0, 80, 81, 82, 89, 140, 134, 135, 136, 172, 196, 197, 198, 199, 30, 31}, // SKINCOLOR_AZURE - { 0, 128, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 118, 118, 119, 111}, // SKINCOLOR_AQUAMARINE - {128, 120, 121, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 31}, // SKINCOLOR_TURQUOISE - { 0, 120, 120, 121, 140, 141, 142, 143, 143, 138, 138, 139, 139, 254, 254, 31}, // SKINCOLOR_TEAL - { 0, 0, 128, 128, 255, 131, 132, 134, 142, 142, 143, 127, 118, 119, 110, 111}, // SKINCOLOR_CYAN - { 0, 0, 128, 128, 129, 146, 133, 134, 135, 149, 149, 173, 173, 174, 175, 31}, // SKINCOLOR_JAWZ - { 0, 128, 129, 130, 131, 132, 133, 135, 136, 136, 137, 137, 138, 138, 139, 31}, // SKINCOLOR_CERULEAN - {128, 129, 130, 132, 134, 135, 136, 137, 137, 138, 138, 139, 139, 29, 30, 31}, // SKINCOLOR_NAVY - { 0, 0, 0, 144, 144, 145, 9, 11, 14, 142, 136, 137, 138, 138, 139, 31}, // SKINCOLOR_PLATINUM - { 0, 0, 144, 144, 144, 145, 145, 145, 170, 170, 171, 171, 172, 173, 174, 175}, // SKINCOLOR_SLATE - { 0, 144, 144, 145, 145, 170, 170, 171, 171, 172, 172, 173, 173, 174, 175, 31}, // SKINCOLOR_STEEL - { 80, 81, 82, 83, 64, 65, 11, 171, 172, 173, 173, 157, 158, 159, 254, 31}, // SKINCOLOR_THUNDER - { 0, 83, 49, 50, 51, 32, 192, 148, 148, 172, 173, 174, 175, 29, 30, 31}, // SKINCOLOR_NOVA - {208, 48, 216, 217, 240, 241, 242, 171, 172, 173, 24, 25, 26, 28, 29, 31}, // SKINCOLOR_RUST - { 48, 218, 221, 224, 227, 231, 196, 173, 173, 174, 159, 159, 253, 253, 254, 31}, // SKINCOLOR_WRISTWATCH - {145, 146, 147, 148, 149, 173, 173, 174, 175, 175, 28, 28, 29, 29, 30, 31}, // SKINCOLOR_JET - { 0, 128, 129, 131, 133, 135, 149, 150, 152, 154, 156, 158, 159, 253, 254, 31}, // SKINCOLOR_SAPPHIRE - { 0, 0, 120, 120, 121, 133, 135, 149, 149, 166, 166, 167, 168, 169, 254, 31}, // SKINCOLOR_ULTRAMARINE - { 0, 0, 144, 144, 145, 146, 147, 149, 150, 152, 154, 155, 157, 159, 253, 254}, // SKINCOLOR_PERIWINKLE - {144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 158, 253, 254, 31}, // SKINCOLOR_BLUE - {146, 148, 149, 150, 152, 153, 155, 157, 159, 253, 253, 254, 254, 31, 31, 31}, // SKINCOLOR_BLUEBERRY - { 0, 0, 0, 252, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_THISTLE - { 0, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 169, 253, 254}, // SKINCOLOR_PURPLE - { 0, 128, 128, 129, 129, 146, 170, 162, 163, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_PASTEL - { 0, 144, 145, 146, 170, 162, 163, 184, 184, 207, 207, 44, 45, 46, 47, 31}, // SKINCOLOR_MOONSET - {252, 200, 201, 192, 193, 194, 172, 172, 173, 173, 174, 174, 175, 169, 253, 254}, // SKINCOLOR_DUSK - {176, 177, 178, 179, 180, 181, 182, 183, 184, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_VIOLET - {176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 185, 186, 187, 30, 31}, // SKINCOLOR_MAGENTA - {208, 209, 209, 32, 33, 182, 183, 184, 185, 185, 186, 186, 187, 253, 254, 31}, // SKINCOLOR_FUCHSIA - { 0, 0, 88, 88, 89, 6, 8, 10, 193, 194, 195, 184, 185, 186, 187, 31}, // SKINCOLOR_TOXIC - { 80, 81, 82, 83, 64, 50, 201, 192, 193, 194, 195, 173, 174, 175, 253, 254}, // SKINCOLOR_MAUVE - {252, 177, 179, 192, 193, 194, 195, 196, 196, 197, 197, 198, 198, 199, 30, 31}, // SKINCOLOR_LAVENDER - {145, 192, 193, 194, 195, 196, 197, 198, 199, 199, 29, 29, 30, 30, 31, 31}, // SKINCOLOR_BYZANTIUM - {208, 209, 210, 211, 212, 213, 214, 195, 195, 196, 196, 197, 198, 199, 29, 30}, // SKINCOLOR_POMEGRANATE - { 0, 0, 0, 252, 252, 176, 200, 201, 179, 192, 193, 194, 195, 196, 197, 198}, // SKINCOLOR_LILAC - { 0, 252, 252, 200, 200, 201, 202, 203, 204, 204, 205, 206, 207, 43, 45, 47}, // SKINCOLOR_TAFFY - - // THESE STILL NEED CONVERTED!!! - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 100, 104, 113, 116, 119}, // SKINCOLOR_SUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 96, 98, 101, 104, 113, 115, 117, 119}, // SKINCOLOR_SUPER2 - { 0, 0, 0, 0, 0, 0, 96, 98, 100, 102, 104, 113, 114, 116, 117, 119}, // SKINCOLOR_SUPER3 - { 0, 0, 0, 0, 96, 97, 99, 100, 102, 104, 113, 114, 115, 116, 117, 119}, // SKINCOLOR_SUPER4 - { 0, 0, 96, 0, 0, 0, 0, 0, 104, 113, 114, 115, 116, 117, 118, 119}, // SKINCOLOR_SUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80, 82, 85, 115, 117, 119}, // SKINCOLOR_TSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 80, 81, 83, 85, 115, 116, 117, 119}, // SKINCOLOR_TSUPER2 - { 0, 0, 0, 0, 0, 0, 80, 81, 82, 83, 85, 115, 116, 117, 118, 119}, // SKINCOLOR_TSUPER3 - { 0, 0, 0, 0, 80, 81, 82, 83, 84, 85, 115, 115, 116, 117, 118, 119}, // SKINCOLOR_TSUPER4 - { 0, 0, 80, 80, 81, 82, 83, 84, 85, 115, 115, 116, 117, 117, 118, 119}, // SKINCOLOR_TSUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 121, 123, 125, 127, 129, 132}, // SKINCOLOR_KSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 121, 122, 124, 125, 127, 128, 130, 132}, // SKINCOLOR_KSUPER2 - { 0, 0, 0, 0, 0, 0, 121, 122, 123, 124, 125, 127, 128, 129, 130, 132}, // SKINCOLOR_KSUPER3 - { 0, 0, 0, 0, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132}, // SKINCOLOR_KSUPER4 - { 0, 0, 121, 121, 122, 123, 124, 125, 126, 126, 127, 128, 129, 130, 131, 132}, // SKINCOLOR_KSUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 122, 124, 248, 251, 255}, // SKINCOLOR_PSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 1, 121, 122, 124, 248, 250, 252, 255}, // SKINCOLOR_PSUPER2 - { 0, 0, 0, 0, 0, 0, 1, 121, 122, 123, 124, 248, 249, 251, 253, 255}, // SKINCOLOR_PSUPER3 - { 0, 0, 0, 0, 1, 121, 122, 123, 124, 248, 249, 250, 251, 252, 253, 255}, // SKINCOLOR_PSUPER4 - { 0, 0, 1, 121, 122, 123, 124, 248, 248, 249, 250, 251, 252, 253, 254, 255}, // SKINCOLOR_PSUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 224, 225, 227, 228, 230, 232}, // SKINCOLOR_BSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 224, 225, 226, 227, 228, 229, 230, 232}, // SKINCOLOR_BSUPER2 - { 0, 0, 0, 0, 0, 0, 224, 224, 225, 226, 227, 228, 229, 230, 231, 232}, // SKINCOLOR_BSUPER3 - { 0, 0, 0, 0, 224, 224, 225, 226, 226, 227, 228, 229, 229, 230, 231, 232}, // SKINCOLOR_BSUPER4 - { 0, 0, 224, 224, 225, 225, 226, 227, 227, 228, 228, 229, 230, 230, 231, 232}, // SKINCOLOR_BSUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 208, 210, 212, 215, 220, 222}, // SKINCOLOR_ASUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 208, 209, 211, 213, 215, 220, 221, 223}, // SKINCOLOR_ASUPER2 - { 0, 0, 0, 0, 0, 0, 208, 209, 210, 211, 212, 213, 215, 220, 221, 223}, // SKINCOLOR_ASUPER3 - { 0, 0, 0, 0, 208, 209, 210, 211, 212, 213, 214, 215, 220, 221, 222, 223}, // SKINCOLOR_ASUPER4 - { 0, 0, 208, 208, 209, 210, 211, 211, 212, 213, 214, 215, 220, 221, 222, 223}, // SKINCOLOR_ASUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 176, 160, 163, 167, 171, 175}, // SKINCOLOR_GSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 176, 176, 160, 163, 166, 169, 172, 175}, // SKINCOLOR_GSUPER2 - { 0, 0, 0, 0, 0, 0, 176, 176, 160, 162, 164, 166, 168, 170, 172, 175}, // SKINCOLOR_GSUPER3 - { 0, 0, 0, 0, 176, 176, 176, 160, 161, 163, 165, 167, 169, 171, 173, 175}, // SKINCOLOR_GSUPER4 - { 0, 0, 176, 176, 176, 160, 161, 163, 164, 166, 167, 169, 170, 172, 173, 175}, // SKINCOLOR_GSUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, // SKINCOLOR_WSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 4, 9}, // SKINCOLOR_WSUPER2 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 4, 6, 8, 11}, // SKINCOLOR_WSUPER3 - { 0, 0, 0, 0, 0, 0, 0, 1, 1, 3, 4, 6, 8, 9, 11, 13}, // SKINCOLOR_WSUPER4 - { 0, 0, 0, 0, 1, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 15}, // SKINCOLOR_WSUPER5 - { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 98, 99, 81, 73, 79}, // SKINCOLOR_CSUPER1 - { 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 81, 81, 71, 75, 79}, // SKINCOLOR_CSUPER2 - { 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 81, 81, 70, 73, 76, 79}, // SKINCOLOR_CSUPER3 - { 0, 0, 0, 0, 96, 96, 97, 98, 99, 81, 81, 70, 72, 74, 76, 79}, // SKINCOLOR_CSUPER4 - { 0, 0, 96, 96, 97, 98, 98, 99, 81, 81, 69, 71, 73, 75, 77, 79}, // SKINCOLOR_CSUPER5 -}; - -// Define for getting accurate color brightness readings according to how the human eye sees them. -// https://en.wikipedia.org/wiki/Relative_luminance -// 0.2126 to red -// 0.7152 to green -// 0.0722 to blue -// (See this same define in hw_md2.c!) -#define SETBRIGHTNESS(brightness,r,g,b) \ - brightness = (UINT8)(((1063*(UINT16)(r))/5000) + ((3576*(UINT16)(g))/5000) + ((361*(UINT16)(b))/5000)) - -/** \brief Generates the rainbow colourmaps that are used when a player has the invincibility power - - \param dest_colormap colormap to populate - \param skincolor translation color -*/ -void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor) -{ - INT32 i; - RGBA_t color; - UINT8 brightness; - INT32 j; - UINT8 colorbrightnesses[16]; - UINT16 brightdif; - INT32 temp; - - // first generate the brightness of all the colours of that skincolour - for (i = 0; i < 16; i++) - { - color = V_GetColor(colortranslations[skincolor][i]); - SETBRIGHTNESS(colorbrightnesses[i], color.s.red, color.s.green, color.s.blue); - } - - // next, for every colour in the palette, choose the transcolor that has the closest brightness - for (i = 0; i < NUM_PALETTE_ENTRIES; i++) - { - if (i == 0 || i == 31) // pure black and pure white don't change - { - dest_colormap[i] = (UINT8)i; - continue; - } - color = V_GetColor(i); - SETBRIGHTNESS(brightness, color.s.red, color.s.green, color.s.blue); - brightdif = 256; - for (j = 0; j < 16; j++) - { - temp = abs((INT16)brightness - (INT16)colorbrightnesses[j]); - if (temp < brightdif) - { - brightdif = (UINT16)temp; - dest_colormap[i] = colortranslations[skincolor][j]; - } - } - } -} - -#undef SETBRIGHTNESS - -/** \brief Generates a translation colormap for Kart, to replace R_GenerateTranslationColormap in r_draw.c - - \param dest_colormap colormap to populate - \param skinnum number of skin, TC_DEFAULT or TC_BOSS - \param color translation color - - \return void -*/ -void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color) -{ - INT32 i; - INT32 starttranscolor; - - // Handle a couple of simple special cases - if (skinnum == TC_BOSS - || skinnum == TC_ALLWHITE - || skinnum == TC_METALSONIC - || skinnum == TC_BLINK - || color == SKINCOLOR_NONE) - { - for (i = 0; i < NUM_PALETTE_ENTRIES; i++) - { - if (skinnum == TC_ALLWHITE) - dest_colormap[i] = 0; - else if (skinnum == TC_BLINK) - dest_colormap[i] = colortranslations[color][3]; - else - dest_colormap[i] = (UINT8)i; - } - - // White! - if (skinnum == TC_BOSS) - dest_colormap[31] = 0; - else if (skinnum == TC_METALSONIC) - dest_colormap[143] = 0; - - return; - } - else if (skinnum == TC_RAINBOW) - { - K_RainbowColormap(dest_colormap, color); - return; - } - - starttranscolor = (skinnum != TC_DEFAULT) ? skins[skinnum].starttranscolor : DEFAULT_STARTTRANSCOLOR; - - // Fill in the entries of the palette that are fixed - for (i = 0; i < starttranscolor; i++) - dest_colormap[i] = (UINT8)i; - - for (i = (UINT8)(starttranscolor + 16); i < NUM_PALETTE_ENTRIES; i++) - dest_colormap[i] = (UINT8)i; - - // Build the translated ramp - for (i = 0; i < SKIN_RAMP_LENGTH; i++) - { - // Sryder 2017-10-26: What was here before was most definitely not particularly readable, check above for new color translation table - dest_colormap[starttranscolor + i] = colortranslations[color][i]; - } -} - -/** \brief Pulls kart color by name, to replace R_GetColorByName in r_draw.c - - \param name color name - - \return 0 -*/ -UINT8 K_GetKartColorByName(const char *name) -{ - UINT8 color = (UINT8)atoi(name); - if (color > 0 && color < MAXSKINCOLORS) - return color; - for (color = 1; color < MAXSKINCOLORS; color++) - if (!stricmp(KartColor_Names[color], name)) - return color; - return 0; -} - -//} - player_t *K_GetItemBoxPlayer(mobj_t *mobj) { fixed_t closest = INT32_MAX; diff --git a/src/k_kart.h b/src/k_kart.h index d250435c6..156fa3e80 100644 --- a/src/k_kart.h +++ b/src/k_kart.h @@ -12,12 +12,6 @@ #define KART_FULLTURN 800 -UINT8 colortranslations[MAXTRANSLATIONS][16]; -extern const char *KartColor_Names[MAXSKINCOLORS]; -extern const UINT8 KartColor_Opposite[MAXSKINCOLORS*2]; -void K_RainbowColormap(UINT8 *dest_colormap, UINT8 skincolor); -void K_GenerateKartColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color); -UINT8 K_GetKartColorByName(const char *name); player_t *K_GetItemBoxPlayer(mobj_t *mobj); void K_RegisterKartStuff(void); diff --git a/src/lua_baselib.c b/src/lua_baselib.c index a9b02aa5f..138773d01 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -27,6 +27,7 @@ #include "console.h" #include "k_kart.h" // SRB2Kart #include "k_battle.h" +#include "k_color.h" #include "d_netcmd.h" // IsPlayerAdmin #include "lua_script.h" diff --git a/src/lua_mathlib.c b/src/lua_mathlib.c index 8c9d10062..b86a03c3b 100644 --- a/src/lua_mathlib.c +++ b/src/lua_mathlib.c @@ -16,7 +16,7 @@ #include "tables.h" #include "p_local.h" #include "doomstat.h" // for ALL7EMERALDS -#include "k_kart.h" // KartColor_Opposite +#include "k_color.h" // KartColor_Opposite #include "lua_script.h" #include "lua_libs.h" diff --git a/src/m_cond.c b/src/m_cond.c index e91ac1273..6ed684ea9 100644 --- a/src/m_cond.c +++ b/src/m_cond.c @@ -20,7 +20,7 @@ #include "g_game.h" // record info #include "r_things.h" // numskins //#include "r_draw.h" // R_GetColorByName -#include "k_kart.h" // K_GetKartColorByName +#include "k_color.h" // K_GetKartColorByName #include "k_pwrlv.h" // Map triggers for linedef executors diff --git a/src/m_menu.c b/src/m_menu.c index 3abf64476..390f50572 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -59,6 +59,7 @@ #include "k_kart.h" // SRB2kart #include "k_pwrlv.h" #include "d_player.h" // KITEM_ constants +#include "k_color.h" #include "i_joy.h" // for joystick menu controls diff --git a/src/p_mobj.c b/src/p_mobj.c index aa04ccac9..174cb0322 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -37,6 +37,7 @@ #include "k_kart.h" #include "k_battle.h" +#include "k_color.h" // protos. //static CV_PossibleValue_t viewheight_cons_t[] = {{16, "MIN"}, {56, "MAX"}, {0, NULL}}; diff --git a/src/r_draw.c b/src/r_draw.c index 70e487342..7746693bf 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -25,7 +25,7 @@ #include "w_wad.h" #include "z_zone.h" #include "console.h" // Until buffering gets finished -#include "k_kart.h" // SRB2kart +#include "k_color.h" // SRB2kart #ifdef HWRENDER #include "hardware/hw_main.h" diff --git a/src/r_things.c b/src/r_things.c index 587be375d..56c7216ac 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -28,7 +28,7 @@ #include "dehacked.h" // get_number (for thok) #include "d_netfil.h" // blargh. for nameonly(). #include "m_cheat.h" // objectplace -#include "k_kart.h" // SRB2kart +#include "k_color.h" // SRB2kart #include "p_local.h" // stplyr #ifdef HWRENDER #include "hardware/hw_md2.h" diff --git a/src/y_inter.c b/src/y_inter.c index 7b76c46ed..34eb3130a 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -38,7 +38,7 @@ #include "m_random.h" // M_RandomKey #include "g_input.h" // PLAYER1INPUTDOWN -#include "k_kart.h" // colortranslations +#include "k_color.h" // colortranslations #include "k_battle.h" #include "k_pwrlv.h" #include "console.h" // cons_menuhighlight From 45e2f03846caab54cf194161a9295a54b7ba2d36 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 11 May 2020 23:46:37 -0400 Subject: [PATCH 04/34] New colors - Removed Salmon, Robo-Hood, Caribbean, and Azure. - Added Skunk, Robin, Blueberry, and Blossom. - Updated Lime, Algae, Violet and Magenta. - Renamed old Blueberry to Midnight. --- src/dehacked.c | 8 ++++---- src/doomdef.h | 8 ++++---- src/hu_stuff.c | 10 +++++----- src/info.c | 6 +++--- src/k_color.c | 44 ++++++++++++++++++++++---------------------- src/screen.c | 2 +- 6 files changed, 39 insertions(+), 39 deletions(-) diff --git a/src/dehacked.c b/src/dehacked.c index 23bac2689..c5f336492 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -8283,6 +8283,7 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "GREY", // SKINCOLOR_GREY "NICKEL", // SKINCOLOR_NICKEL "BLACK", // SKINCOLOR_BLACK + "SKUNK", // SKINCOLOR_SKUNK "FAIRY", // SKINCOLOR_FAIRY "POPCORN", // SKINCOLOR_POPCORN "ARTICHOKE", // SKINCOLOR_ARTICHOKE @@ -8293,7 +8294,6 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "PEACH", // SKINCOLOR_PEACH "BROWN", // SKINCOLOR_BROWN "LEATHER", // SKINCOLOR_LEATHER - "SALMON", // SKINCOLOR_SALMON "PINK", // SKINCOLOR_PINK "ROSE", // SKINCOLOR_ROSE "CINNAMON", // SKINCOLOR_CINNAMON @@ -8331,7 +8331,6 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "PISTACHIO", // SKINCOLOR_PISTACHIO "MOSS", // SKINCOLOR_MOSS "CAMOUFLAGE", // SKINCOLOR_CAMOUFLAGE - "ROBOHOOD", // SKINCOLOR_ROBOHOOD "MINT", // SKINCOLOR_MINT "GREEN", // SKINCOLOR_GREEN "PINETREE", // SKINCOLOR_PINETREE @@ -8341,11 +8340,10 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "PLAGUE", // SKINCOLOR_PLAGUE "EMERALD", // SKINCOLOR_EMERALD "ALGAE", // SKINCOLOR_ALGAE - "CARIBBEAN", // SKINCOLOR_CARIBBEAN - "AZURE", // SKINCOLOR_AZURE "AQUAMARINE", // SKINCOLOR_AQUAMARINE "TURQUOISE", // SKINCOLOR_TURQUOISE "TEAL", // SKINCOLOR_TEAL + "ROBIN", // SKINCOLOR_ROBIN "CYAN", // SKINCOLOR_CYAN "JAWZ", // SKINCOLOR_JAWZ "CERULEAN", // SKINCOLOR_CERULEAN @@ -8362,6 +8360,7 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "ULTRAMARINE", // SKINCOLOR_ULTRAMARINE "PERIWINKLE", // SKINCOLOR_PERIWINKLE "BLUE", // SKINCOLOR_BLUE + "MIDNIGHT", // SKINCOLOR_MIDNIGHT "BLUEBERRY", // SKINCOLOR_BLUEBERRY "THISTLE", // SKINCOLOR_THISTLE "PURPLE", // SKINCOLOR_PURPLE @@ -8377,6 +8376,7 @@ static const char *COLOR_ENUMS[] = { // Rejigged for Kart. "BYZANTIUM", // SKINCOLOR_BYZANTIUM "POMEGRANATE", // SKINCOLOR_POMEGRANATE "LILAC", // SKINCOLOR_LILAC + "BLOSSOM", // SKINCOLOR_BLOSSOM "TAFFY", // SKINCOLOR_TAFFY // Special super colors diff --git a/src/doomdef.h b/src/doomdef.h index 2a67ce0e2..c816a090d 100644 --- a/src/doomdef.h +++ b/src/doomdef.h @@ -259,6 +259,7 @@ typedef enum SKINCOLOR_GREY, SKINCOLOR_NICKEL, SKINCOLOR_BLACK, + SKINCOLOR_SKUNK, SKINCOLOR_FAIRY, SKINCOLOR_POPCORN, SKINCOLOR_ARTICHOKE, @@ -269,7 +270,6 @@ typedef enum SKINCOLOR_PEACH, SKINCOLOR_BROWN, SKINCOLOR_LEATHER, - SKINCOLOR_SALMON, SKINCOLOR_PINK, SKINCOLOR_ROSE, SKINCOLOR_CINNAMON, @@ -307,7 +307,6 @@ typedef enum SKINCOLOR_PISTACHIO, SKINCOLOR_MOSS, SKINCOLOR_CAMOUFLAGE, - SKINCOLOR_ROBOHOOD, SKINCOLOR_MINT, SKINCOLOR_GREEN, SKINCOLOR_PINETREE, @@ -317,11 +316,10 @@ typedef enum SKINCOLOR_PLAGUE, SKINCOLOR_EMERALD, SKINCOLOR_ALGAE, - SKINCOLOR_CARIBBEAN, - SKINCOLOR_AZURE, SKINCOLOR_AQUAMARINE, SKINCOLOR_TURQUOISE, SKINCOLOR_TEAL, + SKINCOLOR_ROBIN, SKINCOLOR_CYAN, SKINCOLOR_JAWZ, // Oni's torment SKINCOLOR_CERULEAN, @@ -338,6 +336,7 @@ typedef enum SKINCOLOR_ULTRAMARINE, SKINCOLOR_PERIWINKLE, SKINCOLOR_BLUE, + SKINCOLOR_MIDNIGHT, SKINCOLOR_BLUEBERRY, SKINCOLOR_THISTLE, SKINCOLOR_PURPLE, @@ -353,6 +352,7 @@ typedef enum SKINCOLOR_BYZANTIUM, SKINCOLOR_POMEGRANATE, SKINCOLOR_LILAC, + SKINCOLOR_BLOSSOM, SKINCOLOR_TAFFY, // "Careful! MAXSKINCOLORS cannot be greater than 0x40 -- Which it is now." diff --git a/src/hu_stuff.c b/src/hu_stuff.c index faa92c95e..1a559a26b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -796,6 +796,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_GREY: case SKINCOLOR_NICKEL: case SKINCOLOR_BLACK: + case SKINCOLOR_SKUNK: case SKINCOLOR_PLATINUM: case SKINCOLOR_JET: cstart = "\x86"; // V_GRAYMAP @@ -811,11 +812,11 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) cstart = "\x8e"; // V_BROWNMAP break; case SKINCOLOR_FAIRY: - case SKINCOLOR_SALMON: case SKINCOLOR_PINK: case SKINCOLOR_ROSE: case SKINCOLOR_LEMONADE: case SKINCOLOR_LILAC: + case SKINCOLOR_BLOSSOM: case SKINCOLOR_TAFFY: cstart = "\x8d"; // V_PINKMAP break; @@ -866,7 +867,6 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_PISTACHIO: case SKINCOLOR_MOSS: case SKINCOLOR_CAMOUFLAGE: - case SKINCOLOR_ROBOHOOD: case SKINCOLOR_MINT: case SKINCOLOR_GREEN: case SKINCOLOR_PINETREE: @@ -878,14 +878,13 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_ALGAE: cstart = "\x83"; // V_GREENMAP break; - case SKINCOLOR_CARIBBEAN: - case SKINCOLOR_AZURE: case SKINCOLOR_AQUAMARINE: case SKINCOLOR_TURQUOISE: case SKINCOLOR_TEAL: cstart = "\x8b"; // V_AQUAMAP break; case SKINCOLOR_PIGEON: + case SKINCOLOR_ROBIN: case SKINCOLOR_CYAN: case SKINCOLOR_JAWZ: case SKINCOLOR_CERULEAN: @@ -897,6 +896,7 @@ static void Got_Saycmd(UINT8 **p, INT32 playernum) case SKINCOLOR_ULTRAMARINE: case SKINCOLOR_PERIWINKLE: case SKINCOLOR_BLUE: + case SKINCOLOR_MIDNIGHT: case SKINCOLOR_BLUEBERRY: case SKINCOLOR_NOVA: cstart = "\x84"; // V_BLUEMAP @@ -2504,7 +2504,7 @@ Ping_gfx_num (int ping) void HU_drawPing(INT32 x, INT32 y, UINT32 ping, INT32 flags) { INT32 gfxnum; // gfx to draw - UINT8 const *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SALMON, GTC_CACHE); + UINT8 const *colormap = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE); gfxnum = Ping_gfx_num(ping); diff --git a/src/info.c b/src/info.c index 989b1aa27..6a51028cb 100644 --- a/src/info.c +++ b/src/info.c @@ -6157,7 +6157,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - SKINCOLOR_SALMON, // painchance + SKINCOLOR_RASPBERRY, // painchance sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate @@ -6265,7 +6265,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - SKINCOLOR_SALMON, // painchance + SKINCOLOR_RASPBERRY, // painchance sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate @@ -6373,7 +6373,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 8, // reactiontime sfx_None, // attacksound S_NULL, // painstate - SKINCOLOR_SALMON, // painchance + SKINCOLOR_RASPBERRY, // painchance sfx_s3kb1, // painsound S_NULL, // meleestate S_NULL, // missilestate diff --git a/src/k_color.c b/src/k_color.c index a838f833a..a51cf418d 100644 --- a/src/k_color.c +++ b/src/k_color.c @@ -27,6 +27,7 @@ const char *KartColor_Names[MAXSKINCOLORS] = "Grey", // SKINCOLOR_GREY "Nickel", // SKINCOLOR_NICKEL "Black", // SKINCOLOR_BLACK + "Skunk", // SKINCOLOR_SKUNK "Fairy", // SKINCOLOR_FAIRY "Popcorn", // SKINCOLOR_POPCORN "Artichoke", // SKINCOLOR_ARTICHOKE @@ -37,7 +38,6 @@ const char *KartColor_Names[MAXSKINCOLORS] = "Peach", // SKINCOLOR_PEACH "Brown", // SKINCOLOR_BROWN "Leather", // SKINCOLOR_LEATHER - "Salmon", // SKINCOLOR_SALMON "Pink", // SKINCOLOR_PINK "Rose", // SKINCOLOR_ROSE "Cinnamon", // SKINCOLOR_CINNAMON @@ -75,7 +75,6 @@ const char *KartColor_Names[MAXSKINCOLORS] = "Pistachio", // SKINCOLOR_PISTACHIO "Moss", // SKINCOLOR_MOSS "Camouflage", // SKINCOLOR_CAMOUFLAGE - "Robo-Hood", // SKINCOLOR_ROBOHOOD "Mint", // SKINCOLOR_MINT "Green", // SKINCOLOR_GREEN "Pinetree", // SKINCOLOR_PINETREE @@ -85,11 +84,10 @@ const char *KartColor_Names[MAXSKINCOLORS] = "Plague", // SKINCOLOR_PLAGUE "Emerald", // SKINCOLOR_EMERALD "Algae", // SKINCOLOR_ALGAE - "Caribbean", // SKINCOLOR_CARIBBEAN - "Azure", // SKINCOLOR_AZURE "Aquamarine", // SKINCOLOR_AQUAMARINE "Turquoise", // SKINCOLOR_TURQUOISE "Teal", // SKINCOLOR_TEAL + "Robin", // SKINCOLOR_ROBIN "Cyan", // SKINCOLOR_CYAN "Jawz", // SKINCOLOR_JAWZ "Cerulean", // SKINCOLOR_CERULEAN @@ -106,6 +104,7 @@ const char *KartColor_Names[MAXSKINCOLORS] = "Ultramarine", // SKINCOLOR_ULTRAMARINE "Periwinkle", // SKINCOLOR_PERIWINKLE "Blue", // SKINCOLOR_BLUE + "Midnight", // SKINCOLOR_MIDNIGHT "Blueberry", // SKINCOLOR_BLUEBERRY "Thistle", // SKINCOLOR_THISTLE "Purple", // SKINCOLOR_PURPLE @@ -121,6 +120,7 @@ const char *KartColor_Names[MAXSKINCOLORS] = "Byzantium", // SKINCOLOR_BYZANTIUM "Pomegranate", // SKINCOLOR_POMEGRANATE "Lilac", // SKINCOLOR_LILAC + "Blossom", // SKINCOLOR_BLOSSOM "Taffy" // SKINCOLOR_TAFFY }; @@ -133,6 +133,7 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_GREY,8, // SKINCOLOR_GREY SKINCOLOR_SILVER,8, // SKINCOLOR_NICKEL SKINCOLOR_WHITE,8, // SKINCOLOR_BLACK + SKINCOLOR_VOMIT,8, // SKINCOLOR_SKUNK SKINCOLOR_ARTICHOKE,12, // SKINCOLOR_FAIRY SKINCOLOR_PIGEON,12, // SKINCOLOR_POPCORN SKINCOLOR_FAIRY,12, // SKINCOLOR_ARTICHOKE @@ -143,7 +144,6 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_CYAN,8, // SKINCOLOR_PEACH SKINCOLOR_BEIGE,8, // SKINCOLOR_BROWN SKINCOLOR_SEPIA,8, // SKINCOLOR_LEATHER - SKINCOLOR_TEA,8, // SKINCOLOR_SALMON SKINCOLOR_PISTACHIO,8, // SKINCOLOR_PINK SKINCOLOR_MOSS,8, // SKINCOLOR_ROSE SKINCOLOR_WRISTWATCH,6, // SKINCOLOR_CINNAMON @@ -173,15 +173,14 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_TEAL,8, // SKINCOLOR_OLIVE SKINCOLOR_VIOLET,8, // SKINCOLOR_CROCODILE SKINCOLOR_NAVY,6, // SKINCOLOR_PERIDOT - SKINCOLOR_ROBOHOOD,8, // SKINCOLOR_VOMIT + SKINCOLOR_SKUNK,8, // SKINCOLOR_VOMIT SKINCOLOR_LAVENDER,6, // SKINCOLOR_GARDEN SKINCOLOR_TANGERINE,8, // SKINCOLOR_LIME SKINCOLOR_ULTRAMARINE,8, // SKINCOLOR_HANDHELD - SKINCOLOR_SALMON,8, // SKINCOLOR_TEA + SKINCOLOR_BLOSSOM,8, // SKINCOLOR_TEA SKINCOLOR_PINK,6, // SKINCOLOR_PISTACHIO SKINCOLOR_ROSE,8, // SKINCOLOR_MOSS SKINCOLOR_CAMOUFLAGE,8, // SKINCOLOR_CAMOUFLAGE - SKINCOLOR_VOMIT,8, // SKINCOLOR_ROBOHOOD SKINCOLOR_RASPBERRY,8, // SKINCOLOR_MINT SKINCOLOR_RED,8, // SKINCOLOR_GREEN SKINCOLOR_CRIMSON,8, // SKINCOLOR_PINETREE @@ -191,11 +190,10 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_NOVA,8, // SKINCOLOR_PLAGUE SKINCOLOR_BANANA,8, // SKINCOLOR_EMERALD SKINCOLOR_SCARLET,10, // SKINCOLOR_ALGAE - SKINCOLOR_PURPLE,8, // SKINCOLOR_CARIBBEAN - SKINCOLOR_THISTLE,8, // SKINCOLOR_AZURE SKINCOLOR_YELLOW,8, // SKINCOLOR_AQUAMARINE SKINCOLOR_MAUVE,10, // SKINCOLOR_TURQUOISE SKINCOLOR_OLIVE,8, // SKINCOLOR_TEAL + SKINCOLOR_THISTLE,8, // SKINCOLOR_ROBIN SKINCOLOR_PEACH,8, // SKINCOLOR_CYAN SKINCOLOR_LILAC,10, // SKINCOLOR_JAWZ SKINCOLOR_CARAMEL,8, // SKINCOLOR_CERULEAN @@ -212,9 +210,10 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_HANDHELD,10, // SKINCOLOR_ULTRAMARINE SKINCOLOR_CREAMSICLE,8, // SKINCOLOR_PERIWINKLE SKINCOLOR_ORANGE,8, // SKINCOLOR_BLUE - SKINCOLOR_ROSEWOOD,8, // SKINCOLOR_BLUEBERRY - SKINCOLOR_AZURE,8, // SKINCOLOR_THISTLE - SKINCOLOR_CARIBBEAN,10, // SKINCOLOR_PURPLE + SKINCOLOR_ROSEWOOD,8, // SKINCOLOR_MIDNIGHT + SKINCOLOR_PURPLE,8, // SKINCOLOR_BLUEBERRY + SKINCOLOR_ROBIN,8, // SKINCOLOR_THISTLE + SKINCOLOR_MIDNIGHT,10, // SKINCOLOR_PURPLE SKINCOLOR_FUCHSIA,11, // SKINCOLOR_PASTEL SKINCOLOR_SUNSLAM,10, // SKINCOLOR_MOONSET SKINCOLOR_DAWN,6, // SKINCOLOR_DUSK @@ -227,6 +226,7 @@ const UINT8 KartColor_Opposite[MAXSKINCOLORS*2] = SKINCOLOR_SWAMP,8, // SKINCOLOR_BYZANTIUM SKINCOLOR_DREAM,8, // SKINCOLOR_POMEGRANATE SKINCOLOR_JAWZ,6, // SKINCOLOR_LILAC + SKINCOLOR_TEA,8, // SKINCOLOR_BLOSSOM SKINCOLOR_JET,8 // SKINCOLOR_TAFFY }; @@ -237,6 +237,7 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = { { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31}, // SKINCOLOR_GREY { 3, 5, 8, 11, 15, 17, 19, 21, 23, 24, 25, 26, 27, 29, 30, 31}, // SKINCOLOR_NICKEL { 4, 7, 11, 15, 20, 22, 24, 27, 28, 28, 28, 29, 29, 30, 30, 31}, // SKINCOLOR_BLACK + { 0, 1, 2, 3, 4, 10, 16, 21, 23, 24, 25, 26, 27, 28, 29, 31}, // SKINCOLOR_SKUNK { 0, 0, 252, 252, 200, 201, 211, 14, 16, 18, 20, 22, 24, 26, 28, 31}, // SKINCOLOR_FAIRY { 0, 80, 80, 81, 82, 218, 240, 11, 13, 16, 18, 21, 23, 26, 28, 31}, // SKINCOLOR_POPCORN { 80, 88, 89, 98, 99, 91, 12, 14, 16, 18, 20, 22, 24, 26, 28, 31}, // SKINCOLOR_ARTICHOKE @@ -247,7 +248,6 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = { { 0, 208, 48, 216, 218, 221, 212, 213, 214, 215, 206, 207, 197, 198, 199, 254}, // SKINCOLOR_PEACH {216, 217, 219, 221, 224, 225, 227, 229, 230, 232, 234, 235, 237, 239, 29, 30}, // SKINCOLOR_BROWN {218, 221, 224, 227, 229, 231, 233, 235, 237, 239, 28, 28, 29, 29, 30, 31}, // SKINCOLOR_LEATHER - { 0, 0, 0, 208, 208, 209, 210, 32, 34, 35, 36, 38, 40, 42, 44, 46}, // SKINCOLOR_SALMON { 0, 208, 208, 209, 209, 210, 211, 211, 212, 213, 214, 215, 41, 43, 45, 46}, // SKINCOLOR_PINK {209, 210, 211, 211, 212, 213, 214, 215, 41, 42, 43, 44, 45, 71, 46, 47}, // SKINCOLOR_ROSE {216, 221, 224, 226, 228, 60, 61, 43, 44, 45, 71, 46, 47, 29, 30, 31}, // SKINCOLOR_CINNAMON @@ -279,13 +279,12 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = { { 0, 80, 81, 88, 188, 189, 190, 191, 94, 94, 95, 95, 109, 110, 111, 31}, // SKINCOLOR_PERIDOT { 0, 208, 216, 209, 218, 51, 65, 76, 191, 191, 126, 143, 138, 175, 169, 254}, // SKINCOLOR_VOMIT { 81, 82, 83, 73, 64, 65, 66, 92, 92, 93, 93, 94, 95, 109, 110, 111}, // SKINCOLOR_GARDEN - { 0, 80, 81, 82, 83, 88, 89, 99, 100, 102, 104, 126, 143, 138, 139, 31}, // SKINCOLOR_LIME + { 0, 80, 81, 88, 188, 189, 114, 114, 115, 115, 116, 116, 117, 118, 119, 111}, // SKINCOLOR_LIME { 83, 72, 73, 74, 75, 76, 102, 104, 105, 106, 107, 108, 109, 110, 111, 31}, // SKINCOLOR_HANDHELD { 0, 80, 80, 81, 88, 89, 90, 91, 92, 93, 94, 95, 109, 110, 111, 31}, // SKINCOLOR_TEA { 0, 80, 88, 88, 89, 90, 91, 102, 103, 104, 105, 106, 107, 108, 109, 110}, // SKINCOLOR_PISTACHIO { 88, 89, 90, 91, 91, 92, 93, 94, 107, 107, 108, 108, 109, 109, 110, 111}, // SKINCOLOR_MOSS {208, 84, 85, 240, 241, 243, 245, 94, 107, 108, 108, 109, 109, 110, 110, 111}, // SKINCOLOR_CAMOUFLAGE - { 0, 88, 98, 101, 103, 104, 105, 94, 94, 107, 95, 109, 110, 111, 30, 31}, // SKINCOLOR_ROBOHOOD { 0, 88, 88, 89, 89, 100, 101, 102, 125, 126, 143, 143, 138, 175, 169, 254}, // SKINCOLOR_MINT { 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111}, // SKINCOLOR_GREEN { 97, 99, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 30, 30, 31}, // SKINCOLOR_PINETREE @@ -294,12 +293,11 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = { { 0, 0, 208, 208, 48, 89, 98, 100, 148, 148, 172, 172, 173, 173, 174, 175}, // SKINCOLOR_DREAM { 80, 88, 96, 112, 113, 124, 142, 149, 149, 173, 174, 175, 169, 253, 254, 31}, // SKINCOLOR_PLAGUE { 0, 120, 121, 112, 113, 114, 115, 125, 125, 126, 126, 127, 138, 175, 253, 254}, // SKINCOLOR_EMERALD - {128, 128, 129, 129, 130, 140, 124, 103, 104, 116, 116, 117, 118, 119, 111, 31}, // SKINCOLOR_ALGAE - { 0, 88, 89, 97, 113, 141, 135, 136, 136, 173, 173, 174, 174, 175, 199, 31}, // SKINCOLOR_CARIBBEAN - { 0, 80, 81, 82, 89, 140, 134, 135, 136, 172, 196, 197, 198, 199, 30, 31}, // SKINCOLOR_AZURE + {128, 129, 130, 131, 132, 133, 134, 115, 115, 116, 116, 117, 118, 119, 110, 111}, // SKINCOLOR_ALGAE { 0, 128, 120, 121, 122, 123, 124, 125, 126, 126, 127, 127, 118, 118, 119, 111}, // SKINCOLOR_AQUAMARINE {128, 120, 121, 122, 123, 141, 141, 142, 142, 143, 143, 138, 138, 139, 139, 31}, // SKINCOLOR_TURQUOISE { 0, 120, 120, 121, 140, 141, 142, 143, 143, 138, 138, 139, 139, 254, 254, 31}, // SKINCOLOR_TEAL + { 0, 80, 81, 82, 83, 88, 121, 140, 133, 133, 134, 135, 136, 137, 138, 139}, // SKINCOLOR_ROBIN { 0, 0, 128, 128, 255, 131, 132, 134, 142, 142, 143, 127, 118, 119, 110, 111}, // SKINCOLOR_CYAN { 0, 0, 128, 128, 129, 146, 133, 134, 135, 149, 149, 173, 173, 174, 175, 31}, // SKINCOLOR_JAWZ { 0, 128, 129, 130, 131, 132, 133, 135, 136, 136, 137, 137, 138, 138, 139, 31}, // SKINCOLOR_CERULEAN @@ -316,14 +314,15 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = { { 0, 0, 120, 120, 121, 133, 135, 149, 149, 166, 166, 167, 168, 169, 254, 31}, // SKINCOLOR_ULTRAMARINE { 0, 0, 144, 144, 145, 146, 147, 149, 150, 152, 154, 155, 157, 159, 253, 254}, // SKINCOLOR_PERIWINKLE {144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 155, 156, 158, 253, 254, 31}, // SKINCOLOR_BLUE - {146, 148, 149, 150, 152, 153, 155, 157, 159, 253, 253, 254, 254, 31, 31, 31}, // SKINCOLOR_BLUEBERRY + {146, 148, 149, 150, 152, 153, 155, 157, 159, 253, 253, 254, 254, 31, 31, 31}, // SKINCOLOR_MIDNIGHT + { 0, 144, 145, 146, 147, 171, 172, 166, 166, 167, 167, 168, 168, 175, 169, 253}, // SKINCOLOR_BLUEBERRY { 0, 0, 0, 252, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_THISTLE { 0, 252, 160, 161, 162, 163, 164, 165, 166, 167, 168, 168, 169, 169, 253, 254}, // SKINCOLOR_PURPLE { 0, 128, 128, 129, 129, 146, 170, 162, 163, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_PASTEL { 0, 144, 145, 146, 170, 162, 163, 184, 184, 207, 207, 44, 45, 46, 47, 31}, // SKINCOLOR_MOONSET {252, 200, 201, 192, 193, 194, 172, 172, 173, 173, 174, 174, 175, 169, 253, 254}, // SKINCOLOR_DUSK - {176, 177, 178, 179, 180, 181, 182, 183, 184, 164, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_VIOLET - {176, 177, 178, 179, 180, 181, 182, 183, 184, 184, 185, 185, 186, 187, 30, 31}, // SKINCOLOR_MAGENTA + {176, 177, 178, 179, 180, 181, 182, 183, 184, 165, 165, 166, 167, 168, 169, 254}, // SKINCOLOR_VIOLET + {252, 200, 177, 177, 178, 179, 180, 181, 182, 183, 183, 184, 185, 186, 187, 31}, // SKINCOLOR_MAGENTA {208, 209, 209, 32, 33, 182, 183, 184, 185, 185, 186, 186, 187, 253, 254, 31}, // SKINCOLOR_FUCHSIA { 0, 0, 88, 88, 89, 6, 8, 10, 193, 194, 195, 184, 185, 186, 187, 31}, // SKINCOLOR_TOXIC { 80, 81, 82, 83, 64, 50, 201, 192, 193, 194, 195, 173, 174, 175, 253, 254}, // SKINCOLOR_MAUVE @@ -331,6 +330,7 @@ UINT8 colortranslations[MAXTRANSLATIONS][16] = { {145, 192, 193, 194, 195, 196, 197, 198, 199, 199, 29, 29, 30, 30, 31, 31}, // SKINCOLOR_BYZANTIUM {208, 209, 210, 211, 212, 213, 214, 195, 195, 196, 196, 197, 198, 199, 29, 30}, // SKINCOLOR_POMEGRANATE { 0, 0, 0, 252, 252, 176, 200, 201, 179, 192, 193, 194, 195, 196, 197, 198}, // SKINCOLOR_LILAC + { 0, 252, 252, 176, 200, 177, 201, 202, 202, 34, 36, 38, 40, 42, 45, 46}, // SKINCOLOR_BLOSSOM { 0, 252, 252, 200, 200, 201, 202, 203, 204, 204, 205, 206, 207, 43, 45, 47}, // SKINCOLOR_TAFFY // THESE STILL NEED CONVERTED!!! diff --git a/src/screen.c b/src/screen.c index 5b38f82db..651c9f481 100644 --- a/src/screen.c +++ b/src/screen.c @@ -418,7 +418,7 @@ void SCR_DisplayTicRate(void) if (fpsgraph[i]) ++totaltics; - if (totaltics <= TICRATE/2) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_SALMON, GTC_CACHE); + if (totaltics <= TICRATE/2) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_RASPBERRY, GTC_CACHE); else if (totaltics == TICRATE) ticcntcolor = R_GetTranslationColormap(TC_RAINBOW, SKINCOLOR_MINT, GTC_CACHE); /*V_DrawString(vid.width-(24*vid.dupx), vid.height-(16*vid.dupy), From fc789790bb8747e053d2a12d083566c4e5fd4a39 Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Thu, 14 May 2020 17:28:33 +0200 Subject: [PATCH 05/34] Create a quick P_StartQuake without epicenter/radius support and clean up the grand total of 4 earthquake uses in the code --- src/k_kart.c | 9 +++------ src/lua_baselib.c | 3 +-- src/p_inter.c | 7 ++----- src/p_spec.c | 8 ++++++++ src/p_spec.h | 4 ++++ 5 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index 2610de1f5..eac5c4bad 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3157,10 +3157,7 @@ void K_ExplodePlayer(player_t *player, mobj_t *source, mobj_t *inflictor) // A b K_PlayPainSound(player->mo); if (P_IsDisplayPlayer(player)) - { - quake.intensity = 64*FRACUNIT; - quake.time = 5; - } + P_StartQuake(64<kartstuff[k_instashield] = 15; K_DropItems(player); @@ -5244,7 +5241,7 @@ static void K_MoveHeldObjects(player_t *player) if (cur->type == MT_EGGMANITEM_SHIELD) { // Decided that this should use their "canon" color. - cur->color = SKINCOLOR_BLACK; + cur->color = SKINCOLOR_BLACK; } cur->flags &= ~MF_NOCLIPTHING; @@ -5613,7 +5610,7 @@ static void K_UpdateInvincibilitySounds(player_t *player) { if (player->kartstuff[k_invincibilitytimer] > 0) // Prioritize invincibility sfxnum = sfx_alarmi; - else if (player->kartstuff[k_growshrinktimer] > 0) + else if (player->kartstuff[k_growshrinktimer] > 0) sfxnum = sfx_alarmg; } else diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 421af0238..21342d936 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -1518,8 +1518,7 @@ static int lib_pStartQuake(lua_State *L) quake.radius = luaL_optinteger(L, 4, 512*FRACUNIT); // These things are actually used in 2.1. - quake.intensity = q_intensity; - quake.time = q_time; + P_StartQuake(q_intensity, q_time); return 0; } diff --git a/src/p_inter.c b/src/p_inter.c index 56885f56f..8286b6e3d 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -638,7 +638,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_SetTarget(&special->tracer, toucher); toucher->flags |= MF_NOGRAVITY; toucher->momz = (8*toucher->scale) * P_MobjFlip(toucher); - S_StartSound(toucher, sfx_s1b2); + S_StartSound(toucher, sfx_s1b2); return; // ***************************************** // @@ -3192,10 +3192,7 @@ boolean P_DamageMobj(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 da K_KartPainEnergyFling(player); if (P_IsDisplayPlayer(player)) - { - quake.intensity = 32*FRACUNIT; - quake.time = 5; - } + P_StartQuake(32< Date: Thu, 14 May 2020 17:55:33 +0200 Subject: [PATCH 06/34] Make explosions cause earthquakes and initiate flashpals --- src/doomstat.h | 1 + src/g_game.c | 1 + src/k_kart.c | 26 ++++++++++++++++++++++++++ src/p_tick.c | 3 +++ 4 files changed, 31 insertions(+) diff --git a/src/doomstat.h b/src/doomstat.h index 9971fdfc5..cffecce9a 100644 --- a/src/doomstat.h +++ b/src/doomstat.h @@ -513,6 +513,7 @@ extern tic_t mapreset; extern boolean thwompsactive; extern SINT8 spbplace; +extern tic_t bombflashtimer; // Used to avoid causing seizures if multiple mines explode close to you :) extern boolean legitimateexit; extern boolean comebackshowninfo; extern tic_t curlap, bestlap; diff --git a/src/g_game.c b/src/g_game.c index 11cc2fbe8..4eafb9103 100644 --- a/src/g_game.c +++ b/src/g_game.c @@ -288,6 +288,7 @@ boolean thwompsactive; // Thwomps activate on lap 2 SINT8 spbplace; // SPB exists, give the person behind better items // Client-sided, unsynched variables (NEVER use in anything that needs to be synced with other players) +tic_t bombflashtimer = 0; // Cooldown before another FlashPal can be intialized by a bomb exploding near a displayplayer. Avoids seizures. boolean legitimateexit; // Did this client actually finish the match? boolean comebackshowninfo; // Have you already seen the "ATTACK OR PROTECT" message? tic_t curlap; // Current lap time diff --git a/src/k_kart.c b/src/k_kart.c index eac5c4bad..e8b126e43 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3321,6 +3321,8 @@ void K_SpawnKartExplosion(fixed_t x, fixed_t y, fixed_t z, fixed_t radius, INT32 } } +#define MINEQUAKEDIST 4096 + // Spawns the purely visual explosion void K_SpawnMineExplosion(mobj_t *source, UINT8 color) { @@ -3329,6 +3331,28 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) mobj_t *dust; mobj_t *truc; INT32 speed, speed2; + INT32 pnum; + player_t *p; + + // check for potential display players near the source so we can have a sick earthquake / flashpal. + for (pnum = 0; pnum < MAXPLAYERS; pnum++) + { + p = &players[pnum]; + + if (!playeringame[pnum] || !P_IsDisplayPlayer(p)) + continue; + + if (R_PointToDist2(p->mo->x, p->mo->y, source->x, source->y) < mapobjectscale*MINEQUAKEDIST) + { + P_StartQuake(55<mo, source)) + { + bombflashtimer = TICRATE*5; + P_FlashPal(p, 1, 1); + } + break; // we can break right now because quakes are global to all split players somehow. + } + } K_MatchGenericExtraFlags(smoldering, source); smoldering->tics = TICRATE*3; @@ -3399,6 +3423,8 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) } } +#undef MINEQUAKEDIST + static mobj_t *K_SpawnKartMissile(mobj_t *source, mobjtype_t type, angle_t an, INT32 flags2, fixed_t speed) { mobj_t *th; diff --git a/src/p_tick.c b/src/p_tick.c index 385985c34..d57a6dc43 100644 --- a/src/p_tick.c +++ b/src/p_tick.c @@ -722,6 +722,9 @@ void P_Ticker(boolean run) K_CalculateBattleWanted(); } + if (bombflashtimer) + bombflashtimer--; // Bomb seizure prevention + if (quake.time) { fixed_t ir = quake.intensity>>1; From ff756ae35c5e755983846d7e9573ff915079212f Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 15 May 2020 23:49:17 -0400 Subject: [PATCH 07/34] OGL sprite support --- src/hardware/hw_main.c | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 303676eed..4a4b6d600 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -2831,6 +2831,10 @@ static boolean HWR_DoCulling(line_t *cullheight, line_t *viewcullheight, float v static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) { + const fixed_t thingxpos = thing->x + thing->sprxoff; + const fixed_t thingypos = thing->y + thing->spryoff; + const fixed_t thingzpos = thing->z + thing->sprzoff; + GLPatch_t *gpatch; FOutVector shadowVerts[4]; FSurfaceInfo sSurf; @@ -2848,7 +2852,7 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) pslope_t *floorslope; floorz = R_GetShadowZ(thing, &floorslope); - floordiff = abs(thing->z - floorz); + floordiff = abs(thingzpos - floorz); alpha = floordiff / (4*FRACUNIT) + 75; if (alpha >= 255) return; @@ -2872,8 +2876,8 @@ static void HWR_DrawDropShadow(mobj_t *thing, fixed_t scale) scalemul = FixedMul(scalemul, (thing->radius*2) / gpatch->height); fscale = FIXED_TO_FLOAT(scalemul); - fx = FIXED_TO_FLOAT(thing->x); - fy = FIXED_TO_FLOAT(thing->y); + fx = FIXED_TO_FLOAT(thingxpos); + fy = FIXED_TO_FLOAT(thingypos); // 3--2 // | /| @@ -4096,6 +4100,10 @@ void HWR_AddSprites(sector_t *sec) // BP why not use xtoviexangle/viewangletox like in bsp ?.... void HWR_ProjectSprite(mobj_t *thing) { + const fixed_t thingxpos = thing->x + thing->sprxoff; + const fixed_t thingypos = thing->y + thing->spryoff; + const fixed_t thingzpos = thing->z + thing->sprzoff; + gr_vissprite_t *vis; float tr_x, tr_y; float tz; @@ -4120,8 +4128,8 @@ void HWR_ProjectSprite(mobj_t *thing) this_scale = FIXED_TO_FLOAT(thing->scale); // transform the origin point - tr_x = FIXED_TO_FLOAT(thing->x) - gr_viewx; - tr_y = FIXED_TO_FLOAT(thing->y) - gr_viewy; + tr_x = FIXED_TO_FLOAT(thingxpos) - gr_viewx; + tr_y = FIXED_TO_FLOAT(thingypos) - gr_viewy; // rotation around vertical axis tz = (tr_x * gr_viewcos) + (tr_y * gr_viewsin); @@ -4131,8 +4139,8 @@ void HWR_ProjectSprite(mobj_t *thing) return; // The above can stay as it works for cutting sprites that are too close - tr_x = FIXED_TO_FLOAT(thing->x); - tr_y = FIXED_TO_FLOAT(thing->y); + tr_x = FIXED_TO_FLOAT(thingxpos); + tr_y = FIXED_TO_FLOAT(thingypos); // decide which patch to use for sprite relative to player #ifdef RANGECHECK @@ -4168,9 +4176,9 @@ void HWR_ProjectSprite(mobj_t *thing) #endif if (thing->player) - ang = R_PointToAngle (thing->x, thing->y) - thing->player->frameangle; + ang = R_PointToAngle (thingxpos, thingypos) - thing->player->frameangle; else - ang = R_PointToAngle (thing->x, thing->y) - thing->angle; + ang = R_PointToAngle (thingxpos, thingypos) - thing->angle; if (sprframe->rotate == SRF_SINGLE) { @@ -4242,12 +4250,12 @@ void HWR_ProjectSprite(mobj_t *thing) if (vflip) { - gz = FIXED_TO_FLOAT(thing->z+thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; + gz = FIXED_TO_FLOAT(thingzpos + thing->height) - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; gzt = gz + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale; } else { - gzt = FIXED_TO_FLOAT(thing->z) + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; + gzt = FIXED_TO_FLOAT(thingzpos) + FIXED_TO_FLOAT(spritecachedinfo[lumpoff].topoffset) * this_scale; gz = gzt - FIXED_TO_FLOAT(spritecachedinfo[lumpoff].height) * this_scale; } @@ -4266,12 +4274,12 @@ void HWR_ProjectSprite(mobj_t *thing) if (heightsec != -1 && phs != -1) // only clip things which are in special sectors { if (gr_viewz < FIXED_TO_FLOAT(sectors[phs].floorheight) ? - FIXED_TO_FLOAT(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) : + FIXED_TO_FLOAT(thingzpos) >= FIXED_TO_FLOAT(sectors[heightsec].floorheight) : gzt < FIXED_TO_FLOAT(sectors[heightsec].floorheight)) return; if (gr_viewz > FIXED_TO_FLOAT(sectors[phs].ceilingheight) ? gzt < FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) && gr_viewz >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight) : - FIXED_TO_FLOAT(thing->z) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight)) + FIXED_TO_FLOAT(thingzpos) >= FIXED_TO_FLOAT(sectors[heightsec].ceilingheight)) return; } From 6839a8cb69a91f75ece64ba16bd2a8f91c6df5db Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 15 May 2020 23:58:22 -0400 Subject: [PATCH 08/34] OGL model support for runtime sprite offsets --- src/hardware/hw_md2.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index 53503fa5c..0ae97c225 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -1121,6 +1121,10 @@ void HWR_DrawMD2(gr_vissprite_t *spr) // Look at HWR_ProjectSprite for more { + const fixed_t thingxpos = spr->mobj->x + spr->mobj->sprxoff; + const fixed_t thingypos = spr->mobj->y + spr->mobj->spryoff; + const fixed_t thingzpos = spr->mobj->z + spr->mobj->sprzoff; + GLPatch_t *gpatch; INT32 durs = spr->mobj->state->tics; INT32 tics = spr->mobj->tics; @@ -1266,13 +1270,13 @@ void HWR_DrawMD2(gr_vissprite_t *spr) #endif //Hurdler: it seems there is still a small problem with mobj angle - p.x = FIXED_TO_FLOAT(spr->mobj->x); - p.y = FIXED_TO_FLOAT(spr->mobj->y)+md2->offset; + p.x = FIXED_TO_FLOAT(thingxpos); + p.y = FIXED_TO_FLOAT(thingypos) + md2->offset; if (spr->mobj->eflags & MFE_VERTICALFLIP) - p.z = FIXED_TO_FLOAT(spr->mobj->z + spr->mobj->height); + p.z = FIXED_TO_FLOAT(thingzpos + spr->mobj->height); else - p.z = FIXED_TO_FLOAT(spr->mobj->z); + p.z = FIXED_TO_FLOAT(thingzpos); if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY) sprdef = &((skin_t *)spr->mobj->skin)->spritedef; @@ -1292,7 +1296,7 @@ void HWR_DrawMD2(gr_vissprite_t *spr) } else { - const fixed_t anglef = AngleFixed((R_PointToAngle(spr->mobj->x, spr->mobj->y))-ANGLE_180); + const fixed_t anglef = AngleFixed((R_PointToAngle(thingxpos, thingypos))-ANGLE_180); p.angley = FIXED_TO_FLOAT(anglef); } p.anglex = 0.0f; From 846ff298ebca868001e81685aa565ea580d543b5 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 18 May 2020 10:35:12 -0400 Subject: [PATCH 09/34] Fix k_color.c brief --- src/k_color.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/k_color.c b/src/k_color.c index a51cf418d..89112db29 100644 --- a/src/k_color.c +++ b/src/k_color.c @@ -7,8 +7,7 @@ // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file k_color.c -/// \brief Waypoint handling from the relevant mobjs -/// Setup and interfacing with waypoints for the main game +/// \brief Skincolor & colormapping code #include "k_color.h" From 6aa6521fb45960a92f1d109f6cbf166edbf91415 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 18 May 2020 14:52:26 -0400 Subject: [PATCH 10/34] Allow spectators through Block Players lines --- src/p_map.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/p_map.c b/src/p_map.c index a6306bb19..fec884f66 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -1941,7 +1941,7 @@ static boolean PIT_CheckLine(line_t *ld) { if (ld->flags & ML_IMPASSABLE) // block objects from moving through this linedef. return false; - if (tmthing->player && ld->flags & ML_BLOCKPLAYERS) + if (tmthing->player && !tmthing->player->spectator && ld->flags & ML_BLOCKPLAYERS) return false; // SRB2Kart: Only block players, not items } @@ -3307,7 +3307,7 @@ static boolean PTR_SlideTraverse(intercept_t *in) if (li->flags & ML_IMPASSABLE) goto isblocking; - if (slidemo->player && li->flags & ML_BLOCKPLAYERS) + if (slidemo->player && !slidemo->player->spectator && li->flags & ML_BLOCKPLAYERS) goto isblocking; } From c3a51931504984eee32e0b3e0338dd67a5e9685e Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 18 May 2020 15:19:48 -0400 Subject: [PATCH 11/34] Remove this code, it's in grand-pricks & functional now --- src/k_bot.c | 141 ---------------------------------------------------- 1 file changed, 141 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index 285207caa..bc35bc21d 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -197,147 +197,6 @@ void K_UpdateMatchRaceBots(void) // We should have enough bots now :) } -#if 0 -// This is mostly just pesudo code right now... -void K_InitGrandPrixBots(void) -{ - const UINT8 defaultbotskin = 9; // eggrobo - - // startingdifficulty: Easy = 3, Normal = 6, Hard = 9 - const UINT8 startingdifficulty = min(MAXBOTDIFFICULTY, (cv_kartspeed.value + 1) * 3); - UINT8 difficultylevels[MAXPLAYERS]; - - UINT8 playercount = 8; - UINT8 wantedbots = 0; - - UINT8 numplayers = 0; - UINT8 competitors[4]; - - boolean skinusable[MAXSKINS]; - UINT8 botskinlist[MAXPLAYERS]; - UINT8 botskinlistpos = 0; - - UINT8 i; - - memset(difficultylevels, MAXBOTDIFFICULTY, sizeof (difficultylevels)); - memset(competitors, MAXPLAYERS, sizeof (competitors)); - memset(botskinlist, defaultbotskin, sizeof (botskinlist)); - - // init usable bot skins list - for (i = 0; i < MAXSKINS; i++) - { - if (i < numskins) - { - skinusable[i] = true; - } - else - { - skinusable[i] = false; - } - } - - // init difficulty levels list - //if (!mastermodebots) { - difficultylevels[MAXPLAYERS] = { - max(1, startingdifficulty), - max(1, startingdifficulty-1), - max(1, startingdifficulty-2), - max(1, startingdifficulty-3), - max(1, startingdifficulty-3), - max(1, startingdifficulty-4), - max(1, startingdifficulty-4), - max(1, startingdifficulty-4), - max(1, startingdifficulty-5), - max(1, startingdifficulty-5), - max(1, startingdifficulty-6), - max(1, startingdifficulty-6), - max(1, startingdifficulty-7), - max(1, startingdifficulty-7), - max(1, startingdifficulty-8), - max(1, startingdifficulty-8), - }; - - for (i = 0; i < MAXPLAYERS; i++) - { - if (numplayers < MAXSPLITSCREENPLAYERS) - { - if (playeringame[i] && !players[i].spectator) - { - competitors[numplayers] = i; - numplayers++; - } - } - else - { - if (playeringame[i]) - { - players[i].spectator = true; // force spectate for all other players, if they happen to exist? - } - } - } - - if (numplayers > 2) - { - // Add 3 bots per player beyond 2P - playercount += (numplayers-2) * 3; - } - - wantedbots = playercount - numplayers; - - // Create rival list - - // TODO: Use player skin's set rivals - // Starting with P1's rival1, P2's rival1, P3's rival1, P4's rival1, - // then P1's rival2, P2's rival2, etc etc etc etc....... - // then skip over any duplicates. - - // Pad the remaining list with random skins if we need to - if (botskinlistpos < wantedbots) - { - for (i = botskinlistpos; i < wantedbots; i++) - { - UINT8 val = M_RandomKey(numskins); - UINT8 loops = 0; - - while (!skinusable[val]) - { - if (loops >= numskins) - { - // no more skins - break; - } - - val++; - - if (val >= numskins) - { - val = 0; - } - - loops++; - } - - if (loops >= numskins) - { - // leave the rest of the table as the default skin - break; - } - - botskinlist[i] = val; - skinusable[val] = false; - } - } - - for (i = 0; i < wantedbots; i++) - { - if (!K_AddBot(botskinlist[i], difficultylevels[i], &newplayernum)) - { - break; - } - } -} -#endif - boolean K_PlayerUsesBotMovement(player_t *player) { if (player->bot || player->exiting) From 1ec651ff00f4b842033f0367da8b16b90e68ccf9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Mon, 18 May 2020 15:30:55 -0400 Subject: [PATCH 12/34] Combine K_FindRandomItems & K_FindEggboxes --- src/k_bot.c | 53 +++++++++++++++-------------------------------------- 1 file changed, 15 insertions(+), 38 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index bc35bc21d..fe9e73df0 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -270,10 +270,13 @@ fixed_t K_BotRubberband(player_t *player) continue; } - /*if (players[i].bot) +#if 0 + // Only rubberband up to players. + if (players[i].bot) { continue; - }*/ + } +#endif if (firstplace == NULL || players[i].distancetofinish < firstplace->distancetofinish) { @@ -413,36 +416,11 @@ fixed_t eggboxx, eggboxy; UINT8 randomitems = 0; UINT8 eggboxes = 0; -static boolean K_FindRandomItems(mobj_t *thing) -{ - fixed_t dist; - - if (thing->type != MT_RANDOMITEM) - { - return true; - } - - if (!thing->health) - { - return true; - } - - dist = P_AproxDistance(thing->x - eggboxx, thing->y - eggboxy); - - if (dist > distancetocheck) - { - return true; - } - - randomitems++; - return true; -} - static boolean K_FindEggboxes(mobj_t *thing) { fixed_t dist; - if (thing->type != MT_EGGMANITEM) + if (thing->type != MT_RANDOMITEM && thing->type != MT_EGGMANITEM) { return true; } @@ -459,7 +437,14 @@ static boolean K_FindEggboxes(mobj_t *thing) return true; } - eggboxes++; + if (thing->type == MT_RANDOMITEM) + { + randomitems++; + } + else + { + eggboxes++; + } return true; } @@ -480,14 +465,6 @@ static UINT8 K_EggboxStealth(fixed_t x, fixed_t y) BMBOUNDFIX(xl, xh, yl, yh); - for (bx = xl; bx <= xh; bx++) - { - for (by = yl; by <= yh; by++) - { - P_BlockThingsIterator(bx, by, K_FindRandomItems); - } - } - for (bx = xl; bx <= xh; bx++) { for (by = yl; by <= yh; by++) @@ -496,7 +473,7 @@ static UINT8 K_EggboxStealth(fixed_t x, fixed_t y) } } - return randomitems * eggboxes; + return (randomitems * eggboxes); } static inline boolean K_FindBlockingWalls(line_t *line) From 8b0aa9e3333bffb98db4066d26144a43582aeb8a Mon Sep 17 00:00:00 2001 From: Latapostrophe Date: Wed, 20 May 2020 14:21:50 +0200 Subject: [PATCH 13/34] Change flash cooldown from 5 to 2 seconds --- src/k_kart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_kart.c b/src/k_kart.c index e8b126e43..673c66822 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -3347,7 +3347,7 @@ void K_SpawnMineExplosion(mobj_t *source, UINT8 color) P_StartQuake(55<mo, source)) { - bombflashtimer = TICRATE*5; + bombflashtimer = TICRATE*2; P_FlashPal(p, 1, 1); } break; // we can break right now because quakes are global to all split players somehow. From d4080e94f7fa862b77ab759e6f57e3a13ba78d18 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 21 May 2020 16:32:34 +0100 Subject: [PATCH 14/34] Better fake contrast. Fake contrast for the segs are calculated at map load. OpenGL only has the options "Standard" and "Smooth" now. Standard is default and replicates software. Smooth changes the contrast more smoothly depending on angle. --- src/hardware/hw_main.c | 61 +++++++++++++++++------------------------- src/p_setup.c | 14 +++++++++- src/r_defs.h | 6 +++++ src/r_segs.c | 38 +++++++++----------------- src/v_video.c | 2 +- 5 files changed, 57 insertions(+), 64 deletions(-) diff --git a/src/hardware/hw_main.c b/src/hardware/hw_main.c index 4a4b6d600..3d4f26df9 100644 --- a/src/hardware/hw_main.c +++ b/src/hardware/hw_main.c @@ -223,40 +223,27 @@ UINT8 HWR_FogBlockAlpha(INT32 light, extracolormap_t *colormap) // Let's see if return surfcolor.s.alpha; } -static FUINT HWR_CalcWallLight(FUINT lightnum, fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y) +// Lightnum = current light +// line = the seg to get the light offset from +static FUINT HWR_CalcWallLight(seg_t *line, FUINT lightnum) { INT16 finallight = lightnum; - if (cv_grfakecontrast.value != 0) + fixed_t extralight = 0; + + if (cv_grfakecontrast.value == 1) // Smooth setting + extralight += line->hwLightOffset; + else + extralight += line->lightOffset * 8; + + if (extralight != 0) { - const UINT8 contrast = 8; - fixed_t extralight = 0; + finallight += extralight; - if (cv_grfakecontrast.value == 2) // Smooth setting - { - extralight = (-(contrast<> FRACBITS; - } - else - { - if (v1y == v2y) - extralight = -contrast; - else if (v1x == v2x) - extralight = contrast; - } - - if (extralight != 0) - { - finallight += extralight; - - if (finallight < 0) - finallight = 0; - if (finallight > 255) - finallight = 255; - } + if (finallight < 0) + finallight = 0; + if (finallight > 255) + finallight = 255; } return (FUINT)finallight; @@ -618,7 +605,7 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa INT32 solid, i; lightlist_t * list = sector->lightlist; const UINT8 alpha = Surf->PolyColor.s.alpha; - FUINT lightnum = HWR_CalcWallLight(sector->lightlevel, v1x, v1y, v2x, v2y); + FUINT lightnum = HWR_CalcWallLight(gr_curline, sector->lightlevel); extracolormap_t *colormap = NULL; realtop = top = wallVerts[3].y; @@ -647,12 +634,12 @@ void HWR_SplitWall(sector_t *sector, FOutVector *wallVerts, INT32 texnum, FSurfa { if (pfloor && (pfloor->flags & FF_FOG)) { - lightnum = HWR_CalcWallLight(pfloor->master->frontsector->lightlevel, v1x, v1y, v2x, v2y); + lightnum = HWR_CalcWallLight(gr_curline, pfloor->master->frontsector->lightlevel); colormap = pfloor->master->frontsector->extra_colormap; } else { - lightnum = HWR_CalcWallLight(*list[i].lightlevel, v1x, v1y, v2x, v2y); + lightnum = HWR_CalcWallLight(gr_curline, *list[i].lightlevel); colormap = list[i].extra_colormap; } } @@ -933,7 +920,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom cliphigh = (float)(texturehpeg + (gr_curline->flength*FRACUNIT)); } - lightnum = HWR_CalcWallLight(gr_frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = HWR_CalcWallLight(gr_curline, gr_frontsector->lightlevel); colormap = gr_frontsector->extra_colormap; if (gr_frontsector) @@ -1759,7 +1746,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = HWR_CalcWallLight(gr_curline, rover->master->frontsector->lightlevel); colormap = rover->master->frontsector->extra_colormap; Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -1871,7 +1858,7 @@ void HWR_ProcessSeg(void) // Sort of like GLWall::Process in GZDoom blendmode = PF_Fog|PF_NoTexture; - lightnum = HWR_CalcWallLight(rover->master->frontsector->lightlevel, vs.x, vs.y, ve.x, ve.y); + lightnum = HWR_CalcWallLight(gr_curline, rover->master->frontsector->lightlevel); colormap = rover->master->frontsector->extra_colormap; Surf.PolyColor.s.alpha = HWR_FogBlockAlpha(rover->master->frontsector->lightlevel, rover->master->frontsector->extra_colormap); @@ -3596,10 +3583,10 @@ static int CompareVisSprites(const void *p1, const void *p2) gr_vissprite_t* spr2 = *(gr_vissprite_t*const*)p2; int idiff; float fdiff; - + // make transparent sprites last // "boolean to int" - + int transparency1 = (spr1->mobj->flags2 & MF2_SHADOW) || (spr1->mobj->frame & FF_TRANSMASK); int transparency2 = (spr2->mobj->flags2 & MF2_SHADOW) || (spr2->mobj->frame & FF_TRANSMASK); idiff = transparency1 - transparency2; diff --git a/src/p_setup.c b/src/p_setup.c index 2ea730126..f56b2f4ea 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -457,6 +457,7 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) mapseg_t *ml; seg_t *li; line_t *ldef; + fixed_t extralight = 0; numsegs = i / sizeof (mapseg_t); if (numsegs <= 0) @@ -492,6 +493,17 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) li->numlights = 0; li->rlights = NULL; + + extralight = -(8*FRACUNIT) + + FixedDiv(AngleFixed(R_PointToAngle2(0, 0, + abs(li->v1->x - li->v2->x), + abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * 16; + + // Between -1 and 1 for software, -8 and 8 for hardware + li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT; +#ifdef HWRENDER + li->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; +#endif } } @@ -1091,7 +1103,7 @@ static void P_LoadThings(void) || mt->type == 1705 || mt->type == 1713 || mt->type == 1800) { sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector; - + mt->mobj = NULL; // Z for objects diff --git a/src/r_defs.h b/src/r_defs.h index 02c82bf56..b186fecdf 100644 --- a/src/r_defs.h +++ b/src/r_defs.h @@ -565,6 +565,12 @@ typedef struct seg_s polyobj_t *polyseg; boolean dontrenderme; #endif + + // Fake contrast calculated on level load + SINT8 lightOffset; +#ifdef HWRENDER + INT16 hwLightOffset; +#endif } seg_t; // diff --git a/src/r_segs.c b/src/r_segs.c index 2304540fe..efb1f4887 100644 --- a/src/r_segs.c +++ b/src/r_segs.c @@ -412,10 +412,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (rlight->extra_colormap && rlight->extra_colormap->fog) ; - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + else + lightnum += curline->lightOffset; rlight->lightnum = lightnum; } @@ -435,10 +433,8 @@ void R_RenderMaskedSegRange(drawseg_t *ds, INT32 x1, INT32 x2) if (colfunc == R_DrawFogColumn_8 || (frontsector->extra_colormap && frontsector->extra_colormap->fog)) ; - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + else + lightnum += curline->lightOffset; if (lightnum < 0) walllights = scalelight[0]; @@ -932,10 +928,8 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) if (pfloor->flags & FF_FOG || rlight->flags & FF_FOG || (rlight->extra_colormap && rlight->extra_colormap->fog)) ; - else if (curline->v1->y == curline->v2->y) - rlight->lightnum--; - else if (curline->v1->x == curline->v2->x) - rlight->lightnum++; + else + rlight->lightnum += curline->lightOffset; p++; } @@ -955,11 +949,10 @@ void R_RenderThickSideRange(drawseg_t *ds, INT32 x1, INT32 x2, ffloor_t *pfloor) lightnum = R_FakeFlat(frontsector, &tempsec, &templight, &templight, false) ->lightlevel >> LIGHTSEGSHIFT; - if (pfloor->flags & FF_FOG || (frontsector->extra_colormap && frontsector->extra_colormap->fog)); - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + if (pfloor->flags & FF_FOG || (frontsector->extra_colormap && frontsector->extra_colormap->fog)) + ; + else + lightnum += curline->lightOffset; if (lightnum < 0) walllights = scalelight[0]; @@ -1492,10 +1485,8 @@ static void R_RenderSegLoop (void) if (dc_lightlist[i].extra_colormap) ; - else if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + else + lightnum += curline->lightOffset; if (lightnum < 0) xwalllights = scalelight[0]; @@ -2639,10 +2630,7 @@ void R_StoreWallRange(INT32 start, INT32 stop) // OPTIMIZE: get rid of LIGHTSEGSHIFT globally lightnum = (frontsector->lightlevel >> LIGHTSEGSHIFT); - if (curline->v1->y == curline->v2->y) - lightnum--; - else if (curline->v1->x == curline->v2->x) - lightnum++; + lightnum += curline->lightOffset; if (lightnum < 0) walllights = scalelight[0]; diff --git a/src/v_video.c b/src/v_video.c index 7f1bcb7ce..e5fed2a16 100644 --- a/src/v_video.c +++ b/src/v_video.c @@ -84,7 +84,7 @@ static void CV_Gammaxxx_ONChange(void); // - You can change them in software, // but they won't do anything. static CV_PossibleValue_t grgamma_cons_t[] = {{1, "MIN"}, {255, "MAX"}, {0, NULL}}; -static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Off"}, {1, "Standard"}, {2, "Smooth"}, {0, NULL}}; +static CV_PossibleValue_t grfakecontrast_cons_t[] = {{0, "Standard"}, {1, "Smooth"}, {0, NULL}}; consvar_t cv_grshaders = {"gr_shaders", "On", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_grfovchange = {"gr_fovchange", "Off", CV_SAVE, CV_OnOff, NULL, 0, NULL, NULL, 0, 0, NULL}; From 195920acdcffca94bb335bc06d3dea5cd238da43 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 21 May 2020 17:15:50 +0100 Subject: [PATCH 15/34] Update light offset on polyobjects when they rotate --- src/p_polyobj.c | 3 +++ src/p_setup.c | 31 +++++++++++++++++++++---------- src/p_setup.h | 1 + 3 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/p_polyobj.c b/src/p_polyobj.c index 03fb10d0f..12708a44b 100644 --- a/src/p_polyobj.c +++ b/src/p_polyobj.c @@ -1407,7 +1407,10 @@ static boolean Polyobj_rotate(polyobj_t *po, angle_t delta, UINT8 turnthings) { // update seg angles (used only by renderer) for (i = 0; i < po->segCount; ++i) + { po->segs[i]->angle += delta; + P_UpdateSegLightOffset(po->segs[i]); + } // update polyobject's angle po->angle += delta; diff --git a/src/p_setup.c b/src/p_setup.c index f56b2f4ea..259d8f5ff 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -446,6 +446,26 @@ static inline float P_SegLengthFloat(seg_t *seg) } #endif +/** Updates the light offset + * + * \param li Seg to update the light offsets of + */ +void P_UpdateSegLightOffset(seg_t *li) +{ + fixed_t extralight = 0; + + extralight = -(8*FRACUNIT) + + FixedDiv(AngleFixed(R_PointToAngle2(0, 0, + abs(li->v1->x - li->v2->x), + abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * 16; + + // Between -1 and 1 for software, -8 and 8 for hardware + li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT; +#ifdef HWRENDER + li->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; +#endif +} + /** Loads the SEGS resource from a level. * * \param lump Lump number of the SEGS resource. @@ -494,16 +514,7 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) li->numlights = 0; li->rlights = NULL; - extralight = -(8*FRACUNIT) + - FixedDiv(AngleFixed(R_PointToAngle2(0, 0, - abs(li->v1->x - li->v2->x), - abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * 16; - - // Between -1 and 1 for software, -8 and 8 for hardware - li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT; -#ifdef HWRENDER - li->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; -#endif + P_UpdateSegLightOffset(li); } } diff --git a/src/p_setup.h b/src/p_setup.h index 9abcfe5f6..c0b30ca6a 100644 --- a/src/p_setup.h +++ b/src/p_setup.h @@ -66,6 +66,7 @@ boolean P_DelWadFile(void); #endif boolean P_RunSOC(const char *socfilename); void P_WriteThings(lumpnum_t lump); +void P_UpdateSegLightOffset(seg_t *li); size_t P_PrecacheLevelFlats(void); void P_AllocMapHeader(INT16 i); From 8d34ca0533fc46248e169c4953a32353fc503b57 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 21 May 2020 17:55:33 +0100 Subject: [PATCH 16/34] Use a const for the contrast, and double it for extra impact. --- src/p_setup.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/p_setup.c b/src/p_setup.c index 259d8f5ff..ea0c04d5c 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -452,15 +452,16 @@ static inline float P_SegLengthFloat(seg_t *seg) */ void P_UpdateSegLightOffset(seg_t *li) { + const UINT8 contrast = 16; fixed_t extralight = 0; - extralight = -(8*FRACUNIT) + + extralight = -((fixed_t)contrast*FRACUNIT) + FixedDiv(AngleFixed(R_PointToAngle2(0, 0, abs(li->v1->x - li->v2->x), - abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * 16; + abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * ((fixed_t)contrast * 2); - // Between -1 and 1 for software, -8 and 8 for hardware - li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT; + // Between -2 and 2 for software, -16 and 16 for hardware + li->lightOffset = FixedFloor((extralight / contrast) + (FRACUNIT / 2)) / FRACUNIT; #ifdef HWRENDER li->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; #endif @@ -477,7 +478,6 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) mapseg_t *ml; seg_t *li; line_t *ldef; - fixed_t extralight = 0; numsegs = i / sizeof (mapseg_t); if (numsegs <= 0) From ad51b791d5d65eb3d35adbd24d1af4e4cfcaf0d2 Mon Sep 17 00:00:00 2001 From: Sryder Date: Thu, 21 May 2020 18:11:38 +0100 Subject: [PATCH 17/34] Fix software not contrasting properly to +-2 --- src/p_setup.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/p_setup.c b/src/p_setup.c index ea0c04d5c..cd1cabdc9 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -461,7 +461,7 @@ void P_UpdateSegLightOffset(seg_t *li) abs(li->v1->y - li->v2->y))), 90*FRACUNIT) * ((fixed_t)contrast * 2); // Between -2 and 2 for software, -16 and 16 for hardware - li->lightOffset = FixedFloor((extralight / contrast) + (FRACUNIT / 2)) / FRACUNIT; + li->lightOffset = FixedFloor((extralight / 8) + (FRACUNIT / 2)) / FRACUNIT; #ifdef HWRENDER li->hwLightOffset = FixedFloor(extralight + (FRACUNIT / 2)) / FRACUNIT; #endif From 97e261f443946fa63f95b6c7fcdc4eefca35f4f8 Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 22 May 2020 21:27:55 +0100 Subject: [PATCH 18/34] Fix some issues with the tab rankings and end screen that bots exposed. * Laps now have an initial zero instead of being directly indexed from 1, so start counting from there. * Clean up the circumstances under which LAGLESS! is shown next to a name - specifically removing it from both non-netgames in general, and bots in netgames. * Fix `(powertype == -1)` being broken on the intermission drawer, which was especially obvious with bots outside of netgames. --- src/hu_stuff.c | 2 +- src/k_kart.c | 2 +- src/y_inter.c | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/hu_stuff.c b/src/hu_stuff.c index a4acabf79..7338a232b 100644 --- a/src/hu_stuff.c +++ b/src/hu_stuff.c @@ -3095,7 +3095,7 @@ static void HU_DrawRankings(void) if (G_RaceGametype()) { if (circuitmap) - tab[scorelines].count = players[i].laps+1; + tab[scorelines].count = players[i].laps; else tab[scorelines].count = players[i].realtime; } diff --git a/src/k_kart.c b/src/k_kart.c index de653e9b0..a8ddef8f0 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -9434,7 +9434,7 @@ void HU_DrawTabRankings(INT32 x, INT32 y, playersort_t *tab, INT32 scorelines, I y2 = y; - if (playerconsole[tab[i].num] == 0 && server_lagless) + if (netgame && playerconsole[tab[i].num] == 0 && server_lagless && !players[tab[i].num].bot) { y2 = ( y - 4 ); diff --git a/src/y_inter.c b/src/y_inter.c index d3ef26fdd..1051a7e55 100644 --- a/src/y_inter.c +++ b/src/y_inter.c @@ -440,7 +440,7 @@ void Y_IntermissionDrawer(void) int y2; if (data.match.rankingsmode) - timeheader = "PWR.LV"; + timeheader = (powertype != -1 ? "PWR.LV" : "RANK"); else timeheader = ((intertype == int_race || (intertype == int_match && battlecapsules)) ? "TIME" : "SCORE"); @@ -497,7 +497,7 @@ void Y_IntermissionDrawer(void) y2 = y; - if (playerconsole[data.match.num[i]] == 0 && server_lagless) + if (netgame && playerconsole[data.match.num[i]] == 0 && server_lagless && !players[data.match.num[i]].bot) { static int alagles_timer = 0; patch_t *alagles; @@ -533,7 +533,7 @@ void Y_IntermissionDrawer(void) if (data.match.rankingsmode) { - if (!clientpowerlevels[data.match.num[i]][powertype]) // No power level (splitscreen guests) + if (powertype != -1 && !clientpowerlevels[data.match.num[i]][powertype]) // No power level (splitscreen guests) STRBUFCPY(strtime, "----"); else { From 84f277c3239d7e6d23aeab62c31c9213b10148ac Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 22 May 2020 21:34:05 +0100 Subject: [PATCH 19/34] Adjust the finish line detection to exclude a handful of circumstances I've tripped before. --- src/p_spec.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/p_spec.c b/src/p_spec.c index 0c75051ad..82dad34a6 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -2209,7 +2209,8 @@ static void K_HandleLapDecrement(player_t *player) void P_CrossSpecialLine(line_t *line, INT32 side, mobj_t *thing) { // only used for the players currently - if (thing && thing->player) + if (!(thing && thing->player && !thing->player->spectator && !(thing->player->pflags & PF_TIMEOVER))) + return; { player_t *player = thing->player; switch (line->special) From 56226fae458d1ea38be79e5d1fd8a23e609643cd Mon Sep 17 00:00:00 2001 From: toaster Date: Fri, 22 May 2020 21:51:05 +0100 Subject: [PATCH 20/34] Only iterate blockmap once for Random Items and Eggboxes. --- src/k_bot.c | 45 ++++++++------------------------------------- 1 file changed, 8 insertions(+), 37 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index 285207caa..fd75adca5 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -554,11 +554,12 @@ fixed_t eggboxx, eggboxy; UINT8 randomitems = 0; UINT8 eggboxes = 0; -static boolean K_FindRandomItems(mobj_t *thing) +static boolean K_FindRandomItemsAndEggboxes(mobj_t *thing) { fixed_t dist; + boolean egg = (thing->type == MT_EGGMANITEM); - if (thing->type != MT_RANDOMITEM) + if (!egg && thing->type != MT_RANDOMITEM) { return true; } @@ -575,32 +576,10 @@ static boolean K_FindRandomItems(mobj_t *thing) return true; } - randomitems++; - return true; -} - -static boolean K_FindEggboxes(mobj_t *thing) -{ - fixed_t dist; - - if (thing->type != MT_EGGMANITEM) - { - return true; - } - - if (!thing->health) - { - return true; - } - - dist = P_AproxDistance(thing->x - eggboxx, thing->y - eggboxy); - - if (dist > distancetocheck) - { - return true; - } - - eggboxes++; + if (egg) + eggboxes++; + else + randomitems++; return true; } @@ -625,15 +604,7 @@ static UINT8 K_EggboxStealth(fixed_t x, fixed_t y) { for (by = yl; by <= yh; by++) { - P_BlockThingsIterator(bx, by, K_FindRandomItems); - } - } - - for (bx = xl; bx <= xh; bx++) - { - for (by = yl; by <= yh; by++) - { - P_BlockThingsIterator(bx, by, K_FindEggboxes); + P_BlockThingsIterator(bx, by, K_FindRandomItemsAndEggboxes); } } From 19f352e4a450ad28a8466026885669af9bf9a8bb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 22 May 2020 20:19:58 -0400 Subject: [PATCH 21/34] Commentate K_BotReducePrediction better, use angle rather than distance for path split picking --- src/k_bot.c | 79 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index fe9e73df0..fe7b65e2b 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -628,19 +628,29 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) { const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN); // Reduce prediction based on how fast you can turn const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to - const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict + const fixed_t distreduce = K_BotReducePrediction(player); const fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT); - const INT32 distance = (FixedMul(player->speed, distreduce) / FRACUNIT) * futuresight; - INT32 distanceleft = distance; + + const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict + const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy) + (K_GetKartSpeed(player, false) / 2); + const INT32 distance = (FixedMul(speed, distreduce) / FRACUNIT) * futuresight; + botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_LEVEL, NULL); waypoint_t *wp = player->nextwaypoint; + + INT32 distanceleft = distance; fixed_t smallestradius = INT32_MAX; + angle_t angletonext = ANGLE_MAX; + size_t nwp; size_t i; + // Reduce distance left by your distance to the starting waypoint. + // This prevents looking too far ahead if the closest waypoint is really far away. distanceleft -= P_AproxDistance(player->mo->x - wp->mobj->x, player->mo->y - wp->mobj->y) / FRACUNIT; + // We don't want to look ahead at all, just go to the first waypoint. if (distanceleft <= 0) { predict->x = wp->mobj->x; @@ -649,66 +659,99 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) return predict; } + angletonext = R_PointToAngle2( + player->mo->x, player->mo->y, + wp->mobj->x, wp->mobj->y + ); + + // Go through waypoints until we've traveled the distance we wanted to predict ahead! while (distanceleft > 0) { + INT32 disttonext = INT32_MAX; + if (wp->mobj->radius < smallestradius) { smallestradius = wp->mobj->radius; } - nwp = 0; - if (wp->numnextwaypoints == 0) { + // Well, this is where I get off. distanceleft = 0; break; } + // Calculate nextwaypoints index to use + // nextwaypoints[0] by default + nwp = 0; + + // There are multiple nextwaypoints, + // so we need to find the most convenient one to us. + // Let's compare the angle to the player's! if (wp->numnextwaypoints > 1) { - fixed_t closest = INT32_MAX; - fixed_t dist = INT32_MAX; + angle_t delta = ANGLE_MAX; + angle_t a = ANGLE_MAX; for (i = 0; i < wp->numnextwaypoints; i++) { + if (K_GetWaypointIsShortcut(wp->nextwaypoints[i]) && !K_BotCanTakeCut(player)) { continue; } - dist = P_AproxDistance( - player->mo->x - wp->nextwaypoints[i]->mobj->x, - player->mo->y - wp->nextwaypoints[i]->mobj->y + // Unlike the other parts of this function, we're comparing the player's physical position, NOT the position of the waypoint!! + // This should roughly correspond with how players will think about path splits. + a = R_PointToAngle2( + player->mo->x, player->mo->y, + wp->nextwaypoints[i]->mobj->x, wp->nextwaypoints[i]->mobj->y ); + if (a > ANGLE_180) + { + a = InvAngle(a); + } - if (dist < closest) + a = player->mo->angle - a; + + if (a < delta) { nwp = i; - closest = dist; + delta = a; } } } - if ((INT32)(wp->nextwaypointdistances[nwp]) > distanceleft) + // Save angle for the next loop's oldangle + angletonext = R_PointToAngle2( + wp->mobj->x, wp->mobj->y, + wp->nextwaypoints[nwp]->mobj->x, wp->nextwaypoints[nwp]->mobj->y + ); + + disttonext = (wp->nextwaypointdistances[nwp] * FRACUNIT) / FRACUNIT; + + if (disttonext > distanceleft) { break; } - distanceleft -= wp->nextwaypointdistances[nwp]; + distanceleft -= disttonext; wp = wp->nextwaypoints[nwp]; } + // Set our predicted point's coordinates, + // and use the smallest radius of all of the waypoints in the chain! predict->x = wp->mobj->x; predict->y = wp->mobj->y; predict->radius = FixedMul(smallestradius, radreduce); + // Set the prediction coordinates between the 2 waypoints if there's still distance left. if (distanceleft > 0) { - angle_t a = R_PointToAngle2(wp->mobj->x, wp->mobj->y, wp->nextwaypoints[nwp]->mobj->x, wp->nextwaypoints[nwp]->mobj->y); - - predict->x += P_ReturnThrustX(NULL, a, distanceleft * FRACUNIT); - predict->y += P_ReturnThrustY(NULL, a, distanceleft * FRACUNIT); + // Scaled with the leftover anglemul! + predict->x += P_ReturnThrustX(NULL, angletonext, distanceleft * FRACUNIT); + predict->y += P_ReturnThrustY(NULL, angletonext, distanceleft * FRACUNIT); } return predict; From f442b934cccf0f6690d5ace88c8830a6ef25490d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 22 May 2020 20:20:17 -0400 Subject: [PATCH 22/34] Adjust wall steer radius with speed --- src/k_bot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_bot.c b/src/k_bot.c index fe7b65e2b..6633e5e9e 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -589,7 +589,7 @@ static fixed_t K_BotReducePrediction(player_t *player) INT32 xl, xh, yl, yh, bx, by; botmo = player->mo; - distancetocheck = player->mo->radius * 16; + distancetocheck = (player->mo->radius * 8) + (player->speed * 4); closestlinedist = INT32_MAX; tmx = player->mo->x; From 38ec153e901f71a081635f63c9ae1d38c21af47b Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 22 May 2020 20:49:33 -0400 Subject: [PATCH 23/34] A bit redundant --- src/k_bot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_bot.c b/src/k_bot.c index 6633e5e9e..b22fd5946 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -728,7 +728,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) wp->nextwaypoints[nwp]->mobj->x, wp->nextwaypoints[nwp]->mobj->y ); - disttonext = (wp->nextwaypointdistances[nwp] * FRACUNIT) / FRACUNIT; + disttonext = (INT32)wp->nextwaypointdistances[nwp]; if (disttonext > distanceleft) { From ca7154f521423b57b9577cbb4feed6d71af61531 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Fri, 22 May 2020 21:19:50 -0400 Subject: [PATCH 24/34] Make rubberband air speed cap even harsher --- src/p_user.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/p_user.c b/src/p_user.c index 6062d0d63..f91e8dc25 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4170,7 +4170,12 @@ static void P_3dMovement(player_t *player) if (K_PlayerUsesBotMovement(player)) { - div = FixedMul(div, K_BotRubberband(player)); + fixed_t rubberband = K_BotRubberband(player); + + if (rubberband > FRACUNIT) + { + div = FixedMul(div, 4*rubberband); + } } newspeed = speed - FixedDiv((speed - airspeedcap), div); From f5b570da399d51ae251f86e515caf11147ea2899 Mon Sep 17 00:00:00 2001 From: Sryder Date: Sat, 23 May 2020 16:08:51 +0100 Subject: [PATCH 25/34] Set this variable after making sure the target and player exist. --- src/p_mobj.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/p_mobj.c b/src/p_mobj.c index a224d5b58..6aaf6b414 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -8728,7 +8728,7 @@ void P_MobjThinker(mobj_t *mobj) fixed_t destx, desty; statenum_t curstate; statenum_t underlayst = S_NULL; - INT32 flamemax = mobj->target->player->kartstuff[k_flamelength] * flameseg; + INT32 flamemax = 0; if (!mobj->target || !mobj->target->health || !mobj->target->player || mobj->target->player->kartstuff[k_curshield] != KSHIELD_FLAME) @@ -8736,6 +8736,9 @@ void P_MobjThinker(mobj_t *mobj) P_RemoveMobj(mobj); return; } + + flamemax = mobj->target->player->kartstuff[k_flamelength] * flameseg; + P_SetScale(mobj, (mobj->destscale = (5*mobj->target->scale)>>2)); curstate = ((mobj->tics == 1) ? (mobj->state->nextstate) : ((statenum_t)(mobj->state-states))); @@ -8815,7 +8818,7 @@ void P_MobjThinker(mobj_t *mobj) if (curstate >= S_FLAMESHIELD1 && curstate < S_FLAMESHIELDDASH1 && ((curstate-S_FLAMESHIELD1) & 1)) viewingangle += ANGLE_180; - + destx = mobj->target->x + P_ReturnThrustX(mobj->target, viewingangle, mobj->scale>>4); desty = mobj->target->y + P_ReturnThrustY(mobj->target, viewingangle, mobj->scale>>4); } From b1ec2d8f74b065199afa7e21758e73b3282b0732 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 23 May 2020 21:34:30 -0400 Subject: [PATCH 26/34] Scale with mapobjectscale --- src/k_kart.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index c046b2c49..ebd9655b8 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -6787,6 +6787,7 @@ void K_StripOther(player_t *player) static INT32 K_FlameShieldMax(player_t *player) { UINT32 disttofinish = 0; + UINT32 distv = DISTVAR; UINT8 numplayers = 0; UINT8 i; @@ -6808,8 +6809,8 @@ static INT32 K_FlameShieldMax(player_t *player) } disttofinish = player->distancetofinish - disttofinish; - - return min(16, 1 + (disttofinish / DISTVAR)); + distv = FixedDiv(distv * FRACUNIT, mapobjectscale) / FRACUNIT; + return min(16, 1 + (disttofinish / distv)); } // From 12be3ea882a2dc092043ebe0b75cd98d88a1e7e9 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sat, 23 May 2020 21:50:52 -0400 Subject: [PATCH 27/34] Increase handling with flame shield dash --- src/k_kart.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/src/k_kart.c b/src/k_kart.c index ebd9655b8..697881bc9 100644 --- a/src/k_kart.c +++ b/src/k_kart.c @@ -2192,6 +2192,12 @@ void K_MomentumToFacing(player_t *player) player->mo->momy = FixedMul(player->mo->momy - player->cmomy, player->mo->friction) + player->cmomy; } +static fixed_t K_FlameShieldDashVar(INT32 val) +{ + // 1 second = 75% + 50% top speed + return (3*FRACUNIT/4) + (((val * FRACUNIT) / TICRATE) / 2); +} + // sets k_boostpower, k_speedboost, and k_accelboost to whatever we need it to be static void K_GetKartBoostPower(player_t *player) { @@ -2229,10 +2235,7 @@ static void K_GetKartBoostPower(player_t *player) ADDBOOST((3*FRACUNIT)/8, 3*FRACUNIT); // + 37.5% top speed, + 300% acceleration if (player->kartstuff[k_flamedash]) // Flame Shield dash - { - fixed_t dashval = ((player->kartstuff[k_flamedash]<kartstuff[k_flamedash]), 3*FRACUNIT); // + infinite top speed, + 300% acceleration if (player->kartstuff[k_startboost]) // Startup Boost ADDBOOST(FRACUNIT/4, 6*FRACUNIT); // + 25% top speed, + 600% acceleration @@ -6416,12 +6419,20 @@ INT16 K_GetKartTurnValue(player_t *player, INT16 turnvalue) turnvalue = 5*turnvalue/4; } + if (player->kartstuff[k_flamedash] > 0) + { + fixed_t multiplier = K_FlameShieldDashVar(player->kartstuff[k_flamedash]); + multiplier = FRACUNIT + (FixedDiv(multiplier, FRACUNIT/2) / 4); + turnvalue = FixedMul(turnvalue * FRACUNIT, multiplier) / FRACUNIT; + } + if (player->mo->eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) { turnvalue = 3*turnvalue/2; } - turnvalue = FixedMul(turnvalue * FRACUNIT, weightadjust) / FRACUNIT; // Weight has a small effect on turning + // Weight has a small effect on turning + turnvalue = FixedMul(turnvalue * FRACUNIT, weightadjust) / FRACUNIT; return turnvalue; } From edfc14c506fbd8064c01faf72ae75b02fa787c06 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 11:12:38 -0400 Subject: [PATCH 28/34] Better steering - If they're already turning in one direction, they are more likely to steer in that direction for objects - Bots have to want to turn in 1 direction for a few frames in a row before it'll let them Prevents twitching & makes them less indecisive in general --- src/d_clisrv.c | 4 +- src/d_clisrv.h | 2 +- src/d_player.h | 2 +- src/k_bot.c | 119 ++++++++++++++++++++++++++++++++++--------------- src/k_bot.h | 5 +++ src/p_saveg.c | 4 +- 6 files changed, 95 insertions(+), 41 deletions(-) diff --git a/src/d_clisrv.c b/src/d_clisrv.c index f73f436ae..37e39aadf 100644 --- a/src/d_clisrv.c +++ b/src/d_clisrv.c @@ -650,7 +650,7 @@ static inline void resynch_write_player(resynch_pak *rsp, const size_t i) rsp->bot_difficulty = players[i].botvars.difficulty; rsp->bot_itemdelay = players[i].botvars.itemdelay; rsp->bot_itemconfirm = players[i].botvars.itemconfirm; - rsp->bot_lastturn = players[i].botvars.lastturn; + rsp->bot_turnconfirm = players[i].botvars.turnconfirm; rsp->hasmo = false; //Transfer important mo information if the player has a body. @@ -779,7 +779,7 @@ static void resynch_read_player(resynch_pak *rsp) players[i].botvars.difficulty = rsp->bot_difficulty; players[i].botvars.itemdelay = rsp->bot_itemdelay; players[i].botvars.itemconfirm = rsp->bot_itemconfirm; - players[i].botvars.lastturn = rsp->bot_lastturn; + players[i].botvars.turnconfirm = rsp->bot_turnconfirm; //We get a packet for each player in game. if (!playeringame[i]) diff --git a/src/d_clisrv.h b/src/d_clisrv.h index abf43e5f9..1ef85b4f9 100644 --- a/src/d_clisrv.h +++ b/src/d_clisrv.h @@ -289,7 +289,7 @@ typedef struct UINT8 bot_difficulty; tic_t bot_itemdelay; tic_t bot_itemconfirm; - INT16 bot_lastturn; + SINT8 bot_turnconfirm; //player->mo stuff UINT8 hasmo; // Boolean diff --git a/src/d_player.h b/src/d_player.h index d67c4137b..6ed9fd719 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -428,7 +428,7 @@ typedef struct botvars_s tic_t itemdelay; tic_t itemconfirm; - INT16 lastturn; + SINT8 turnconfirm; } botvars_t; // ======================================================================== diff --git a/src/k_bot.c b/src/k_bot.c index b22fd5946..edd46b7d0 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -410,6 +410,7 @@ fixed_t distancetocheck = 0; fixed_t closestlinedist = INT32_MAX; +INT16 curturn = 0; INT16 badsteerglobal = 0; fixed_t eggboxx, eggboxy; @@ -761,30 +762,60 @@ static void K_SteerFromObject(mobj_t *bot, mobj_t *thing, fixed_t fulldist, fixe { angle_t destangle = R_PointToAngle2(bot->x, bot->y, thing->x, thing->y); angle_t angle; + SINT8 flip = 1; amount = (amount * FixedDiv(distancetocheck - fulldist, distancetocheck)) / FRACUNIT; + if (amount == 0) + { + // Shouldn't happen + return; + } + if (towards) { - if (xdist < (bot->radius + thing->radius)) + if (xdist < FixedHypot(bot->radius, thing->radius)) { // Don't need to turn any harder! + + if (abs(badsteerglobal) <= amount) + { + badsteerglobal = 0; + } + else + { + if (badsteerglobal > 0) + { + badsteerglobal -= amount; + } + else if (badsteerglobal < 0) + { + badsteerglobal += amount; + } + } + return; } - amount = -amount; + // Still turning towards it, flip. + flip = -flip; } angle = (bot->angle - destangle); - if (angle < ANGLE_180) { - badsteerglobal -= amount; + flip = -flip; } - else + + // If going in the opposite direction of where you wanted to turn, + // then reduce the amount that you can turn in that direction. + if ((flip == 1 && curturn < 0) + || (flip == -1 && curturn > 0)) { - badsteerglobal += amount; + amount /= 4; } + + badsteerglobal += amount * flip; } static boolean K_BotSteerObjects(mobj_t *thing) @@ -876,7 +907,7 @@ static boolean K_BotSteerObjects(mobj_t *thing) K_SteerFromObject(botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); break; case MT_RANDOMITEM: - if (anglediff > 90) + if (anglediff >= 60) { break; } @@ -887,7 +918,7 @@ static boolean K_BotSteerObjects(mobj_t *thing) } break; case MT_EGGMANITEM: - if (anglediff > 90) + if (anglediff >= 60) { break; } @@ -908,7 +939,7 @@ static boolean K_BotSteerObjects(mobj_t *thing) } break; case MT_FLOATINGITEM: - if (anglediff > 90) + if (anglediff >= 60) { break; } @@ -920,7 +951,7 @@ static boolean K_BotSteerObjects(mobj_t *thing) break; case MT_RING: case MT_FLINGRING: - if (anglediff > 90) + if (anglediff >= 60) { break; } @@ -932,8 +963,8 @@ static boolean K_BotSteerObjects(mobj_t *thing) { K_SteerFromObject(botmo, thing, fulldist, xdist, true, (RINGTOTAL(botmo->player) < 3 - ? (2 * (KART_FULLTURN + attack)) - : ((KART_FULLTURN + attack) / 2)) + ? (4 * (KART_FULLTURN + attack)) + : (KART_FULLTURN + attack)) ); } break; @@ -985,7 +1016,7 @@ static boolean K_BotSteerObjects(mobj_t *thing) fixed_t theirweight = K_GetMobjWeight(thing, botmo); fixed_t weightdiff = 0; - if (anglediff > 90) + if (anglediff >= 90) { weightdiff = theirweight - ourweight; } @@ -1006,6 +1037,11 @@ static boolean K_BotSteerObjects(mobj_t *thing) } break; case MT_BOTHINT: + if (anglediff >= 60) + { + break; + } + if (thing->extravalue1 == 0) { K_SteerFromObject(botmo, thing, fulldist, xdist, false, thing->extravalue2 * (KART_FULLTURN + dodge)); @@ -1025,14 +1061,15 @@ static boolean K_BotSteerObjects(mobj_t *thing) return true; } -static INT16 K_BotFindObjects(player_t *player) +static INT16 K_BotFindObjects(player_t *player, INT16 turn) { INT32 xl, xh, yl, yh, bx, by; badsteerglobal = 0; botmo = player->mo; - distancetocheck = (player->mo->radius * 32) + (player->speed * 4); + curturn = turn; + distancetocheck = 2048*mapobjectscale; xl = (unsigned)(botmo->x - distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; xh = (unsigned)(botmo->x + distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; @@ -1409,11 +1446,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) cmd->forwardmove /= 2; cmd->buttons |= BT_BRAKE; } - else if (dirdist <= realrad) - { - // Steer towards/away from objects! - turnamt += K_BotFindObjects(player); - } if (dirdist <= rad) { @@ -1446,6 +1478,12 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) turnamt /= 4; } } + + if (anglediff < 60) + { + // Steer towards/away from objects! + turnamt += K_BotFindObjects(player, turnamt); + } } } @@ -2169,8 +2207,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) if (turnamt != 0) { - const INT16 minturn = KART_FULLTURN/2; - if (turnamt > KART_FULLTURN) { turnamt = KART_FULLTURN; @@ -2180,26 +2216,39 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) turnamt = -KART_FULLTURN; } - if ((turnamt > minturn && player->botvars.lastturn >= 0) - || (turnamt < -minturn && player->botvars.lastturn <= 0)) + if (turnamt > 0) { - if (turnamt > 0) + if (player->botvars.turnconfirm < 0) { - player->botvars.lastturn = 1; - } - else if (turnamt < 0) - { - player->botvars.lastturn = -1; + // Reset turn confirm + player->botvars.turnconfirm = 0; } + if (player->botvars.turnconfirm < BOTTURNCONFIRM) + { + player->botvars.turnconfirm++; + } + } + else if (turnamt < 0) + { + if (player->botvars.turnconfirm > 0) + { + // Reset turn confirm + player->botvars.turnconfirm = 0; + } + + if (player->botvars.turnconfirm > -BOTTURNCONFIRM) + { + player->botvars.turnconfirm--; + } + } + + if (abs(player->botvars.turnconfirm) >= BOTTURNCONFIRM) + { + // You're probably commiting to your turn, here you go. cmd->driftturn = turnamt; cmd->angleturn += K_GetKartTurnValue(player, turnamt); } - else - { - // Can reset turn dir - player->botvars.lastturn = 0; - } } if (predict != NULL) diff --git a/src/k_bot.h b/src/k_bot.h index ef7409f97..0525480b4 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -13,8 +13,13 @@ #include "k_waypoint.h" #include "d_player.h" +// Maximum value of botvars.difficulty #define MAXBOTDIFFICULTY 9 +// How many tics in a row do you need to turn in this direction before we'll let you turn. +// Made it as small as possible without making it look like the bots are twitching constantly. +#define BOTTURNCONFIRM 7 + // Path that bot will attempt to take typedef struct botprediction_s { fixed_t x, y; diff --git a/src/p_saveg.c b/src/p_saveg.c index 007ce919c..5aa988075 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -272,7 +272,7 @@ static void P_NetArchivePlayers(void) WRITEUINT8(save_p, players[i].botvars.difficulty); WRITEUINT32(save_p, players[i].botvars.itemdelay); WRITEUINT32(save_p, players[i].botvars.itemconfirm); - WRITEINT16(save_p, players[i].botvars.lastturn); + WRITESINT8(save_p, players[i].botvars.turnconfirm); } } @@ -448,7 +448,7 @@ static void P_NetUnArchivePlayers(void) players[i].botvars.difficulty = READUINT8(save_p); players[i].botvars.itemdelay = READUINT32(save_p); players[i].botvars.itemconfirm = READUINT32(save_p); - players[i].botvars.lastturn = READINT16(save_p); + players[i].botvars.turnconfirm = READSINT8(save_p); } } From 56867fb203a569e9a215db58275c039c29f3278d Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 11:13:20 -0400 Subject: [PATCH 29/34] Going above top speed makes radius smaller --- src/k_bot.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index edd46b7d0..da4f432a5 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -630,11 +630,13 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN); // Reduce prediction based on how fast you can turn const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to + const fixed_t topspeed = K_GetKartSpeed(player, false); + const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy) + (topspeed / 4); + const fixed_t distreduce = K_BotReducePrediction(player); - const fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT); + fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT); const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict - const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy) + (K_GetKartSpeed(player, false) / 2); const INT32 distance = (FixedMul(speed, distreduce) / FRACUNIT) * futuresight; botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_LEVEL, NULL); @@ -651,6 +653,12 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) // This prevents looking too far ahead if the closest waypoint is really far away. distanceleft -= P_AproxDistance(player->mo->x - wp->mobj->x, player->mo->y - wp->mobj->y) / FRACUNIT; + if (speed > topspeed) + { + // Play more in the center when going fast. + radreduce = FixedDiv(radreduce, speed / topspeed); + } + // We don't want to look ahead at all, just go to the first waypoint. if (distanceleft <= 0) { From 02605a5aceb4282b435c52cb002bebb480169925 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 15:08:10 -0400 Subject: [PATCH 30/34] Split bot code into multiple files & clean up --- src/CMakeLists.txt | 2 + src/Makefile | 2 + src/k_bot.c | 1655 ++------------------------------------------ src/k_bot.h | 196 +++++- src/k_botitem.c | 1095 +++++++++++++++++++++++++++++ src/k_botsearch.c | 749 ++++++++++++++++++++ 6 files changed, 2109 insertions(+), 1590 deletions(-) create mode 100644 src/k_botitem.c create mode 100644 src/k_botsearch.c diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 59cb146c0..2cba3c836 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -166,6 +166,8 @@ set(SRB2_CORE_GAME_SOURCES k_waypoint.c k_color.c k_bot.c + k_botitem.c + k_botsearch.c p_local.h p_maputl.h diff --git a/src/Makefile b/src/Makefile index 21a08eaab..84d47da5c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -563,6 +563,8 @@ OBJS:=$(i_main_o) \ $(OBJDIR)/lzf.o \ $(OBJDIR)/vid_copy.o \ $(OBJDIR)/k_bot.o \ + $(OBJDIR)/k_botitem.o \ + $(OBJDIR)/k_botsearch.o \ $(i_cdmus_o) \ $(i_net_o) \ $(i_system_o) \ diff --git a/src/k_bot.c b/src/k_bot.c index da4f432a5..927fc357a 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -1,14 +1,13 @@ -// SONIC ROBO BLAST 2 +// SONIC ROBO BLAST 2 KART //----------------------------------------------------------------------------- -// Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2011-2018 by Sonic Team Junior. +// Copyright (C) 2018-2020 by Kart Krew // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file k_bot.c -/// \brief Basic bot handling +/// \brief Bot logic & ticcmd generation code #include "doomdef.h" #include "d_player.h" @@ -27,6 +26,12 @@ #include "m_random.h" #include "r_things.h" // numskins + +/*-------------------------------------------------- + boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) + + See header file for description. +--------------------------------------------------*/ boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) { UINT8 buf[3]; @@ -93,6 +98,11 @@ boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *p) return true; } +/*-------------------------------------------------- + void K_UpdateMatchRaceBots(void) + + See header file for description. +--------------------------------------------------*/ void K_UpdateMatchRaceBots(void) { const UINT8 difficulty = cv_kartbot.value; @@ -197,6 +207,11 @@ void K_UpdateMatchRaceBots(void) // We should have enough bots now :) } +/*-------------------------------------------------- + boolean K_PlayerUsesBotMovement(player_t *player) + + See header file for description. +--------------------------------------------------*/ boolean K_PlayerUsesBotMovement(player_t *player) { if (player->bot || player->exiting) @@ -205,6 +220,11 @@ boolean K_PlayerUsesBotMovement(player_t *player) return false; } +/*-------------------------------------------------- + boolean K_BotCanTakeCut(player_t *player) + + See header file for description. +--------------------------------------------------*/ boolean K_BotCanTakeCut(player_t *player) { if (!K_ApplyOffroad(player) @@ -217,6 +237,18 @@ boolean K_BotCanTakeCut(player_t *player) return false; } +/*-------------------------------------------------- + static UINT32 K_BotRubberbandDistance(player_t *player) + + Calculates the distance away from 1st place that the + bot should rubberband to. + + Input Arguments:- + player - Player to compare. + + Return:- + Distance to add, as an integer. +--------------------------------------------------*/ static UINT32 K_BotRubberbandDistance(player_t *player) { const UINT32 spacing = 2048; @@ -252,6 +284,11 @@ static UINT32 K_BotRubberbandDistance(player_t *player) return (pos * spacing); } +/*-------------------------------------------------- + fixed_t K_BotRubberband(player_t *player) + + See header file for description. +--------------------------------------------------*/ fixed_t K_BotRubberband(player_t *player) { fixed_t rubberband = FRACUNIT; @@ -313,7 +350,12 @@ fixed_t K_BotRubberband(player_t *player) return rubberband; } -static fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy) +/*-------------------------------------------------- + fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy) + + See header file for description. +--------------------------------------------------*/ +fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy) { fixed_t v1toc[2] = {cx - v1x, cy - v1y}; fixed_t v1tov2[2] = {v2x - v1x, v2y - v1y}; @@ -337,294 +379,17 @@ static fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, return P_AproxDistance(cx - px, cy - py); } -static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec) -{ - switch (GETSECSPECIAL(sec->special, 1)) - { - case 1: // Damage - case 5: // Spikes - case 6: case 7: // Death Pit - case 8: // Instant Kill - return true; - //case 2: case 3: // Offroad (let's let them lawnmower) - case 4: // Offroad (Strong) - if (!K_BotCanTakeCut(player)) - return true; - default: - break; - } +/*-------------------------------------------------- + static botprediction_t *K_CreateBotPrediction(player_t *player) - return false; -} + Calculates a point further along the track to attempt to drive towards. -static boolean K_BotHatesThisSector(player_t *player, sector_t *sec) -{ - const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP); - INT32 flag; - ffloor_t *rover; - - if (flip) - { - flag = SF_FLIPSPECIAL_CEILING; - } - else - { - flag = SF_FLIPSPECIAL_FLOOR; - } - - if (sec->flags & flag) - { - if (K_BotHatesThisSectorsSpecial(player, sec)) - { - return true; - } - } - - for (rover = sec->ffloors; rover; rover = rover->next) - { - if (!(rover->flags & FF_EXISTS)) - { - continue; - } - - if (!(rover->master->frontsector->flags & flag)) - { - continue; - } - - if (((*rover->bottomheight >= player->mo->z + player->mo->height) && (flip)) - || ((*rover->topheight <= player->mo->z) && (!flip))) - { - if (K_BotHatesThisSectorsSpecial(player, sec)) - { - return true; - } - } - } - - return false; -} - -mobj_t *botmo = NULL; -fixed_t distancetocheck = 0; - -fixed_t closestlinedist = INT32_MAX; - -INT16 curturn = 0; -INT16 badsteerglobal = 0; - -fixed_t eggboxx, eggboxy; -UINT8 randomitems = 0; -UINT8 eggboxes = 0; - -static boolean K_FindEggboxes(mobj_t *thing) -{ - fixed_t dist; - - if (thing->type != MT_RANDOMITEM && thing->type != MT_EGGMANITEM) - { - return true; - } - - if (!thing->health) - { - return true; - } - - dist = P_AproxDistance(thing->x - eggboxx, thing->y - eggboxy); - - if (dist > distancetocheck) - { - return true; - } - - if (thing->type == MT_RANDOMITEM) - { - randomitems++; - } - else - { - eggboxes++; - } - return true; -} - -static UINT8 K_EggboxStealth(fixed_t x, fixed_t y) -{ - INT32 xl, xh, yl, yh, bx, by; - - eggboxx = x; - eggboxy = y; - distancetocheck = (mapobjectscale * 256); - randomitems = 0; - eggboxes = 0; - - xl = (unsigned)(eggboxx - distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(eggboxx + distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(eggboxy - distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(eggboxy + distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - - BMBOUNDFIX(xl, xh, yl, yh); - - for (bx = xl; bx <= xh; bx++) - { - for (by = yl; by <= yh; by++) - { - P_BlockThingsIterator(bx, by, K_FindEggboxes); - } - } - - return (randomitems * eggboxes); -} - -static inline boolean K_FindBlockingWalls(line_t *line) -{ - // Condensed version of PIT_CheckLine - const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale); - fixed_t maxstep = maxstepmove; - fixed_t linedist = INT32_MAX; - INT32 lineside = 0; - - if (!botmo || P_MobjWasRemoved(botmo) || !botmo->player) - { - return false; - } - - if (line->polyobj && !(line->polyobj->flags & POF_SOLID)) - { - return true; - } - - if (tmbbox[BOXRIGHT] <= line->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= line->bbox[BOXRIGHT] - || tmbbox[BOXTOP] <= line->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= line->bbox[BOXTOP]) - { - return true; - } - - if (P_BoxOnLineSide(tmbbox, line) != -1) - { - return true; - } - - lineside = P_PointOnLineSide(botmo->x, botmo->y, line); - - // one sided line - if (!line->backsector) - { - if (lineside) - { - // don't hit the back side - return true; - } - - goto blocked; - } - - if ((line->flags & ML_IMPASSABLE) || (line->flags & ML_BLOCKPLAYERS)) - { - goto blocked; - } - - // set openrange, opentop, openbottom - P_LineOpening(line, botmo); - - if (botmo->player->kartstuff[k_waterskip]) - maxstep += maxstepmove; - - if (P_MobjTouchingSectorSpecial(botmo, 1, 13, false)) - maxstep <<= 1; - else if (P_MobjTouchingSectorSpecial(botmo, 1, 12, false)) - maxstep = 0; - - if ((openrange < botmo->height) // doesn't fit - || (opentop - botmo->z < botmo->height) // mobj is too high - || (openbottom - botmo->z > maxstep)) // too big a step up - { - goto blocked; - } - - if (!K_BotHatesThisSector(botmo->player, botmo->subsector->sector)) - { - // Treat damage sectors like walls - - if (lineside) - { - if (K_BotHatesThisSector(botmo->player, line->frontsector)) - goto blocked; - } - else - { - if (K_BotHatesThisSector(botmo->player, line->backsector)) - goto blocked; - } - } - - // We weren't blocked! - return true; - -blocked: - linedist = K_DistanceOfLineFromPoint(line->v1->x, line->v1->y, line->v2->x, line->v2->y, botmo->x, botmo->y); - linedist -= (botmo->radius * 8); // Maintain a reasonable distance away from it - - if (linedist > distancetocheck) - { - return true; - } - - if (linedist <= 0) - { - closestlinedist = 0; - return false; - } - - if (linedist < closestlinedist) - { - closestlinedist = linedist; - } - - return true; -} - -static fixed_t K_BotReducePrediction(player_t *player) -{ - INT32 xl, xh, yl, yh, bx, by; - - botmo = player->mo; - distancetocheck = (player->mo->radius * 8) + (player->speed * 4); - closestlinedist = INT32_MAX; - - tmx = player->mo->x; - tmy = player->mo->y; - - xl = (unsigned)(tmx - distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(tmx + distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(tmy - distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(tmy + distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - - BMBOUNDFIX(xl, xh, yl, yh); - - tmbbox[BOXTOP] = tmy + distancetocheck; - tmbbox[BOXBOTTOM] = tmy - distancetocheck; - tmbbox[BOXRIGHT] = tmx + distancetocheck; - tmbbox[BOXLEFT] = tmx - distancetocheck; - - // Check for lines that the bot might collide with - for (bx = xl; bx <= xh; bx++) - { - for (by = yl; by <= yh; by++) - { - P_BlockLinesIterator(bx, by, K_FindBlockingWalls); - } - } - - if (closestlinedist == INT32_MAX) - { - return FRACUNIT; - } - - return FixedDiv(closestlinedist, distancetocheck); -} + Input Arguments:- + player - Player to compare. + Return:- + Bot prediction struct. +--------------------------------------------------*/ static botprediction_t *K_CreateBotPrediction(player_t *player) { const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN); // Reduce prediction based on how fast you can turn @@ -766,581 +531,11 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) return predict; } -static void K_SteerFromObject(mobj_t *bot, mobj_t *thing, fixed_t fulldist, fixed_t xdist, boolean towards, INT16 amount) -{ - angle_t destangle = R_PointToAngle2(bot->x, bot->y, thing->x, thing->y); - angle_t angle; - SINT8 flip = 1; - - amount = (amount * FixedDiv(distancetocheck - fulldist, distancetocheck)) / FRACUNIT; - - if (amount == 0) - { - // Shouldn't happen - return; - } - - if (towards) - { - if (xdist < FixedHypot(bot->radius, thing->radius)) - { - // Don't need to turn any harder! - - if (abs(badsteerglobal) <= amount) - { - badsteerglobal = 0; - } - else - { - if (badsteerglobal > 0) - { - badsteerglobal -= amount; - } - else if (badsteerglobal < 0) - { - badsteerglobal += amount; - } - } - - return; - } - - // Still turning towards it, flip. - flip = -flip; - } - - angle = (bot->angle - destangle); - if (angle < ANGLE_180) - { - flip = -flip; - } - - // If going in the opposite direction of where you wanted to turn, - // then reduce the amount that you can turn in that direction. - if ((flip == 1 && curturn < 0) - || (flip == -1 && curturn > 0)) - { - amount /= 4; - } - - badsteerglobal += amount * flip; -} - -static boolean K_BotSteerObjects(mobj_t *thing) -{ - INT16 anglediff; - fixed_t xdist, ydist, fulldist; - angle_t destangle, angle; - INT16 attack = ((9 - botmo->player->kartspeed) * KART_FULLTURN) / 8; // Acceleration chars are more aggressive - INT16 dodge = ((9 - botmo->player->kartweight) * KART_FULLTURN) / 8; // Handling chars dodge better - - if (!botmo || P_MobjWasRemoved(botmo) || !botmo->player) - { - return false; - } - - if (!thing->health) - { - return true; - } - - if (botmo == thing) - { - return true; - } - - xdist = K_DistanceOfLineFromPoint( - botmo->x, botmo->y, - botmo->x + FINECOSINE(botmo->angle >> ANGLETOFINESHIFT), botmo->y + FINESINE(botmo->angle >> ANGLETOFINESHIFT), - thing->x, thing->y - ) / 2; // weight x dist more heavily than y dist - - ydist = K_DistanceOfLineFromPoint( - botmo->x, botmo->y, - botmo->x + FINECOSINE((botmo->angle + ANGLE_90) >> ANGLETOFINESHIFT), botmo->y + FINESINE((botmo->angle + ANGLE_90) >> ANGLETOFINESHIFT), - thing->x, thing->y - ); - - fulldist = FixedHypot(xdist, ydist); - - if (fulldist > distancetocheck) - { - return true; - } - - if (!P_CheckSight(botmo, thing)) - { - return true; - } - - destangle = R_PointToAngle2(botmo->x, botmo->y, thing->x, thing->y); - angle = (botmo->angle - destangle); - - if (angle < ANGLE_180) - { - anglediff = AngleFixed(angle)>>FRACBITS; - } - else - { - anglediff = 360-(AngleFixed(angle)>>FRACBITS); - } - - anglediff = abs(anglediff); - -#define PlayerAttackSteer(botcond, thingcond) \ - if ((botcond) && !(thingcond)) \ - { \ - K_SteerFromObject(botmo, thing, fulldist, xdist, true, 2 * (KART_FULLTURN + attack)); \ - } \ - else if ((thingcond) && !(botcond)) \ - { \ - K_SteerFromObject(botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); \ - } - - switch (thing->type) - { - case MT_BANANA: - case MT_BANANA_SHIELD: - case MT_EGGMANITEM_SHIELD: - case MT_ORBINAUT: - case MT_ORBINAUT_SHIELD: - case MT_JAWZ: - case MT_JAWZ_DUD: - case MT_JAWZ_SHIELD: - case MT_SSMINE: - case MT_SSMINE_SHIELD: - case MT_BALLHOG: - case MT_SPB: - case MT_BUBBLESHIELDTRAP: - K_SteerFromObject(botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); - break; - case MT_RANDOMITEM: - if (anglediff >= 60) - { - break; - } - - if (P_CanPickupItem(botmo->player, 1)) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, true, KART_FULLTURN + attack); - } - break; - case MT_EGGMANITEM: - if (anglediff >= 60) - { - break; - } - - if (P_CanPickupItem(botmo->player, 1)) // Can pick up an actual item - { - const UINT8 stealth = K_EggboxStealth(thing->x, thing->y); - const UINT8 requiredstealth = (botmo->player->botvars.difficulty * botmo->player->botvars.difficulty); - - if (stealth >= requiredstealth) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, true, 2 * (KART_FULLTURN + attack)); - } - else - { - K_SteerFromObject(botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); - } - } - break; - case MT_FLOATINGITEM: - if (anglediff >= 60) - { - break; - } - - if (P_CanPickupItem(botmo->player, 3)) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, true, KART_FULLTURN + attack); - } - break; - case MT_RING: - case MT_FLINGRING: - if (anglediff >= 60) - { - break; - } - - if ((RINGTOTAL(botmo->player) < 20 && !botmo->player->kartstuff[k_ringlock] - && P_CanPickupItem(botmo->player, 0)) - && !thing->extravalue1 - && (botmo->player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD)) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, true, - (RINGTOTAL(botmo->player) < 3 - ? (4 * (KART_FULLTURN + attack)) - : (KART_FULLTURN + attack)) - ); - } - break; - case MT_PLAYER: - if (thing->player - && !thing->player->kartstuff[k_hyudorotimer] - && !botmo->player->kartstuff[k_hyudorotimer]) - { - // There REALLY ought to be a better way to handle this logic, right?! - // Squishing - PlayerAttackSteer( - botmo->scale > thing->scale + (mapobjectscale/8), - thing->scale > botmo->scale + (mapobjectscale/8) - ) - // Invincibility - else PlayerAttackSteer( - botmo->player->kartstuff[k_invincibilitytimer], - thing->player->kartstuff[k_invincibilitytimer] - ) - // Thunder Shield - else PlayerAttackSteer( - botmo->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD, - thing->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD - ) - // Bubble Shield - else PlayerAttackSteer( - botmo->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD, - thing->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD - ) - // Flame Shield - else PlayerAttackSteer( - botmo->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD, - thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD - ) - // Has held item shield - else PlayerAttackSteer( - (botmo->player->kartstuff[k_itemheld] || botmo->player->kartstuff[k_eggmanheld]), - (thing->player->kartstuff[k_itemheld] || thing->player->kartstuff[k_eggmanheld]) - ) - // Ring Sting - else PlayerAttackSteer( - thing->player->kartstuff[k_rings] <= 0, - botmo->player->kartstuff[k_rings] <= 0 - ) - else - { - // After ALL of that, we can do standard bumping - fixed_t ourweight = K_GetMobjWeight(botmo, thing); - fixed_t theirweight = K_GetMobjWeight(thing, botmo); - fixed_t weightdiff = 0; - - if (anglediff >= 90) - { - weightdiff = theirweight - ourweight; - } - else - { - weightdiff = ourweight - theirweight; - } - - if (weightdiff > mapobjectscale) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, true, KART_FULLTURN + attack); - } - else - { - K_SteerFromObject(botmo, thing, fulldist, xdist, false, KART_FULLTURN + dodge); - } - } - } - break; - case MT_BOTHINT: - if (anglediff >= 60) - { - break; - } - - if (thing->extravalue1 == 0) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, false, thing->extravalue2 * (KART_FULLTURN + dodge)); - } - { - K_SteerFromObject(botmo, thing, fulldist, xdist, true, thing->extravalue2 * (KART_FULLTURN + attack)); - } - break; - default: - if (thing->flags & (MF_SOLID|MF_ENEMY|MF_BOSS|MF_PAIN|MF_MISSILE|MF_FIRE)) - { - K_SteerFromObject(botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); - } - break; - } - - return true; -} - -static INT16 K_BotFindObjects(player_t *player, INT16 turn) -{ - INT32 xl, xh, yl, yh, bx, by; - - badsteerglobal = 0; - - botmo = player->mo; - curturn = turn; - distancetocheck = 2048*mapobjectscale; - - xl = (unsigned)(botmo->x - distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - xh = (unsigned)(botmo->x + distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; - yl = (unsigned)(botmo->y - distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - yh = (unsigned)(botmo->y + distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; - - BMBOUNDFIX(xl, xh, yl, yh); - - for (bx = xl; bx <= xh; bx++) - { - for (by = yl; by <= yh; by++) - { - P_BlockThingsIterator(bx, by, K_BotSteerObjects); - } - } - - return badsteerglobal; -} - -static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius) -{ - UINT8 i; - - if (player->pflags & PF_ATTACKDOWN) - { - return false; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing]) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= radius) - { - cmd->buttons |= BT_ATTACK; - return true; - } - } - - return false; -} - -static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius) -{ - UINT8 i; - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing]) - { - continue; - } - - dist = P_AproxDistance( - x - target->mo->x, - y - target->mo->y - ); - - if (dist <= radius) - { - return true; - } - } - - return false; -} - -static boolean K_BotRevealsBanana(player_t *player, INT16 turnamt, boolean mine) -{ - UINT8 i; - - // Only get out bananas if you have a target - - if (abs(turnamt) >= KART_FULLTURN/2) - { - return false; - } - else - { - UINT32 airtime = FixedDiv((30 * player->mo->scale) + player->mo->momz, gravity); - fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - const angle_t momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, momangle, (throwspeed + player->speed) * airtime); - fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, momangle, (throwspeed + player->speed) * airtime); - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - return true; - } - - if (mine) - { - airtime = FixedDiv((40 * player->mo->scale) + player->mo->momz, gravity); - throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) * 2; - estx = player->mo->x + P_ReturnThrustX(NULL, momangle, (throwspeed + player->speed) * airtime); - esty = player->mo->y + P_ReturnThrustY(NULL, momangle, (throwspeed + player->speed) * airtime); - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - return true; - } - } - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= (player->mo->radius * 16)) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad >= 180-cone) - { - return true; - } - } - } - - return false; -} - -static boolean K_BotRevealsEggbox(player_t *player) -{ - const UINT32 airtime = FixedDiv((30 * player->mo->scale) + player->mo->momz, gravity); - const fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - const angle_t momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - const fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, momangle, (throwspeed + player->speed) * airtime); - const fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, momangle, (throwspeed + player->speed) * airtime); - const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y); - UINT8 i; - - if (stealth > 1) - { - return true; - } - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - return true; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= (player->mo->radius * 16)) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad >= 180-cone) - { - return true; - } - } - } - - return false; -} +/*-------------------------------------------------- + void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) + See header file for description. +--------------------------------------------------*/ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) { botprediction_t *predict = NULL; @@ -1377,11 +572,19 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) // Start boost handler if (leveltime <= starttime) { - if (leveltime >= starttime-35) + tic_t boosthold = starttime - TICRATE; + + boosthold -= (MAXBOTDIFFICULTY - player->botvars.difficulty); + + if (leveltime >= boosthold) + { cmd->buttons |= BT_ACCELERATE; + } + return; } + // Handle steering towards waypoints! if (player->nextwaypoint != NULL && player->nextwaypoint->mobj != NULL && !P_MobjWasRemoved(player->nextwaypoint->mobj)) { SINT8 turnsign = 0; @@ -1495,723 +698,8 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) } } - if (player->kartstuff[k_userings] == 1) - { - if (!player->exiting) - { - INT32 saferingsval = 16 - K_GetKartRingPower(player); - - if (player->speed < K_GetKartSpeed(player, false)/2 // Being slowed down too much - || player->kartstuff[k_speedboost] > (FRACUNIT/5)) // Have another type of boost (tethering) - { - saferingsval -= 5; - } - - if (player->kartstuff[k_rings] > saferingsval) - { - cmd->buttons |= BT_ATTACK; - } - } - } - else if (player->kartstuff[k_itemroulette] && !(player->pflags & PF_ATTACKDOWN)) - { - // Mashing behaviors - - if (player->kartstuff[k_rings] < 0 && cv_superring.value) - { - // Uh oh, we need a loan! - // It'll be better in the long run for bots to lose an item set for 10 free rings. - cmd->buttons |= BT_ATTACK; - } - } - else - { - if (player->botvars.itemdelay) - { - player->botvars.itemdelay--; - player->botvars.itemconfirm = 0; - } - else if (player->kartstuff[k_eggmanexplode]) - { - if (player->kartstuff[k_position] == 1) - { - cmd->forwardmove /= 2; - cmd->buttons |= BT_BRAKE; - } - - K_BotUseItemNearPlayer(player, cmd, 128*player->mo->scale); - } - else if (player->kartstuff[k_eggmanheld]) - { - const UINT32 airtime = FixedDiv((30 * player->mo->scale) + player->mo->momz, gravity); - const fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - const angle_t momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - const fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, momangle, (throwspeed + player->speed) * airtime); - const fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, momangle, (throwspeed + player->speed) * airtime); - const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y); - SINT8 throwdir = -1; - UINT8 i; - - player->botvars.itemconfirm++; - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - player->botvars.itemconfirm += player->botvars.difficulty / 2; - throwdir = 1; - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= (player->mo->radius * 16)) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad >= 180-cone) - { - player->botvars.itemconfirm += player->botvars.difficulty; - throwdir = -1; - } - } - } - - if (stealth > 1) - { - player->botvars.itemconfirm += player->botvars.difficulty * 4; - throwdir = -1; - } - - if (player->kartstuff[k_itemroulette] > 0) // Just grabbed an item - { - player->botvars.itemconfirm += player->botvars.difficulty * 4; - throwdir = -1; - } - - if ((player->botvars.itemconfirm > 2*TICRATE || player->kartstuff[k_bananadrag] >= TICRATE) - && !(player->pflags & PF_ATTACKDOWN)) - { - if (throwdir == 1) - { - cmd->buttons |= BT_FORWARD; - } - else if (throwdir == -1) - { - cmd->buttons |= BT_BACKWARD; - } - - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - else if (player->kartstuff[k_rocketsneakertimer] > 0) - { - if (player->botvars.itemconfirm > TICRATE) - { - if (!player->kartstuff[k_sneakertimer] && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - else - { - player->botvars.itemconfirm++; - } - } - else if (player->kartstuff[k_stealingtimer] == 0 && player->kartstuff[k_stolentimer] == 0) - { - switch (player->kartstuff[k_itemtype]) - { - case KITEM_INVINCIBILITY: - case KITEM_SPB: - case KITEM_GROW: - case KITEM_SHRINK: - case KITEM_HYUDORO: - case KITEM_SUPERRING: - if (!(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - break; - case KITEM_SNEAKER: - if ((player->kartstuff[k_offroad] && K_ApplyOffroad(player)) // Stuck in offroad, use it NOW - || K_GetWaypointIsShortcut(player->nextwaypoint) == true // Going toward a shortcut! - || player->speed < K_GetKartSpeed(player, false)/2 // Being slowed down too much - || player->kartstuff[k_speedboost] > (FRACUNIT/8) // Have another type of boost (tethering) - || player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long - { - if (!player->kartstuff[k_sneakertimer] && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 2*TICRATE; - } - } - else - { - player->botvars.itemconfirm++; - } - break; - case KITEM_ROCKETSNEAKER: - if (player->kartstuff[k_rocketsneakertimer] <= 0 && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - break; - case KITEM_BANANA: - if (!player->kartstuff[k_itemheld]) - { - if ((K_BotRevealsBanana(player, turnamt, false) || (player->botvars.itemconfirm++ > 5*TICRATE)) - && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - else - { - SINT8 throwdir = -1; - UINT8 i; - - player->botvars.itemconfirm++; - - if (abs(turnamt) >= KART_FULLTURN/2) - { - player->botvars.itemconfirm += player->botvars.difficulty / 2; - } - else - { - const UINT32 airtime = FixedDiv((30 * player->mo->scale) + player->mo->momz, gravity); - const fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - const angle_t momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - const fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, momangle, (throwspeed + player->speed) * airtime); - const fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, momangle, (throwspeed + player->speed) * airtime); - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - player->botvars.itemconfirm += player->botvars.difficulty * 2; - throwdir = 1; - } - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= (player->mo->radius * 16)) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad >= 180-cone) - { - player->botvars.itemconfirm += player->botvars.difficulty; - throwdir = -1; - } - } - } - - if ((player->botvars.itemconfirm > 2*TICRATE || player->kartstuff[k_bananadrag] >= TICRATE) - && !(player->pflags & PF_ATTACKDOWN)) - { - if (throwdir == 1) - { - cmd->buttons |= BT_FORWARD; - } - else if (throwdir == -1) - { - cmd->buttons |= BT_BACKWARD; - } - - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - break; - case KITEM_EGGMAN: - if (!player->kartstuff[k_eggmanheld]) - { - if ((K_BotRevealsEggbox(player) || (player->botvars.itemconfirm++ > 20*TICRATE)) - && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - break; - case KITEM_ORBINAUT: - if (!player->kartstuff[k_itemheld] && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - else if (player->kartstuff[k_position] != 1) // Hold onto orbiting items when in 1st :) - /* FALL-THRU */ - case KITEM_BALLHOG: - { - const fixed_t topspeed = K_GetKartSpeed(player, false); - fixed_t radius = (player->mo->radius * 32); - SINT8 throwdir = -1; - UINT8 i; - - if (player->speed > topspeed) - { - radius = FixedMul(radius, FixedDiv(player->speed, topspeed)); - } - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= radius) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad <= cone) - { - player->botvars.itemconfirm += player->botvars.difficulty * 2; - throwdir = 1; - } - else if (ad >= 180-cone) - { - player->botvars.itemconfirm += player->botvars.difficulty; - } - } - } - - if ((player->botvars.itemconfirm > 5*TICRATE) - && !(player->pflags & PF_ATTACKDOWN)) - { - if (throwdir == 1) - { - cmd->buttons |= BT_FORWARD; - } - else if (throwdir == -1) - { - cmd->buttons |= BT_BACKWARD; - } - - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - break; - case KITEM_JAWZ: - if (!player->kartstuff[k_itemheld] && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - else if (player->kartstuff[k_position] != 1) // Hold onto orbiting items when in 1st :) - { - SINT8 throwdir = 1; - UINT8 i; - - player->botvars.itemconfirm++; - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= (player->mo->radius * 32)) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad >= 180-cone) - { - player->botvars.itemconfirm += player->botvars.difficulty; - throwdir = -1; - } - } - } - - if (player->kartstuff[k_lastjawztarget] != -1) - { - player->botvars.itemconfirm += player->botvars.difficulty * 2; - throwdir = 1; - } - - if ((player->botvars.itemconfirm > 5*TICRATE) - && !(player->pflags & PF_ATTACKDOWN)) - { - if (throwdir == 1) - { - cmd->buttons |= BT_FORWARD; - } - else if (throwdir == -1) - { - cmd->buttons |= BT_BACKWARD; - } - - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - break; - case KITEM_MINE: - if (!player->kartstuff[k_itemheld]) - { - if ((K_BotRevealsBanana(player, turnamt, true) || (player->botvars.itemconfirm++ > 5*TICRATE)) - && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - else - { - SINT8 throwdir = 0; - UINT8 i; - - player->botvars.itemconfirm++; - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing] - || !P_CheckSight(player->mo, target->mo)) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= (player->mo->radius * 16)) - { - angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); - INT16 ad = 0; - const INT16 cone = 10; - - if (a < ANGLE_180) - { - ad = AngleFixed(a)>>FRACBITS; - } - else - { - ad = 360-(AngleFixed(a)>>FRACBITS); - } - - ad = abs(ad); - - if (ad >= 180-cone) - { - player->botvars.itemconfirm += player->botvars.difficulty; - throwdir = -1; - } - } - } - - if (abs(turnamt) >= KART_FULLTURN/2) - { - player->botvars.itemconfirm += player->botvars.difficulty / 2; - throwdir = -1; - } - else - { - UINT32 airtime = FixedDiv((30 * player->mo->scale) + player->mo->momz, gravity); - fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); - angle_t momangle = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy); - fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, momangle, (throwspeed + player->speed) * airtime); - fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, momangle, (throwspeed + player->speed) * airtime); - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - player->botvars.itemconfirm += player->botvars.difficulty * 2; - throwdir = 0; - } - - airtime = FixedDiv((40 * player->mo->scale) + player->mo->momz, gravity); - throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)) * 2; - estx = player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, (throwspeed + player->speed) * airtime); - esty = player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, (throwspeed + player->speed) * airtime); - - if (K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2)) - { - player->botvars.itemconfirm += player->botvars.difficulty / 2; - throwdir = 1; - } - } - - if (((player->botvars.itemconfirm > 2*TICRATE) - || (player->kartstuff[k_bananadrag] >= TICRATE)) - && !(player->pflags & PF_ATTACKDOWN)) - { - if (throwdir == 1) - { - cmd->buttons |= BT_FORWARD; - } - else if (throwdir == -1) - { - cmd->buttons |= BT_BACKWARD; - } - - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - } - break; - case KITEM_THUNDERSHIELD: - if (!K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale)) - { - if (player->botvars.itemconfirm > 10*TICRATE && !(player->pflags & PF_ATTACKDOWN)) - { - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - } - else - { - player->botvars.itemconfirm++; - } - } - break; - case KITEM_BUBBLESHIELD: - { - boolean hold = false; - - if (player->kartstuff[k_bubbleblowup] <= 0) - { - UINT8 i; - - player->botvars.itemconfirm++; - - if (player->kartstuff[k_bubblecool] <= 0) - { - const fixed_t radius = 192 * player->mo->scale; - - for (i = 0; i < MAXPLAYERS; i++) - { - player_t *target = NULL; - fixed_t dist = INT32_MAX; - - if (!playeringame[i]) - { - continue; - } - - target = &players[i]; - - if (target->mo == NULL || P_MobjWasRemoved(target->mo) - || player == target || target->spectator - || target->powers[pw_flashing]) - { - continue; - } - - dist = P_AproxDistance(P_AproxDistance( - player->mo->x - target->mo->x, - player->mo->y - target->mo->y), - (player->mo->z - target->mo->z) / 4 - ); - - if (dist <= radius) - { - hold = true; - break; - } - } - } - } - else if (player->kartstuff[k_bubbleblowup] >= bubbletime) - { - if (player->botvars.itemconfirm >= 10*TICRATE) - { - hold = true; - } - } - else if (player->kartstuff[k_bubbleblowup] < bubbletime) - { - hold = true; - } - - if (hold && player->kartstuff[k_holdready]) - { - cmd->buttons |= BT_ATTACK; - } - } - break; - case KITEM_FLAMESHIELD: - if (player->botvars.itemconfirm > 0) - { - player->botvars.itemconfirm--; - } - else if (player->kartstuff[k_holdready]) - { - INT32 flamemax = player->kartstuff[k_flamelength] * flameseg; - - if (player->kartstuff[k_flamemeter] < flamemax || flamemax == 0) - { - cmd->buttons |= BT_ATTACK; - } - else - { - player->botvars.itemconfirm = 3*flamemax/4; - } - } - break; - default: - if (player->kartstuff[k_itemtype] != KITEM_NONE && !(player->pflags & PF_ATTACKDOWN)) - cmd->buttons |= BT_ATTACK; - player->botvars.itemconfirm = 0; - break; - } - } - } + // Handle item usage + K_BotItemUsage(player, cmd, turnamt); if (turnamt != 0) { @@ -2253,12 +741,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) if (abs(player->botvars.turnconfirm) >= BOTTURNCONFIRM) { - // You're probably commiting to your turn, here you go. + // You're commiting to your turn, you're allowed! cmd->driftturn = turnamt; cmd->angleturn += K_GetKartTurnValue(player, turnamt); } } + // Free the prediction we made earlier if (predict != NULL) { Z_Free(predict); diff --git a/src/k_bot.h b/src/k_bot.h index 0525480b4..81257ecbf 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -1,14 +1,16 @@ -// SONIC ROBO BLAST 2 +// SONIC ROBO BLAST 2 KART //----------------------------------------------------------------------------- -// Copyright (C) 2007-2016 by John "JTE" Muniz. -// Copyright (C) 2012-2018 by Sonic Team Junior. +// Copyright (C) 2018-2020 by Kart Krew // // This program is free software distributed under the // terms of the GNU General Public License, version 2. // See the 'LICENSE' file for more details. //----------------------------------------------------------------------------- /// \file k_bot.h -/// \brief Basic bot handling +/// \brief Bot logic & ticcmd generation code + +#ifndef __K_BOT__ +#define __K_BOT__ #include "k_waypoint.h" #include "d_player.h" @@ -20,16 +22,196 @@ // Made it as small as possible without making it look like the bots are twitching constantly. #define BOTTURNCONFIRM 7 -// Path that bot will attempt to take +// Point for bots to aim for typedef struct botprediction_s { fixed_t x, y; fixed_t radius; angle_t dir; } botprediction_t; -boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *newplayernum); -void K_UpdateMatchRaceBots(void); + +// AVAILABLE FOR LUA + + +/*-------------------------------------------------- + boolean K_PlayerUsesBotMovement(player_t *player); + + Tells if this player is being controlled via bot movement code (is a bot, or is exiting). + + Input Arguments:- + player - Player to check. + + Return:- + true if using bot movement code, otherwise false. +--------------------------------------------------*/ + boolean K_PlayerUsesBotMovement(player_t *player); + + +/*-------------------------------------------------- + boolean K_BotCanTakeCut(player_t *player); + + Tells if this bot is able to take shortcuts (currently unaffected by offroad, + or has certain items ready). + + Input Arguments:- + player - Player to check. + + Return:- + true if able to take shortcuts, otherwise false. +--------------------------------------------------*/ + boolean K_BotCanTakeCut(player_t *player); + + +/*-------------------------------------------------- + fixed_t K_BotRubberband(player_t *player); + + Gives a multiplier for a bot's rubberbanding. Meant to be used for top speed, + acceleration, and handling. + + Input Arguments:- + player - Player to check. + + Return:- + A multiplier in fixed point scale, between 0.875 and 2.0. +--------------------------------------------------*/ + fixed_t K_BotRubberband(player_t *player); + + +/*-------------------------------------------------- + fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy); + + Gets the distance of a point away from a line. + TODO: Could go in another file? + + Input Arguments:- + v1x - Line's first vertex x position. + v1y - Line's first vertex y position. + v2x - Line's second vertex x position. + v2y - Line's second vertex y position. + cx - Point's x position. + cy - Point's y position. + + Return:- + The distance between the point and the line. +--------------------------------------------------*/ + +fixed_t K_DistanceOfLineFromPoint(fixed_t v1x, fixed_t v1y, fixed_t v2x, fixed_t v2y, fixed_t cx, fixed_t cy); + + +// NOT AVAILABLE FOR LUA + + +/*-------------------------------------------------- + boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *newplayernum); + + Returns the waypoint actually being used as the finish line. + + Input Arguments:- + skin - Skin number that the bot will use. + difficulty - Difficulty level this bot will use. + newplayernum - Pointer to the last valid player slot number. + Is a pointer so that this function can be called multiple times to add more than one bot. + + Return:- + true if a bot packet can be sent, otherwise false. +--------------------------------------------------*/ + +boolean K_AddBot(UINT8 skin, UINT8 difficulty, UINT8 *newplayernum); + + +/*-------------------------------------------------- + void K_UpdateMatchRaceBots(void); + + Updates the number of bots in the server and their difficulties for Match Race. +--------------------------------------------------*/ + +void K_UpdateMatchRaceBots(void); + + +/*-------------------------------------------------- + UINT8 K_EggboxStealth(fixed_t x, fixed_t y); + + Gets a "stealth" value for a position, to figure out how + well Eggman boxes blend into random items. + + Input Arguments:- + x - X coordinate to check. + y - Y coordinate to check. + + Return:- + Stealth value for the position. +--------------------------------------------------*/ + +UINT8 K_EggboxStealth(fixed_t x, fixed_t y); + + +/*-------------------------------------------------- + fixed_t K_BotReducePrediction(player_t *player); + + Finds walls nearby the specified player, to create a multiplier + to pull bot predictions back by. + + Input Arguments:- + player - Player to compare. + + Return:- + Multiplier in fixed point scale. +--------------------------------------------------*/ + +fixed_t K_BotReducePrediction(player_t *player); + + +/*-------------------------------------------------- + INT16 K_BotFindObjects(player_t *player, INT16 turn); + + Generates a sum for objects to steer towards/away from. + + Input Arguments:- + player - Player to compare. + turn - Turn value before object steering. + + Return:- + Turn amount sum to add to final product. +--------------------------------------------------*/ + +INT16 K_BotFindObjects(player_t *player, INT16 turn); + + +/*-------------------------------------------------- + void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd); + + Gives a multiplier for a bot's rubberbanding. Meant to be used for top speed, + acceleration, and handling. + + Input Arguments:- + player - Player to generate the ticcmd for. + cmd - The player's ticcmd to modify. + + Return:- + None +--------------------------------------------------*/ + void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd); + + +/*-------------------------------------------------- + void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt); + + Item usage part of ticcmd generation. + + Input Arguments:- + player - Player to generate the ticcmd for. + cmd - The player's ticcmd to modify. + turnamt - How hard the bot is turning. + + Return:- + None +--------------------------------------------------*/ + +void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt); + + +#endif diff --git a/src/k_botitem.c b/src/k_botitem.c new file mode 100644 index 000000000..55f8e15e4 --- /dev/null +++ b/src/k_botitem.c @@ -0,0 +1,1095 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2020 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_botitem.c +/// \brief Bot item usage logic + +#include "doomdef.h" +#include "d_player.h" +#include "g_game.h" +#include "r_main.h" +#include "p_local.h" +#include "k_bot.h" +#include "lua_hook.h" +#include "byteptr.h" +#include "d_net.h" // nodetoplayer +#include "k_kart.h" +#include "z_zone.h" +#include "i_system.h" +#include "p_maputl.h" +#include "d_ticcmd.h" +#include "m_random.h" +#include "r_things.h" // numskins + +/*-------------------------------------------------- + static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius) + + Looks for players around the bot, and presses the item button + if there is one in range. + + Input Arguments:- + player - Bot to compare against. + cmd - The bot's ticcmd. + radius - The radius to look for players in. + + Return:- + true if a player was found & we can press the item button, otherwise false. +--------------------------------------------------*/ +static boolean K_BotUseItemNearPlayer(player_t *player, ticcmd_t *cmd, fixed_t radius) +{ + UINT8 i; + + if (player->pflags & PF_ATTACKDOWN) + { + return false; + } + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *target = NULL; + fixed_t dist = INT32_MAX; + + if (!playeringame[i]) + { + continue; + } + + target = &players[i]; + + if (target->mo == NULL || P_MobjWasRemoved(target->mo) + || player == target || target->spectator + || target->powers[pw_flashing]) + { + continue; + } + + dist = P_AproxDistance(P_AproxDistance( + player->mo->x - target->mo->x, + player->mo->y - target->mo->y), + (player->mo->z - target->mo->z) / 4 + ); + + if (dist <= radius) + { + cmd->buttons |= BT_ATTACK; + return true; + } + } + + return false; +} + +/*-------------------------------------------------- + static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius) + + Looks for players around a specified x/y coordinate. + + Input Arguments:- + player - Bot to compare against. + x - X coordinate to look around. + y - Y coordinate to look around. + radius - The radius to look for players in. + + Return:- + true if a player was found around the coordinate, otherwise false. +--------------------------------------------------*/ +static boolean K_PlayerNearSpot(player_t *player, fixed_t x, fixed_t y, fixed_t radius) +{ + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *target = NULL; + fixed_t dist = INT32_MAX; + + if (!playeringame[i]) + { + continue; + } + + target = &players[i]; + + if (target->mo == NULL || P_MobjWasRemoved(target->mo) + || player == target || target->spectator + || target->powers[pw_flashing]) + { + continue; + } + + dist = P_AproxDistance( + x - target->mo->x, + y - target->mo->y + ); + + if (dist <= radius) + { + return true; + } + } + + return false; +} + +/*-------------------------------------------------- + static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra) + + Looks for players around the predicted coordinates of their thrown item. + + Input Arguments:- + player - Bot to compare against. + extra - Extra throwing distance, for aim forward on mines. + + Return:- + true if a player was found around the coordinate, otherwise false. +--------------------------------------------------*/ +static boolean K_PlayerPredictThrow(player_t *player, UINT8 extra) +{ + const fixed_t dist = (30 + (extra * 10)) * player->mo->scale; + const UINT32 airtime = FixedDiv(dist + player->mo->momz, gravity); + const fixed_t throwspeed = FixedMul(82 * mapobjectscale, K_GetKartGameSpeedScalar(gamespeed)); + const fixed_t estx = player->mo->x + P_ReturnThrustX(NULL, player->mo->angle, (throwspeed + player->speed) * airtime); + const fixed_t esty = player->mo->y + P_ReturnThrustY(NULL, player->mo->angle, (throwspeed + player->speed) * airtime); + return K_PlayerNearSpot(player, estx, esty, player->mo->radius * 2); +} + +/*-------------------------------------------------- + static boolean K_PlayerInCone(player_t *player, UINT16 cone, boolean flip) + + Looks for players in the . + + Input Arguments:- + player - Bot to compare against. + radius - How far away the targets can be. + cone - Size of cone, in degrees as an integer. + flip - If true, look behind. Otherwise, check in front of the player. + + Return:- + true if a player was found in the cone, otherwise false. +--------------------------------------------------*/ +static boolean K_PlayerInCone(player_t *player, fixed_t radius, UINT16 cone, boolean flip) +{ + UINT8 i; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *target = NULL; + fixed_t dist = INT32_MAX; + + if (!playeringame[i]) + { + continue; + } + + target = &players[i]; + + if (target->mo == NULL || P_MobjWasRemoved(target->mo) + || player == target || target->spectator + || target->powers[pw_flashing] + || !P_CheckSight(player->mo, target->mo)) + { + continue; + } + + dist = P_AproxDistance(P_AproxDistance( + player->mo->x - target->mo->x, + player->mo->y - target->mo->y), + (player->mo->z - target->mo->z) / 4 + ); + + if (dist <= radius) + { + angle_t a = player->mo->angle - R_PointToAngle2(player->mo->x, player->mo->y, target->mo->x, target->mo->y); + INT16 ad = 0; + + if (a < ANGLE_180) + { + ad = AngleFixed(a)>>FRACBITS; + } + else + { + ad = 360-(AngleFixed(a)>>FRACBITS); + } + + ad = abs(ad); + + if (flip) + { + if (ad >= 180-cone) + { + return true; + } + } + else + { + if (ad <= cone) + { + return true; + } + } + } + } + + return false; +} + +/*-------------------------------------------------- + static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir) + + Presses the item button & aim buttons for the bot. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + dir - Aiming direction: 1 for forwards, -1 for backwards, 0 for neutral. + + Return:- + true if we could press, false if not. +--------------------------------------------------*/ +static boolean K_BotGenericPressItem(player_t *player, ticcmd_t *cmd, SINT8 dir) +{ + if (player->pflags & PF_ATTACKDOWN) + { + return false; + } + + if (dir == 1) + { + cmd->buttons |= BT_FORWARD; + } + else if (dir == -1) + { + cmd->buttons |= BT_BACKWARD; + } + + cmd->buttons |= BT_ATTACK; + player->botvars.itemconfirm = 0; + return true; +} + +/*-------------------------------------------------- + static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd) + + Item usage for generic items that you need to tap. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemGenericTap(player_t *player, ticcmd_t *cmd) +{ + if (!(player->pflags & PF_ATTACKDOWN)) + { + cmd->buttons |= BT_ATTACK; + player->botvars.itemconfirm = 0; + } +} + +/*-------------------------------------------------- + static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean mine) + + Decides if a bot is ready to reveal their trap item or not. + + Input Arguments:- + player - Bot that has the banana. + turnamt - How hard they currently are turning. + mine - Set to true to handle Mine-specific behaviors. + + Return:- + true if we want the bot to reveal their banana, otherwise false. +--------------------------------------------------*/ +static boolean K_BotRevealsGenericTrap(player_t *player, INT16 turnamt, boolean mine) +{ + if (abs(turnamt) >= KART_FULLTURN/2) + { + // DON'T reveal on turns, we can place bananas on turns whenever we have multiple to spare, + // or if you missed your intentioned throw/place on a player. + return false; + } + + // Check the predicted throws. + if (K_PlayerPredictThrow(player, 0)) + { + return true; + } + + if (mine) + { + if (K_PlayerPredictThrow(player, 1)) + { + return true; + } + } + + // Check your behind. + if (K_PlayerInCone(player, player->mo->radius * 16, 10, true)) + { + return true; + } + + return false; +} + +/*-------------------------------------------------- + static void K_BotItemGenericTrapShield(player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine) + + Item usage for Eggman shields. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + turnamt - How hard they currently are turning. + mine - Set to true to handle Mine-specific behaviors. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemGenericTrapShield(player_t *player, ticcmd_t *cmd, INT16 turnamt, boolean mine) +{ + if (player->kartstuff[k_itemheld]) + { + return; + } + + if (K_BotRevealsGenericTrap(player, turnamt, mine) || (player->botvars.itemconfirm++ > 5*TICRATE)) + { + K_BotGenericPressItem(player, cmd, 0); + } +} + +/*-------------------------------------------------- + static void K_BotItemGenericOrbitShield(player_t *player, ticcmd_t *cmd) + + Item usage for orbitting shields. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemGenericOrbitShield(player_t *player, ticcmd_t *cmd) +{ + if (player->kartstuff[k_itemheld]) + { + return; + } + + K_BotGenericPressItem(player, cmd, 0); +} + +/*-------------------------------------------------- + static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd) + + Item usage for sneakers. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemSneaker(player_t *player, ticcmd_t *cmd) +{ + if ((player->kartstuff[k_offroad] && K_ApplyOffroad(player)) // Stuck in offroad, use it NOW + || K_GetWaypointIsShortcut(player->nextwaypoint) == true // Going toward a shortcut! + || player->speed < K_GetKartSpeed(player, false)/2 // Being slowed down too much + || player->kartstuff[k_speedboost] > (FRACUNIT/8) // Have another type of boost (tethering) + || player->botvars.itemconfirm > 4*TICRATE) // Held onto it for too long + { + if (!player->kartstuff[k_sneakertimer] && !(player->pflags & PF_ATTACKDOWN)) + { + cmd->buttons |= BT_ATTACK; + player->botvars.itemconfirm = 2*TICRATE; + } + } + else + { + player->botvars.itemconfirm++; + } +} + +/*-------------------------------------------------- + static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd) + + Item usage for rocket sneakers. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemRocketSneaker(player_t *player, ticcmd_t *cmd) +{ + if (player->botvars.itemconfirm > TICRATE) + { + if (!player->kartstuff[k_sneakertimer] && !(player->pflags & PF_ATTACKDOWN)) + { + cmd->buttons |= BT_ATTACK; + player->botvars.itemconfirm = 0; + } + } + else + { + player->botvars.itemconfirm++; + } +} + + +/*-------------------------------------------------- + static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt) + + Item usage for trap item throwing. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + turnamt - How hard they currently are turning. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemBanana(player_t *player, ticcmd_t *cmd, INT16 turnamt) +{ + SINT8 throwdir = -1; + + player->botvars.itemconfirm++; + + if (abs(turnamt) >= KART_FULLTURN/2) + { + player->botvars.itemconfirm += player->botvars.difficulty / 2; + throwdir = -1; + } + else + { + if (K_PlayerPredictThrow(player, 0)) + { + player->botvars.itemconfirm += player->botvars.difficulty * 2; + throwdir = 1; + } + } + + if (K_PlayerInCone(player, player->mo->radius * 16, 10, true)) + { + player->botvars.itemconfirm += player->botvars.difficulty; + throwdir = -1; + } + + if (player->botvars.itemconfirm > 2*TICRATE || player->kartstuff[k_bananadrag] >= TICRATE) + { + K_BotGenericPressItem(player, cmd, throwdir); + } +} + +/*-------------------------------------------------- + static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt) + + Item usage for trap item throwing. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + turnamt - How hard they currently are turning. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemMine(player_t *player, ticcmd_t *cmd, INT16 turnamt) +{ + SINT8 throwdir = 0; + + player->botvars.itemconfirm++; + + if (K_PlayerInCone(player, player->mo->radius * 16, 10, true)) + { + player->botvars.itemconfirm += player->botvars.difficulty; + throwdir = -1; + } + + if (abs(turnamt) >= KART_FULLTURN/2) + { + player->botvars.itemconfirm += player->botvars.difficulty / 2; + throwdir = -1; + } + else + { + if (K_PlayerPredictThrow(player, 0)) + { + player->botvars.itemconfirm += player->botvars.difficulty * 2; + throwdir = 0; + } + + if (K_PlayerPredictThrow(player, 1)) + { + player->botvars.itemconfirm += player->botvars.difficulty * 2; + throwdir = 1; + } + } + + + + if (player->botvars.itemconfirm > 2*TICRATE || player->kartstuff[k_bananadrag] >= TICRATE) + { + K_BotGenericPressItem(player, cmd, throwdir); + } +} + +/*-------------------------------------------------- + static void K_BotItemEggman(player_t *player, ticcmd_t *cmd) + + Item usage for Eggman item throwing. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemEggman(player_t *player, ticcmd_t *cmd) +{ + const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y); + SINT8 throwdir = -1; + + player->botvars.itemconfirm++; + + if (K_PlayerPredictThrow(player, 0)) + { + player->botvars.itemconfirm += player->botvars.difficulty / 2; + throwdir = 1; + } + + if (K_PlayerInCone(player, player->mo->radius * 16, 10, true)) + { + player->botvars.itemconfirm += player->botvars.difficulty; + throwdir = -1; + } + + if (stealth > 1 || player->kartstuff[k_itemroulette] > 0) + { + player->botvars.itemconfirm += player->botvars.difficulty * 4; + throwdir = -1; + } + + if (player->botvars.itemconfirm > 2*TICRATE || player->kartstuff[k_bananadrag] >= TICRATE) + { + K_BotGenericPressItem(player, cmd, throwdir); + } +} + +/*-------------------------------------------------- + static boolean K_BotRevealsEggbox(player_t *player) + + Decides if a bot is ready to place their Eggman item or not. + + Input Arguments:- + player - Bot that has the eggbox. + + Return:- + true if we want the bot to reveal their eggbox, otherwise false. +--------------------------------------------------*/ +static boolean K_BotRevealsEggbox(player_t *player) +{ + const UINT8 stealth = K_EggboxStealth(player->mo->x, player->mo->y); + + // This is a stealthy spot for an eggbox, lets reveal it! + if (stealth > 1) + { + return true; + } + + // Check the predicted throws. + if (K_PlayerPredictThrow(player, 0)) + { + return true; + } + + // Check your behind. + if (K_PlayerInCone(player, player->mo->radius * 16, 10, true)) + { + return true; + } + + return false; +} + +/*-------------------------------------------------- + static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd) + + Item usage for Eggman shields. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemEggmanShield(player_t *player, ticcmd_t *cmd) +{ + if (player->kartstuff[k_eggmanheld]) + { + return; + } + + if (K_BotRevealsEggbox(player) || (player->botvars.itemconfirm++ > 20*TICRATE)) + { + K_BotGenericPressItem(player, cmd, 0); + } +} + +/*-------------------------------------------------- + static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd) + + Item usage for Eggman explosions. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemEggmanExplosion(player_t *player, ticcmd_t *cmd) +{ + if (player->kartstuff[k_position] == 1) + { + cmd->forwardmove /= 2; + cmd->buttons |= BT_BRAKE; + } + + K_BotUseItemNearPlayer(player, cmd, 128*player->mo->scale); +} + +/*-------------------------------------------------- + static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd) + + Item usage for Orbinaut throwing. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemOrbinaut(player_t *player, ticcmd_t *cmd) +{ + const fixed_t topspeed = K_GetKartSpeed(player, false); + fixed_t radius = (player->mo->radius * 32); + SINT8 throwdir = -1; + + if (player->speed > topspeed) + { + radius = FixedMul(radius, FixedDiv(player->speed, topspeed)); + } + + player->botvars.itemconfirm++; + + if (K_PlayerInCone(player, radius, 10, false)) + { + player->botvars.itemconfirm += player->botvars.difficulty * 2; + throwdir = 1; + } + else if (K_PlayerInCone(player, radius, 10, true)) + { + player->botvars.itemconfirm += player->botvars.difficulty; + throwdir = -1; + } + + if (player->botvars.itemconfirm > 5*TICRATE) + { + K_BotGenericPressItem(player, cmd, throwdir); + } +} + +/*-------------------------------------------------- + static void K_BotItemJawz(player_t *player, ticcmd_t *cmd) + + Item usage for Jawz throwing. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemJawz(player_t *player, ticcmd_t *cmd) +{ + const fixed_t topspeed = K_GetKartSpeed(player, false); + fixed_t radius = (player->mo->radius * 32); + SINT8 throwdir = 1; + + if (player->speed > topspeed) + { + radius = FixedMul(radius, FixedDiv(player->speed, topspeed)); + } + + player->botvars.itemconfirm++; + + if (K_PlayerInCone(player, radius, 10, true)) + { + player->botvars.itemconfirm += player->botvars.difficulty; + throwdir = -1; + } + + if (player->kartstuff[k_lastjawztarget] != -1) + { + player->botvars.itemconfirm += player->botvars.difficulty * 2; + throwdir = 1; + } + + if (player->botvars.itemconfirm > 5*TICRATE) + { + K_BotGenericPressItem(player, cmd, throwdir); + } +} + +/*-------------------------------------------------- + static void K_BotItemThunder(player_t *player, ticcmd_t *cmd) + + Item usage for Thunder Shield. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemThunder(player_t *player, ticcmd_t *cmd) +{ + if (!K_BotUseItemNearPlayer(player, cmd, 192*player->mo->scale)) + { + if (player->botvars.itemconfirm > 10*TICRATE) + { + K_BotGenericPressItem(player, cmd, 0); + } + else + { + player->botvars.itemconfirm++; + } + } +} + +/*-------------------------------------------------- + static void K_BotItemBubble(player_t *player, ticcmd_t *cmd) + + Item usage for Bubble Shield. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemBubble(player_t *player, ticcmd_t *cmd) +{ + boolean hold = false; + + if (player->kartstuff[k_bubbleblowup] <= 0) + { + UINT8 i; + + player->botvars.itemconfirm++; + + if (player->kartstuff[k_bubblecool] <= 0) + { + const fixed_t radius = 192 * player->mo->scale; + + for (i = 0; i < MAXPLAYERS; i++) + { + player_t *target = NULL; + fixed_t dist = INT32_MAX; + + if (!playeringame[i]) + { + continue; + } + + target = &players[i]; + + if (target->mo == NULL || P_MobjWasRemoved(target->mo) + || player == target || target->spectator + || target->powers[pw_flashing]) + { + continue; + } + + dist = P_AproxDistance(P_AproxDistance( + player->mo->x - target->mo->x, + player->mo->y - target->mo->y), + (player->mo->z - target->mo->z) / 4 + ); + + if (dist <= radius) + { + hold = true; + break; + } + } + } + } + else if (player->kartstuff[k_bubbleblowup] >= bubbletime) + { + if (player->botvars.itemconfirm >= 10*TICRATE) + { + hold = true; + } + } + else if (player->kartstuff[k_bubbleblowup] < bubbletime) + { + hold = true; + } + + if (hold && player->kartstuff[k_holdready]) + { + cmd->buttons |= BT_ATTACK; + } +} + +/*-------------------------------------------------- + static void K_BotItemFlame(player_t *player, ticcmd_t *cmd) + + Item usage for Flame Shield. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemFlame(player_t *player, ticcmd_t *cmd) +{ + if (player->botvars.itemconfirm > 0) + { + player->botvars.itemconfirm--; + } + else if (player->kartstuff[k_holdready]) + { + INT32 flamemax = player->kartstuff[k_flamelength] * flameseg; + + if (player->kartstuff[k_flamemeter] < flamemax || flamemax == 0) + { + cmd->buttons |= BT_ATTACK; + } + else + { + player->botvars.itemconfirm = 3*flamemax/4; + } + } +} + +/*-------------------------------------------------- + static void K_BotItemRings(player_t *player, ticcmd_t *cmd) + + Item usage for rings. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemRings(player_t *player, ticcmd_t *cmd) +{ + INT32 saferingsval = 16 - K_GetKartRingPower(player); + + if (player->speed < K_GetKartSpeed(player, false)/2 // Being slowed down too much + || player->kartstuff[k_speedboost] > (FRACUNIT/5)) // Have another type of boost (tethering) + { + saferingsval -= 5; + } + + if (player->kartstuff[k_rings] > saferingsval) + { + cmd->buttons |= BT_ATTACK; + } +} + +/*-------------------------------------------------- + static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) + + Item usage for item roulette mashing. + + Input Arguments:- + player - Bot to do this for. + cmd - Bot's ticcmd to edit. + + Return:- + None +--------------------------------------------------*/ +static void K_BotItemRouletteMash(player_t *player, ticcmd_t *cmd) +{ + boolean mash = false; + + if (player->pflags & PF_ATTACKDOWN) + { + return; + } + + if (player->kartstuff[k_rings] < 0 && cv_superring.value) + { + // Uh oh, we need a loan! + // It'll be better in the long run for bots to lose an item set for 10 free rings. + mash = true; + } + + // TODO: Mash based on how far behind you are, when items are + // almost garantueed to be in your favor. + + if (mash == true) + { + cmd->buttons |= BT_ATTACK; + } +} + +/*-------------------------------------------------- + void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) + + See header file for description. +--------------------------------------------------*/ +void K_BotItemUsage(player_t *player, ticcmd_t *cmd, INT16 turnamt) +{ + if (player->kartstuff[k_userings] == 1) + { + // Use rings! + + if (!player->exiting) + { + K_BotItemRings(player, cmd); + } + } + else + { + if (player->botvars.itemdelay) + { + player->botvars.itemdelay--; + player->botvars.itemconfirm = 0; + return; + } + + if (player->kartstuff[k_itemroulette]) + { + // Mashing behaviors + K_BotItemRouletteMash(player, cmd); + return; + } + + if (player->kartstuff[k_stealingtimer] == 0 && player->kartstuff[k_stolentimer] == 0) + { + if (player->kartstuff[k_eggmanexplode]) + { + K_BotItemEggmanExplosion(player, cmd); + } + else if (player->kartstuff[k_eggmanheld]) + { + K_BotItemEggman(player, cmd); + } + else if (player->kartstuff[k_rocketsneakertimer] > 0) + { + K_BotItemRocketSneaker(player, cmd); + } + else + { + switch (player->kartstuff[k_itemtype]) + { + default: + if (player->kartstuff[k_itemtype] != KITEM_NONE) + { + K_BotItemGenericTap(player, cmd); + } + + player->botvars.itemconfirm = 0; + break; + case KITEM_INVINCIBILITY: + case KITEM_SPB: + case KITEM_GROW: + case KITEM_SHRINK: + case KITEM_HYUDORO: + case KITEM_SUPERRING: + K_BotItemGenericTap(player, cmd); + break; + case KITEM_ROCKETSNEAKER: + if (player->kartstuff[k_rocketsneakertimer] <= 0) + { + K_BotItemGenericTap(player, cmd); + } + break; + case KITEM_SNEAKER: + K_BotItemSneaker(player, cmd); + break; + case KITEM_BANANA: + if (!player->kartstuff[k_itemheld]) + { + K_BotItemGenericTrapShield(player, cmd, turnamt, false); + } + else + { + K_BotItemBanana(player, cmd, turnamt); + } + break; + case KITEM_EGGMAN: + K_BotItemEggmanShield(player, cmd); + break; + case KITEM_ORBINAUT: + if (!player->kartstuff[k_itemheld]) + { + K_BotItemGenericOrbitShield(player, cmd); + } + else if (player->kartstuff[k_position] != 1) // Hold onto orbiting items when in 1st :) + /* FALL-THRU */ + case KITEM_BALLHOG: + { + K_BotItemOrbinaut(player, cmd); + } + break; + case KITEM_JAWZ: + if (!player->kartstuff[k_itemheld]) + { + K_BotItemGenericOrbitShield(player, cmd); + } + else if (player->kartstuff[k_position] != 1) // Hold onto orbiting items when in 1st :) + { + K_BotItemJawz(player, cmd); + } + break; + case KITEM_MINE: + if (!player->kartstuff[k_itemheld]) + { + K_BotItemGenericTrapShield(player, cmd, turnamt, true); + } + else + { + K_BotItemMine(player, cmd, turnamt); + } + break; + case KITEM_THUNDERSHIELD: + K_BotItemThunder(player, cmd); + break; + case KITEM_BUBBLESHIELD: + K_BotItemBubble(player, cmd); + break; + case KITEM_FLAMESHIELD: + K_BotItemFlame(player, cmd); + break; + } + } + } + } +} diff --git a/src/k_botsearch.c b/src/k_botsearch.c new file mode 100644 index 000000000..28bef819e --- /dev/null +++ b/src/k_botsearch.c @@ -0,0 +1,749 @@ +// SONIC ROBO BLAST 2 KART +//----------------------------------------------------------------------------- +// Copyright (C) 2018-2020 by Kart Krew +// +// This program is free software distributed under the +// terms of the GNU General Public License, version 2. +// See the 'LICENSE' file for more details. +//----------------------------------------------------------------------------- +/// \file k_botsearch.c +/// \brief Bot blockmap search functions + +#include "doomdef.h" +#include "d_player.h" +#include "g_game.h" +#include "r_main.h" +#include "p_local.h" +#include "k_bot.h" +#include "lua_hook.h" +#include "byteptr.h" +#include "d_net.h" // nodetoplayer +#include "k_kart.h" +#include "z_zone.h" +#include "i_system.h" +#include "p_maputl.h" +#include "d_ticcmd.h" +#include "m_random.h" +#include "r_things.h" // numskins + +struct globalsmuggle +{ + mobj_t *botmo; + fixed_t distancetocheck; + + fixed_t closestlinedist; + + INT16 curturn; + INT16 steer; + + fixed_t eggboxx, eggboxy; + UINT8 randomitems; + UINT8 eggboxes; +} globalsmuggle; + +/*-------------------------------------------------- + static boolean K_FindEggboxes(mobj_t *thing) + + Blockmap search function. + Increments the random items and egg boxes counters. + + Input Arguments:- + thing - Object passed in from iteration. + + Return:- + true continues searching, false ends the search early. +--------------------------------------------------*/ +static boolean K_FindEggboxes(mobj_t *thing) +{ + fixed_t dist; + + if (thing->type != MT_RANDOMITEM && thing->type != MT_EGGMANITEM) + { + return true; + } + + if (!thing->health) + { + return true; + } + + dist = P_AproxDistance(thing->x - globalsmuggle.eggboxx, thing->y - globalsmuggle.eggboxy); + + if (dist > globalsmuggle.distancetocheck) + { + return true; + } + + if (thing->type == MT_RANDOMITEM) + { + globalsmuggle.randomitems++; + } + else + { + globalsmuggle.eggboxes++; + } + + return true; +} + +/*-------------------------------------------------- + UINT8 K_EggboxStealth(fixed_t x, fixed_t y) + + See header file for description. +--------------------------------------------------*/ +UINT8 K_EggboxStealth(fixed_t x, fixed_t y) +{ + INT32 xl, xh, yl, yh, bx, by; + + memset(&globalsmuggle, 0, sizeof (struct globalsmuggle)); + globalsmuggle.eggboxx = x; + globalsmuggle.eggboxy = y; + globalsmuggle.distancetocheck = (mapobjectscale * 256); + globalsmuggle.randomitems = 0; + globalsmuggle.eggboxes = 0; + + xl = (unsigned)(globalsmuggle.eggboxx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(globalsmuggle.eggboxx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(globalsmuggle.eggboxy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(globalsmuggle.eggboxy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + + BMBOUNDFIX(xl, xh, yl, yh); + + for (bx = xl; bx <= xh; bx++) + { + for (by = yl; by <= yh; by++) + { + P_BlockThingsIterator(bx, by, K_FindEggboxes); + } + } + + return (globalsmuggle.randomitems * globalsmuggle.eggboxes); +} + +/*-------------------------------------------------- + static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec) + + Tells us if a bot will play more careful around + this sector's special type. + + Input Arguments:- + player - Player to check against. + sec - Sector to check the specials of. + + Return:- + true if avoiding this sector special, false otherwise. +--------------------------------------------------*/ +static boolean K_BotHatesThisSectorsSpecial(player_t *player, sector_t *sec) +{ + switch (GETSECSPECIAL(sec->special, 1)) + { + case 1: // Damage + case 5: // Spikes + case 6: case 7: // Death Pit + case 8: // Instant Kill + return true; + //case 2: case 3: // Offroad (let's let them lawnmower) + case 4: // Offroad (Strong) + if (!K_BotCanTakeCut(player)) + { + return true; + } + break; + default: + break; + } + + return false; +} + +/*-------------------------------------------------- + static boolean K_BotHatesThisSector(player_t *player, sector_t *sec) + + Tells us if a bot will play more careful around + this sector. + + Input Arguments:- + player - Player to check against. + sec - Sector to check against. + + Return:- + true if avoiding this sector, false otherwise. +--------------------------------------------------*/ +static boolean K_BotHatesThisSector(player_t *player, sector_t *sec) +{ + const boolean flip = (player->mo->eflags & MFE_VERTICALFLIP); + INT32 flag; + ffloor_t *rover; + + if (flip) + { + flag = SF_FLIPSPECIAL_CEILING; + } + else + { + flag = SF_FLIPSPECIAL_FLOOR; + } + + if (sec->flags & flag) + { + if (K_BotHatesThisSectorsSpecial(player, sec)) + { + return true; + } + } + + for (rover = sec->ffloors; rover; rover = rover->next) + { + if (!(rover->flags & FF_EXISTS)) + { + continue; + } + + if (!(rover->master->frontsector->flags & flag)) + { + continue; + } + + if (((*rover->bottomheight >= player->mo->z + player->mo->height) && (flip)) + || ((*rover->topheight <= player->mo->z) && (!flip))) + { + if (K_BotHatesThisSectorsSpecial(player, sec)) + { + return true; + } + } + } + + return false; +} + +/*-------------------------------------------------- + static boolean K_FindBlockingWalls(line_t *line) + + Blockmap search function. + Reels the bot prediction back in based on solid walls + or other obstacles surrounding the bot. + + Input Arguments:- + line - Linedef passed in from iteration. + + Return:- + true continues searching, false ends the search early. +--------------------------------------------------*/ +static boolean K_FindBlockingWalls(line_t *line) +{ + // Condensed version of PIT_CheckLine + const fixed_t maxstepmove = FixedMul(MAXSTEPMOVE, mapobjectscale); + fixed_t maxstep = maxstepmove; + fixed_t linedist = INT32_MAX; + INT32 lineside = 0; + + if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player) + { + return false; + } + + if (line->polyobj && !(line->polyobj->flags & POF_SOLID)) + { + return true; + } + + if (tmbbox[BOXRIGHT] <= line->bbox[BOXLEFT] || tmbbox[BOXLEFT] >= line->bbox[BOXRIGHT] + || tmbbox[BOXTOP] <= line->bbox[BOXBOTTOM] || tmbbox[BOXBOTTOM] >= line->bbox[BOXTOP]) + { + return true; + } + + if (P_BoxOnLineSide(tmbbox, line) != -1) + { + return true; + } + + lineside = P_PointOnLineSide(globalsmuggle.botmo->x, globalsmuggle.botmo->y, line); + + // one sided line + if (!line->backsector) + { + if (lineside) + { + // don't hit the back side + return true; + } + + goto blocked; + } + + if ((line->flags & ML_IMPASSABLE) || (line->flags & ML_BLOCKPLAYERS)) + { + goto blocked; + } + + // set openrange, opentop, openbottom + P_LineOpening(line, globalsmuggle.botmo); + + if (globalsmuggle.botmo->player->kartstuff[k_waterskip]) + maxstep += maxstepmove; + + if (P_MobjTouchingSectorSpecial(globalsmuggle.botmo, 1, 13, false)) + maxstep <<= 1; + else if (P_MobjTouchingSectorSpecial(globalsmuggle.botmo, 1, 12, false)) + maxstep = 0; + + if ((openrange < globalsmuggle.botmo->height) // doesn't fit + || (opentop - globalsmuggle.botmo->z < globalsmuggle.botmo->height) // mobj is too high + || (openbottom - globalsmuggle.botmo->z > maxstep)) // too big a step up + { + goto blocked; + } + + if (!K_BotHatesThisSector(globalsmuggle.botmo->player, globalsmuggle.botmo->subsector->sector)) + { + // Treat damage sectors like walls + + if (lineside) + { + if (K_BotHatesThisSector(globalsmuggle.botmo->player, line->frontsector)) + goto blocked; + } + else + { + if (K_BotHatesThisSector(globalsmuggle.botmo->player, line->backsector)) + goto blocked; + } + } + + // We weren't blocked! + return true; + +blocked: + linedist = K_DistanceOfLineFromPoint(line->v1->x, line->v1->y, line->v2->x, line->v2->y, globalsmuggle.botmo->x, globalsmuggle.botmo->y); + linedist -= (globalsmuggle.botmo->radius * 8); // Maintain a reasonable distance away from it + + if (linedist > globalsmuggle.distancetocheck) + { + return true; + } + + if (linedist <= 0) + { + globalsmuggle.closestlinedist = 0; + return false; + } + + if (linedist < globalsmuggle.closestlinedist) + { + globalsmuggle.closestlinedist = linedist; + } + + return true; +} + +/*-------------------------------------------------- + fixed_t K_BotReducePrediction(player_t *player) + + See header file for description. +--------------------------------------------------*/ +fixed_t K_BotReducePrediction(player_t *player) +{ + INT32 xl, xh, yl, yh, bx, by; + + memset(&globalsmuggle, 0, sizeof (struct globalsmuggle)); + globalsmuggle.botmo = player->mo; + globalsmuggle.distancetocheck = (player->mo->radius * 8) + (player->speed * 4); + globalsmuggle.closestlinedist = INT32_MAX; + + tmx = player->mo->x; + tmy = player->mo->y; + + xl = (unsigned)(tmx - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(tmx + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(tmy - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(tmy + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + + BMBOUNDFIX(xl, xh, yl, yh); + + tmbbox[BOXTOP] = tmy + globalsmuggle.distancetocheck; + tmbbox[BOXBOTTOM] = tmy - globalsmuggle.distancetocheck; + tmbbox[BOXRIGHT] = tmx + globalsmuggle.distancetocheck; + tmbbox[BOXLEFT] = tmx - globalsmuggle.distancetocheck; + + // Check for lines that the bot might collide with + for (bx = xl; bx <= xh; bx++) + { + for (by = yl; by <= yh; by++) + { + P_BlockLinesIterator(bx, by, K_FindBlockingWalls); + } + } + + if (globalsmuggle.closestlinedist == INT32_MAX) + { + return FRACUNIT; + } + + return FixedDiv(globalsmuggle.closestlinedist, globalsmuggle.distancetocheck); +} + +/*-------------------------------------------------- + static void K_SteerFromObject(mobj_t *bot, mobj_t *thing, fixed_t fulldist, fixed_t xdist, boolean towards, INT16 amount) + + Handles steering away/towards the specified object. + + Input Arguments:- + bot - Bot's mobj. + thing - Mobj to steer towards/away from. + fulldist - Distance away from object. + xdist - Horizontal distance away from object. + towards - If true, steer towards the object. Otherwise, steer away. + amount - How hard to turn. + + Return:- + None +--------------------------------------------------*/ +static void K_SteerFromObject(mobj_t *bot, mobj_t *thing, fixed_t fulldist, fixed_t xdist, boolean towards, INT16 amount) +{ + angle_t destangle = R_PointToAngle2(bot->x, bot->y, thing->x, thing->y); + angle_t angle; + SINT8 flip = 1; + + amount = (amount * FixedDiv(globalsmuggle.distancetocheck - fulldist, globalsmuggle.distancetocheck)) / FRACUNIT; + + if (amount == 0) + { + // Shouldn't happen + return; + } + + if (towards) + { + if (xdist < FixedHypot(bot->radius, thing->radius)) + { + // Don't need to turn any harder! + + if (abs(globalsmuggle.steer) <= amount) + { + globalsmuggle.steer = 0; + } + else + { + if (globalsmuggle.steer > 0) + { + globalsmuggle.steer -= amount; + } + else if (globalsmuggle.steer < 0) + { + globalsmuggle.steer += amount; + } + } + + return; + } + + // Still turning towards it, flip. + flip = -flip; + } + + angle = (bot->angle - destangle); + if (angle < ANGLE_180) + { + flip = -flip; + } + + // If going in the opposite direction of where you wanted to turn, + // then reduce the amount that you can turn in that direction. + if ((flip == 1 && globalsmuggle.curturn < 0) + || (flip == -1 && globalsmuggle.curturn > 0)) + { + amount /= 4; + } + + globalsmuggle.steer += amount * flip; +} + +/*-------------------------------------------------- + static boolean K_BotSteerObjects(mobj_t *thing) + + Blockmap search function. + Finds objects around the bot to steer towards/away from. + + Input Arguments:- + thing - Object passed in from iteration. + + Return:- + true continues searching, false ends the search early. +--------------------------------------------------*/ +static boolean K_BotSteerObjects(mobj_t *thing) +{ + INT16 anglediff; + fixed_t xdist, ydist, fulldist; + angle_t destangle, angle; + INT16 attack = ((9 - globalsmuggle.botmo->player->kartspeed) * KART_FULLTURN) / 8; // Acceleration chars are more aggressive + INT16 dodge = ((9 - globalsmuggle.botmo->player->kartweight) * KART_FULLTURN) / 8; // Handling chars dodge better + + if (!globalsmuggle.botmo || P_MobjWasRemoved(globalsmuggle.botmo) || !globalsmuggle.botmo->player) + { + return false; + } + + if (!thing->health) + { + return true; + } + + if (globalsmuggle.botmo == thing) + { + return true; + } + + xdist = K_DistanceOfLineFromPoint( + globalsmuggle.botmo->x, globalsmuggle.botmo->y, + globalsmuggle.botmo->x + FINECOSINE(globalsmuggle.botmo->angle >> ANGLETOFINESHIFT), globalsmuggle.botmo->y + FINESINE(globalsmuggle.botmo->angle >> ANGLETOFINESHIFT), + thing->x, thing->y + ) / 2; // weight x dist more heavily than y dist + + ydist = K_DistanceOfLineFromPoint( + globalsmuggle.botmo->x, globalsmuggle.botmo->y, + globalsmuggle.botmo->x + FINECOSINE((globalsmuggle.botmo->angle + ANGLE_90) >> ANGLETOFINESHIFT), globalsmuggle.botmo->y + FINESINE((globalsmuggle.botmo->angle + ANGLE_90) >> ANGLETOFINESHIFT), + thing->x, thing->y + ); + + fulldist = FixedHypot(xdist, ydist); + + if (fulldist > globalsmuggle.distancetocheck) + { + return true; + } + + if (!P_CheckSight(globalsmuggle.botmo, thing)) + { + return true; + } + + destangle = R_PointToAngle2(globalsmuggle.botmo->x, globalsmuggle.botmo->y, thing->x, thing->y); + angle = (globalsmuggle.botmo->angle - destangle); + + if (angle < ANGLE_180) + { + anglediff = AngleFixed(angle)>>FRACBITS; + } + else + { + anglediff = 360-(AngleFixed(angle)>>FRACBITS); + } + + anglediff = abs(anglediff); + +#define PlayerAttackSteer(botcond, thingcond) \ + if ((botcond) && !(thingcond)) \ + { \ + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, 2 * (KART_FULLTURN + attack)); \ + } \ + else if ((thingcond) && !(botcond)) \ + { \ + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); \ + } + + switch (thing->type) + { + case MT_BANANA: + case MT_BANANA_SHIELD: + case MT_EGGMANITEM_SHIELD: + case MT_ORBINAUT: + case MT_ORBINAUT_SHIELD: + case MT_JAWZ: + case MT_JAWZ_DUD: + case MT_JAWZ_SHIELD: + case MT_SSMINE: + case MT_SSMINE_SHIELD: + case MT_BALLHOG: + case MT_SPB: + case MT_BUBBLESHIELDTRAP: + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); + break; + case MT_RANDOMITEM: + if (anglediff >= 60) + { + break; + } + + if (P_CanPickupItem(globalsmuggle.botmo->player, 1)) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, KART_FULLTURN + attack); + } + break; + case MT_EGGMANITEM: + if (anglediff >= 60) + { + break; + } + + if (P_CanPickupItem(globalsmuggle.botmo->player, 1)) // Can pick up an actual item + { + const UINT8 stealth = K_EggboxStealth(thing->x, thing->y); + const UINT8 requiredstealth = (globalsmuggle.botmo->player->botvars.difficulty * globalsmuggle.botmo->player->botvars.difficulty); + + if (stealth >= requiredstealth) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, 2 * (KART_FULLTURN + attack)); + } + else + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); + } + } + break; + case MT_FLOATINGITEM: + if (anglediff >= 60) + { + break; + } + + if (P_CanPickupItem(globalsmuggle.botmo->player, 3)) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, KART_FULLTURN + attack); + } + break; + case MT_RING: + case MT_FLINGRING: + if (anglediff >= 60) + { + break; + } + + if ((RINGTOTAL(globalsmuggle.botmo->player) < 20 && !globalsmuggle.botmo->player->kartstuff[k_ringlock] + && P_CanPickupItem(globalsmuggle.botmo->player, 0)) + && !thing->extravalue1 + && (globalsmuggle.botmo->player->kartstuff[k_itemtype] != KITEM_THUNDERSHIELD)) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, + (RINGTOTAL(globalsmuggle.botmo->player) < 3 + ? (4 * (KART_FULLTURN + attack)) + : (KART_FULLTURN + attack)) + ); + } + break; + case MT_PLAYER: + if (thing->player + && !thing->player->kartstuff[k_hyudorotimer] + && !globalsmuggle.botmo->player->kartstuff[k_hyudorotimer]) + { + // There REALLY ought to be a better way to handle this logic, right?! + // Squishing + PlayerAttackSteer( + globalsmuggle.botmo->scale > thing->scale + (mapobjectscale/8), + thing->scale > globalsmuggle.botmo->scale + (mapobjectscale/8) + ) + // Invincibility + else PlayerAttackSteer( + globalsmuggle.botmo->player->kartstuff[k_invincibilitytimer], + thing->player->kartstuff[k_invincibilitytimer] + ) + // Thunder Shield + else PlayerAttackSteer( + globalsmuggle.botmo->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD, + thing->player->kartstuff[k_itemtype] == KITEM_THUNDERSHIELD + ) + // Bubble Shield + else PlayerAttackSteer( + globalsmuggle.botmo->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD, + thing->player->kartstuff[k_itemtype] == KITEM_BUBBLESHIELD + ) + // Flame Shield + else PlayerAttackSteer( + globalsmuggle.botmo->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD, + thing->player->kartstuff[k_itemtype] == KITEM_FLAMESHIELD + ) + // Has held item shield + else PlayerAttackSteer( + (globalsmuggle.botmo->player->kartstuff[k_itemheld] || globalsmuggle.botmo->player->kartstuff[k_eggmanheld]), + (thing->player->kartstuff[k_itemheld] || thing->player->kartstuff[k_eggmanheld]) + ) + // Ring Sting + else PlayerAttackSteer( + thing->player->kartstuff[k_rings] <= 0, + globalsmuggle.botmo->player->kartstuff[k_rings] <= 0 + ) + else + { + // After ALL of that, we can do standard bumping + fixed_t ourweight = K_GetMobjWeight(globalsmuggle.botmo, thing); + fixed_t theirweight = K_GetMobjWeight(thing, globalsmuggle.botmo); + fixed_t weightdiff = 0; + + if (anglediff >= 90) + { + weightdiff = theirweight - ourweight; + } + else + { + weightdiff = ourweight - theirweight; + } + + if (weightdiff > mapobjectscale) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, KART_FULLTURN + attack); + } + else + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, false, KART_FULLTURN + dodge); + } + } + } + break; + case MT_BOTHINT: + if (anglediff >= 60) + { + break; + } + + if (thing->extravalue1 == 0) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, false, thing->extravalue2 * (KART_FULLTURN + dodge)); + } + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, true, thing->extravalue2 * (KART_FULLTURN + attack)); + } + break; + default: + if (thing->flags & (MF_SOLID|MF_ENEMY|MF_BOSS|MF_PAIN|MF_MISSILE|MF_FIRE)) + { + K_SteerFromObject(globalsmuggle.botmo, thing, fulldist, xdist, false, 2 * (KART_FULLTURN + dodge)); + } + break; + } + + return true; +} + +/*-------------------------------------------------- + INT16 K_BotFindObjects(player_t *player, INT16 turn) + + See header file for description. +--------------------------------------------------*/ +INT16 K_BotFindObjects(player_t *player, INT16 turn) +{ + INT32 xl, xh, yl, yh, bx, by; + + memset(&globalsmuggle, 0, sizeof (struct globalsmuggle)); + globalsmuggle.steer = 0; + globalsmuggle.botmo = player->mo; + globalsmuggle.curturn = turn; + globalsmuggle.distancetocheck = 2048*mapobjectscale; + + xl = (unsigned)(globalsmuggle.botmo->x - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; + xh = (unsigned)(globalsmuggle.botmo->x + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; + yl = (unsigned)(globalsmuggle.botmo->y - globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + yh = (unsigned)(globalsmuggle.botmo->y + globalsmuggle.distancetocheck - bmaporgy)>>MAPBLOCKSHIFT; + + BMBOUNDFIX(xl, xh, yl, yh); + + for (bx = xl; bx <= xh; bx++) + { + for (by = yl; by <= yh; by++) + { + P_BlockThingsIterator(bx, by, K_BotSteerObjects); + } + } + + return globalsmuggle.steer; +} From dbc30da69ff8284309e7444f6423a82acdf31d47 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 15:55:10 -0400 Subject: [PATCH 31/34] Dial back the bot steering changes a bit --- src/k_bot.c | 40 +++++++++------------------------------- src/k_bot.h | 2 +- src/k_botsearch.c | 7 ++----- 3 files changed, 12 insertions(+), 37 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index 927fc357a..01767054f 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -395,13 +395,11 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) const INT16 handling = K_GetKartTurnValue(player, KART_FULLTURN); // Reduce prediction based on how fast you can turn const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to - const fixed_t topspeed = K_GetKartSpeed(player, false); - const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy) + (topspeed / 4); - const fixed_t distreduce = K_BotReducePrediction(player); fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT); const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict + const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy); const INT32 distance = (FixedMul(speed, distreduce) / FRACUNIT) * futuresight; botprediction_t *predict = Z_Calloc(sizeof(botprediction_t), PU_LEVEL, NULL); @@ -418,12 +416,6 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) // This prevents looking too far ahead if the closest waypoint is really far away. distanceleft -= P_AproxDistance(player->mo->x - wp->mobj->x, player->mo->y - wp->mobj->y) / FRACUNIT; - if (speed > topspeed) - { - // Play more in the center when going fast. - radreduce = FixedDiv(radreduce, speed / topspeed); - } - // We don't want to look ahead at all, just go to the first waypoint. if (distanceleft <= 0) { @@ -495,8 +487,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) } } } - - // Save angle for the next loop's oldangle + angletonext = R_PointToAngle2( wp->mobj->x, wp->mobj->y, wp->nextwaypoints[nwp]->mobj->x, wp->nextwaypoints[nwp]->mobj->y @@ -651,13 +642,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) // Full speed ahead! cmd->forwardmove = 50; - if (anglediff > 60) - { - // Actually, don't go too fast... - cmd->forwardmove /= 2; - cmd->buttons |= BT_BRAKE; - } - if (dirdist <= rad) { fixed_t speedmul = FixedMul(player->speed, K_GetKartSpeed(player, false)); @@ -690,7 +674,13 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) } } - if (anglediff < 60) + if (anglediff > 60) + { + // Actually, don't go too fast... + cmd->forwardmove /= 2; + cmd->buttons |= BT_BRAKE; + } + else if (dirdist <= realrad) { // Steer towards/away from objects! turnamt += K_BotFindObjects(player, turnamt); @@ -714,12 +704,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) if (turnamt > 0) { - if (player->botvars.turnconfirm < 0) - { - // Reset turn confirm - player->botvars.turnconfirm = 0; - } - if (player->botvars.turnconfirm < BOTTURNCONFIRM) { player->botvars.turnconfirm++; @@ -727,12 +711,6 @@ void K_BuildBotTiccmd(player_t *player, ticcmd_t *cmd) } else if (turnamt < 0) { - if (player->botvars.turnconfirm > 0) - { - // Reset turn confirm - player->botvars.turnconfirm = 0; - } - if (player->botvars.turnconfirm > -BOTTURNCONFIRM) { player->botvars.turnconfirm--; diff --git a/src/k_bot.h b/src/k_bot.h index 81257ecbf..bbd2dedcd 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -20,7 +20,7 @@ // How many tics in a row do you need to turn in this direction before we'll let you turn. // Made it as small as possible without making it look like the bots are twitching constantly. -#define BOTTURNCONFIRM 7 +#define BOTTURNCONFIRM 4 // Point for bots to aim for typedef struct botprediction_s { diff --git a/src/k_botsearch.c b/src/k_botsearch.c index 28bef819e..2a95da738 100644 --- a/src/k_botsearch.c +++ b/src/k_botsearch.c @@ -95,7 +95,6 @@ UINT8 K_EggboxStealth(fixed_t x, fixed_t y) { INT32 xl, xh, yl, yh, bx, by; - memset(&globalsmuggle, 0, sizeof (struct globalsmuggle)); globalsmuggle.eggboxx = x; globalsmuggle.eggboxy = y; globalsmuggle.distancetocheck = (mapobjectscale * 256); @@ -347,9 +346,8 @@ fixed_t K_BotReducePrediction(player_t *player) { INT32 xl, xh, yl, yh, bx, by; - memset(&globalsmuggle, 0, sizeof (struct globalsmuggle)); globalsmuggle.botmo = player->mo; - globalsmuggle.distancetocheck = (player->mo->radius * 8) + (player->speed * 4); + globalsmuggle.distancetocheck = (player->mo->radius * 16); globalsmuggle.closestlinedist = INT32_MAX; tmx = player->mo->x; @@ -724,11 +722,10 @@ INT16 K_BotFindObjects(player_t *player, INT16 turn) { INT32 xl, xh, yl, yh, bx, by; - memset(&globalsmuggle, 0, sizeof (struct globalsmuggle)); globalsmuggle.steer = 0; globalsmuggle.botmo = player->mo; globalsmuggle.curturn = turn; - globalsmuggle.distancetocheck = 2048*mapobjectscale; + globalsmuggle.distancetocheck = (player->mo->radius * 32) + (player->speed * 4); xl = (unsigned)(globalsmuggle.botmo->x - globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; xh = (unsigned)(globalsmuggle.botmo->x + globalsmuggle.distancetocheck - bmaporgx)>>MAPBLOCKSHIFT; From 597baf212b0381beb452f38c43421347634868ec Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 15:55:26 -0400 Subject: [PATCH 32/34] Allow rubberbanding up to exiting players --- src/k_bot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/k_bot.c b/src/k_bot.c index 01767054f..541acd78f 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -302,7 +302,7 @@ fixed_t K_BotRubberband(player_t *player) for (i = 0; i < MAXPLAYERS; i++) { - if (!playeringame[i] || players[i].spectator || players[i].exiting) + if (!playeringame[i] || players[i].spectator) { continue; } From 5d77807a78bd3915c5583db8db4f0da6d83969d3 Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 16:16:01 -0400 Subject: [PATCH 33/34] const radreduce, removed unused "dir" property --- src/k_bot.c | 2 +- src/k_bot.h | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/k_bot.c b/src/k_bot.c index 541acd78f..4405bee44 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -396,7 +396,7 @@ static botprediction_t *K_CreateBotPrediction(player_t *player) const INT16 normal = KART_FULLTURN; // "Standard" handling to compare to const fixed_t distreduce = K_BotReducePrediction(player); - fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT); + const fixed_t radreduce = min(distreduce + FRACUNIT/4, FRACUNIT); const tic_t futuresight = (TICRATE * normal) / max(1, handling); // How far ahead into the future to try and predict const fixed_t speed = P_AproxDistance(player->mo->momx, player->mo->momy); diff --git a/src/k_bot.h b/src/k_bot.h index bbd2dedcd..48756e2c8 100644 --- a/src/k_bot.h +++ b/src/k_bot.h @@ -26,7 +26,6 @@ typedef struct botprediction_s { fixed_t x, y; fixed_t radius; - angle_t dir; } botprediction_t; From 4916516e2e5d6fa4b067799c8c9bbf33c0ffe6cb Mon Sep 17 00:00:00 2001 From: Sally Coolatta Date: Sun, 24 May 2020 17:12:58 -0400 Subject: [PATCH 34/34] Prevent duplicate skins, fix bots not being able to be disabled, change default to "off" --- src/d_netcmd.c | 13 +++++-- src/k_bot.c | 98 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 81 insertions(+), 30 deletions(-) diff --git a/src/d_netcmd.c b/src/d_netcmd.c index fe931a70f..18c9db93b 100644 --- a/src/d_netcmd.c +++ b/src/d_netcmd.c @@ -393,12 +393,19 @@ static CV_PossibleValue_t kartvoices_cons_t[] = {{0, "Never"}, {1, "Tasteful"}, consvar_t cv_kartvoices = {"kartvoices", "Tasteful", CV_SAVE, kartvoices_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; static CV_PossibleValue_t kartbot_cons_t[] = { - {1, "MIN"}, - {9, "MAX"}, {0, "Off"}, + {1, "Lv.1"}, + {2, "Lv.2"}, + {3, "Lv.3"}, + {4, "Lv.4"}, + {5, "Lv.5"}, + {6, "Lv.6"}, + {7, "Lv.7"}, + {8, "Lv.8"}, + {9, "Lv.9"}, {0, NULL} }; -consvar_t cv_kartbot = {"kartbot", "5", CV_NETVAR|CV_CHEAT, kartbot_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; +consvar_t cv_kartbot = {"kartbot", "0", CV_NETVAR|CV_CHEAT, kartbot_cons_t, NULL, 0, NULL, NULL, 0, 0, NULL}; consvar_t cv_karteliminatelast = {"karteliminatelast", "Yes", CV_NETVAR|CV_CHEAT|CV_CALL|CV_NOSHOWHELP, CV_YesNo, KartEliminateLast_OnChange, 0, NULL, NULL, 0, 0, NULL}; diff --git a/src/k_bot.c b/src/k_bot.c index 4405bee44..3103facdb 100644 --- a/src/k_bot.c +++ b/src/k_bot.c @@ -111,6 +111,7 @@ void K_UpdateMatchRaceBots(void) UINT8 numbots = 0; UINT8 numwaiting = 0; SINT8 wantedbots = 0; + boolean skinusable[MAXSKINS]; UINT8 i; if (!server) @@ -118,38 +119,57 @@ void K_UpdateMatchRaceBots(void) return; } - if (difficulty != 0) + // init usable bot skins list + for (i = 0; i < MAXSKINS; i++) { - if (cv_ingamecap.value > 0) + if (i < numskins) { - pmax = min(pmax, cv_ingamecap.value); + skinusable[i] = true; } - - for (i = 0; i < MAXPLAYERS; i++) + else { - if (playeringame[i]) - { - if (!players[i].spectator) - { - if (players[i].bot) - { - numbots++; + skinusable[i] = false; + } + } - // While we're here, we should update bot difficulty to the proper value. - players[i].botvars.difficulty = difficulty; - } - else - { - numplayers++; - } - } - else if (players[i].pflags & PF_WANTSTOJOIN) + if (cv_ingamecap.value > 0) + { + pmax = min(pmax, cv_ingamecap.value); + } + + for (i = 0; i < MAXPLAYERS; i++) + { + if (playeringame[i]) + { + if (!players[i].spectator) + { + skinusable[players[i].skin] = false; + + if (players[i].bot) { - numwaiting++; + numbots++; + + // While we're here, we should update bot difficulty to the proper value. + players[i].botvars.difficulty = difficulty; + } + else + { + numplayers++; } } + else if (players[i].pflags & PF_WANTSTOJOIN) + { + numwaiting++; + } } + } + if (difficulty == 0) + { + wantedbots = 0; + } + else + { wantedbots = pmax - numplayers - numwaiting; if (wantedbots < 0) @@ -157,15 +177,12 @@ void K_UpdateMatchRaceBots(void) wantedbots = 0; } } - else - { - wantedbots = 0; - } if (numbots < wantedbots) { // We require MORE bots! UINT8 newplayernum = 0; + boolean usedallskins = false; if (dedicated) { @@ -174,12 +191,39 @@ void K_UpdateMatchRaceBots(void) while (numbots < wantedbots) { - if (!K_AddBot(M_RandomKey(numskins), difficulty, &newplayernum)) + UINT8 skin = M_RandomKey(numskins); + + if (usedallskins == false) + { + UINT8 loops = 0; + + while (!skinusable[skin]) + { + if (loops >= numskins) + { + // no more skins, stick to our first choice + usedallskins = true; + break; + } + + skin++; + + if (skin >= numskins) + { + skin = 0; + } + + loops++; + } + } + + if (!K_AddBot(skin, difficulty, &newplayernum)) { // Not enough player slots to add the bot, break the loop. break; } + skinusable[skin] = false; numbots++; } }