Merge branch 'master' of https://git.magicalgirl.moe/STJr/SRB2Internal.git into eggcolosseum

# Conflicts:
#	src/p_mobj.c
#	src/sounds.c
#	src/sounds.h
This commit is contained in:
toaster 2019-07-09 19:52:52 +01:00
commit 2df90888bb
31 changed files with 1768 additions and 913 deletions

View File

@ -196,6 +196,7 @@ typedef enum
SH_PITY = 1, // the world's most basic shield ever, given to players who suck at Match
SH_WHIRLWIND,
SH_ARMAGEDDON,
SH_PINK, // PITY IN PINK!
// Normal shields that use flags
SH_ATTRACT = SH_PITY|SH_PROTECTELECTRIC,

View File

@ -28,6 +28,7 @@
#include "p_local.h" // for var1 and var2, and some constants
#include "p_setup.h"
#include "r_data.h"
#include "r_draw.h"
#include "r_sky.h"
#include "fastcmp.h"
#include "lua_script.h"
@ -5136,7 +5137,10 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_METALSONIC_BADBOUNCE",
"S_METALSONIC_SHOOT",
"S_METALSONIC_PAIN",
"S_METALSONIC_DEATH",
"S_METALSONIC_DEATH1",
"S_METALSONIC_DEATH2",
"S_METALSONIC_DEATH3",
"S_METALSONIC_DEATH4",
"S_METALSONIC_FLEE1",
"S_METALSONIC_FLEE2",
"S_METALSONIC_FLEE3",
@ -6174,6 +6178,12 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_PITY4",
"S_PITY5",
"S_PITY6",
"S_PITY7",
"S_PITY8",
"S_PITY9",
"S_PITY10",
"S_PITY11",
"S_PITY12",
"S_FIRS1",
"S_FIRS2",
@ -6672,6 +6682,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_GOTFLAG",
"S_CORK",
"S_LHRT",
// Red Ring
"S_RRNG1",
@ -7177,6 +7188,7 @@ static const char *const STATE_LIST[] = { // array length left dynamic for sanit
"S_ROCKCRUMBLEN",
"S_ROCKCRUMBLEO",
"S_ROCKCRUMBLEP",
"S_BRICKDEBRIS",
#ifdef SEENAMES
"S_NAMECHECK",
@ -7762,6 +7774,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_MACHINEAMBIENCE",
"MT_CORK",
"MT_LHRT",
// Ring Weapons
"MT_REDRING",
@ -7894,6 +7907,7 @@ static const char *const MOBJTYPE_LIST[] = { // array length left dynamic for s
"MT_ROCKCRUMBLE14",
"MT_ROCKCRUMBLE15",
"MT_ROCKCRUMBLE16",
"MT_BRICKDEBRIS",
#ifdef SEENAMES
"MT_NAMECHECK",
@ -8534,6 +8548,7 @@ struct {
{"SH_PITY",SH_PITY},
{"SH_WHIRLWIND",SH_WHIRLWIND},
{"SH_ARMAGEDDON",SH_ARMAGEDDON},
{"SH_PINK",SH_PINK},
// normal shields that use flags
{"SH_ATTRACT",SH_ATTRACT},
{"SH_ELEMENTAL",SH_ELEMENTAL},
@ -8922,6 +8937,14 @@ struct {
{"KR_TIMEOUT",KR_TIMEOUT},
{"KR_BAN",KR_BAN},
{"KR_LEAVE",KR_LEAVE},
// translation colormaps
{"TC_DEFAULT",TC_DEFAULT},
{"TC_BOSS",TC_BOSS},
{"TC_METALSONIC",TC_METALSONIC},
{"TC_ALLWHITE",TC_ALLWHITE},
{"TC_RAINBOW",TC_RAINBOW},
{"TC_BLINK",TC_BLINK},
#endif
{NULL,0}
@ -9586,11 +9609,6 @@ static inline int lib_getenum(lua_State *L)
lua_pushinteger(L, ((lua_Integer)1<<i));
return 1;
}
if (fastcmp(p, "NETONLY"))
{
lua_pushinteger(L, (lua_Integer)ML_NETONLY);
return 1;
}
if (mathlib) return luaL_error(L, "linedef flag '%s' could not be found.\n", word);
return 0;
}

View File

@ -130,11 +130,9 @@ typedef struct
#define ML_EFFECT4 512
#define ML_EFFECT5 1024
// New ones to disable lines for characters
#define ML_NOSONIC 2048
#define ML_NOTAILS 4096
#define ML_NOKNUX 8192
#define ML_NETONLY 14336 // all of the above
#define ML_NETONLY 2048 // Apply effect only in netgames
#define ML_NONET 4096 // Apply effect only in single player games
#define ML_EFFECT6 8192
// Bounce off walls!
#define ML_BOUNCY 16384

View File

@ -488,6 +488,7 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_GFLG
&lspr[NOLIGHT], // SPR_CORK
&lspr[NOLIGHT], // SPR_LHRT
// Ring Weapons
&lspr[RINGLIGHT_L], // SPR_RRNG
@ -581,6 +582,9 @@ light_t *t_lspr[NUMSPRITES] =
&lspr[NOLIGHT], // SPR_ROIO
&lspr[NOLIGHT], // SPR_ROIP
// Bricks
&lspr[NOLIGHT], // SPR_BRIC
// Gravity Well Objects
&lspr[NOLIGHT], // SPR_GWLG
&lspr[NOLIGHT], // SPR_GWLR

View File

@ -5660,9 +5660,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
vis->z2 = z2;
//Hurdler: 25/04/2000: now support colormap in hardware mode
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
if ((vis->mobj->flags & MF_BOSS) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
if (vis->mobj->type == MT_CYBRAKDEMON)
if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
vis->colormap = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
else if (vis->mobj->type == MT_METALSONIC_BATTLE)
vis->colormap = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
@ -5672,7 +5672,9 @@ static void HWR_ProjectSprite(mobj_t *thing)
else if (thing->color)
{
// New colormap stuff for skins Tails 06-07-2002
if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
if (thing->colorized)
vis->colormap = R_GetTranslationColormap(TC_RAINBOW, thing->color, GTC_CACHE);
else if (thing->skin && thing->sprite == SPR_PLAY) // This thing is a player!
{
size_t skinnum = (skin_t*)thing->skin-skins;
vis->colormap = R_GetTranslationColormap((INT32)skinnum, thing->color, GTC_CACHE);

View File

@ -40,6 +40,8 @@
#include "../w_wad.h"
#include "../z_zone.h"
#include "../r_things.h"
#include "../r_draw.h"
#include "../p_tick.h"
#include "hw_main.h"
#include "../v_video.h"
@ -978,8 +980,18 @@ spritemd2found:
fclose(f);
}
static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, skincolors_t color)
// 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 k_kart.c!)
#define SETBRIGHTNESS(brightness,r,g,b) \
brightness = (UINT8)(((1063*((UINT16)r)/5000) + (3576*((UINT16)g)/5000) + (361*((UINT16)b)/5000)) / 3)
static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, GLMipmap_t *grmip, INT32 skinnum, skincolors_t color)
{
UINT8 i;
UINT16 w = gpatch->width, h = gpatch->height;
UINT32 size = w*h;
RGBA_t *image, *blendimage, *cur, blendcolor;
@ -1005,50 +1017,112 @@ static void HWR_CreateBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch,
image = gpatch->mipmap.grInfo.data;
blendimage = blendgpatch->mipmap.grInfo.data;
// Average all of the translation's colors
if (color == SKINCOLOR_NONE || color >= MAXTRANSLATIONS)
blendcolor = V_GetColor(0xff);
else
blendcolor = V_GetColor(Color_Index[color-1][4]);
while (size--)
{
if (blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
}
else
{
INT32 tempcolor;
INT16 tempmult, tempalpha;
tempalpha = -(abs(blendimage->s.red-127)-127)*2;
if (tempalpha > 255)
tempalpha = 255;
else if (tempalpha < 0)
tempalpha = 0;
const UINT8 div = 6;
const UINT8 start = 4;
UINT32 r, g, b;
tempmult = (blendimage->s.red-127)*2;
if (tempmult > 255)
tempmult = 255;
else if (tempmult < 0)
tempmult = 0;
blendcolor = V_GetColor(Color_Index[color-1][start]);
r = (UINT32)(blendcolor.s.red*blendcolor.s.red);
g = (UINT32)(blendcolor.s.green*blendcolor.s.green);
b = (UINT32)(blendcolor.s.blue*blendcolor.s.blue);
tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
cur->s.red = (UINT8)tempcolor;
tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
cur->s.green = (UINT8)tempcolor;
tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
for (i = 1; i < div; i++)
{
RGBA_t nextcolor = V_GetColor(Color_Index[color-1][start+i]);
r += (UINT32)(nextcolor.s.red*nextcolor.s.red);
g += (UINT32)(nextcolor.s.green*nextcolor.s.green);
b += (UINT32)(nextcolor.s.blue*nextcolor.s.blue);
}
cur++; image++; blendimage++;
blendcolor.s.red = (UINT8)(FixedSqrt((r/div)<<FRACBITS)>>FRACBITS);
blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<<FRACBITS)>>FRACBITS);
blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<<FRACBITS)>>FRACBITS);
}
// rainbow support, could theoretically support boss ones too
if (skinnum == TC_RAINBOW)
{
while (size--)
{
if (image->s.alpha == 0 && blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
}
else
{
UINT32 tempcolor;
UINT16 imagebright, blendbright, finalbright, colorbright;
SETBRIGHTNESS(imagebright,image->s.red,image->s.green,image->s.blue);
SETBRIGHTNESS(blendbright,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
finalbright = (imagebright*(255-blendimage->s.alpha))/255 + (blendbright*blendimage->s.alpha)/255;
SETBRIGHTNESS(colorbright,blendcolor.s.red,blendcolor.s.green,blendcolor.s.blue);
tempcolor = (finalbright*blendcolor.s.red)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.red = (UINT8)tempcolor;
tempcolor = (finalbright*blendcolor.s.green)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.green = (UINT8)tempcolor;
tempcolor = (finalbright*blendcolor.s.blue)/colorbright;
tempcolor = min(255, tempcolor);
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
cur++; image++; blendimage++;
}
}
else
{
while (size--)
{
if (blendimage->s.alpha == 0)
{
// Don't bother with blending the pixel if the alpha of the blend pixel is 0
cur->rgba = image->rgba;
}
else
{
INT32 tempcolor;
INT16 tempmult, tempalpha;
tempalpha = -(abs(blendimage->s.red-127)-127)*2;
if (tempalpha > 255)
tempalpha = 255;
else if (tempalpha < 0)
tempalpha = 0;
tempmult = (blendimage->s.red-127)*2;
if (tempmult > 255)
tempmult = 255;
else if (tempmult < 0)
tempmult = 0;
tempcolor = (image->s.red*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.red)/255)) * blendimage->s.alpha)/255;
cur->s.red = (UINT8)tempcolor;
tempcolor = (image->s.green*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.green)/255)) * blendimage->s.alpha)/255;
cur->s.green = (UINT8)tempcolor;
tempcolor = (image->s.blue*(255-blendimage->s.alpha))/255 + ((tempmult + ((tempalpha*blendcolor.s.blue)/255)) * blendimage->s.alpha)/255;
cur->s.blue = (UINT8)tempcolor;
cur->s.alpha = image->s.alpha;
}
cur++; image++; blendimage++;
}
}
return;
}
static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, const UINT8 *colormap, skincolors_t color)
#undef SETBRIGHTNESS
static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, INT32 skinnum, const UINT8 *colormap, skincolors_t color)
{
// mostly copied from HWR_GetMappedPatch, hence the similarities and comment
GLMipmap_t *grmip, *newmip;
@ -1089,13 +1163,14 @@ static void HWR_GetBlendedTexture(GLPatch_t *gpatch, GLPatch_t *blendgpatch, con
grmip->nextcolormap = newmip;
newmip->colormap = colormap;
HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, color);
HWR_CreateBlendedTexture(gpatch, blendgpatch, newmip, skinnum, color);
HWD.pfnSetTexture(newmip);
Z_ChangeTag(newmip->grInfo.data, PU_HWRCACHE_UNLOCKED);
}
// -----------------+
// HWR_DrawMD2 : Draw MD2
// : (monsters, bonuses, weapons, lights, ...)
@ -1285,7 +1360,30 @@ void HWR_DrawMD2(gr_vissprite_t *spr)
md2->blendgrpatch && ((GLPatch_t *)md2->blendgrpatch)->mipmap.grInfo.format
&& gpatch->width == ((GLPatch_t *)md2->blendgrpatch)->width && gpatch->height == ((GLPatch_t *)md2->blendgrpatch)->height)
{
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, spr->colormap, (skincolors_t)spr->mobj->color);
INT32 skinnum = TC_DEFAULT;
if ((spr->mobj->flags & (MF_ENEMY|MF_BOSS)) && (spr->mobj->flags2 & MF2_FRET) && !(spr->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
if (spr->mobj->type == MT_CYBRAKDEMON || spr->mobj->colorized)
skinnum = TC_ALLWHITE;
else if (spr->mobj->type == MT_METALSONIC_BATTLE)
skinnum = TC_METALSONIC;
else
skinnum = TC_BOSS;
}
else if (spr->mobj->color)
{
if (spr->mobj->skin && spr->mobj->sprite == SPR_PLAY)
{
if (spr->mobj->colorized)
skinnum = TC_RAINBOW;
else
{
skinnum = (INT32)((skin_t*)spr->mobj->skin-skins);
}
}
else skinnum = TC_DEFAULT;
}
HWR_GetBlendedTexture(gpatch, (GLPatch_t *)md2->blendgrpatch, skinnum, spr->colormap, (skincolors_t)spr->mobj->color);
}
else
{

View File

@ -383,6 +383,7 @@ char sprnames[NUMSPRITES + 1][5] =
"GFLG", // Got Flag sign
"CORK",
"LHRT",
// Ring Weapons
"RRNG", // Red Ring
@ -476,6 +477,9 @@ char sprnames[NUMSPRITES + 1][5] =
"ROIO",
"ROIP",
// Bricks
"BRIC",
// Gravity Well Objects
"GWLG",
"GWLR",
@ -743,10 +747,10 @@ state_t states[NUMSTATES] =
{SPR_PLAY, SPR2_FIRE, 15, {NULL}, S_PLAY_STND, 0, S_PLAY_STND}, // S_PLAY_FIRE_FINISH
// CA_TWINSPIN
{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN
{SPR_PLAY, SPR2_TWIN|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_JUMP, 0, S_PLAY_TWINSPIN}, // S_PLAY_TWINSPIN
// CA2_MELEE
{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 1, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
{SPR_PLAY, SPR2_MLEE|FF_SPR2ENDSTATE, 2, {NULL}, S_PLAY_MELEE_FINISH, 0, S_PLAY_MELEE}, // S_PLAY_MELEE
{SPR_PLAY, SPR2_MLEE, 70, {NULL}, 0, 0, S_PLAY_FALL}, // S_PLAY_MELEE_FINISH
{SPR_PLAY, SPR2_MLEL, 35, {NULL}, 0, 0, S_PLAY_WALK}, // S_PLAY_MELEE_LANDING
@ -1751,20 +1755,23 @@ state_t states[NUMSTATES] =
{SPR_METL, 9, 2, {NULL}, 0, 0, S_METALSONIC_RUN1}, // S_METALSONIC_RUN4
{SPR_METL, 4, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_FLOAT
{SPR_METL, 12, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
{SPR_METL, 0, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
{SPR_METL, 13, 40, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
{SPR_METL, 12|FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_METALSONIC_STUN}, // S_METALSONIC_VECTOR
{SPR_METL, 11, -1, {NULL}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_STUN
{SPR_METL, 13, 20, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_RAISE
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_GATHER
{SPR_METL, 15, -1, {NULL}, 0, 0, S_METALSONIC_BOUNCE},// S_METALSONIC_DASH
{SPR_METL, 14, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BOUNCE
{SPR_METL, 16, -1, {NULL}, 0, 0, S_NULL}, // S_METALSONIC_BADBOUNCE
{SPR_METL, 13, -1, {NULL}, 0, 0, S_METALSONIC_GATHER},// S_METALSONIC_SHOOT
{SPR_METL, 11, 40, {A_Pain}, 0, 0, S_METALSONIC_FLOAT}, // S_METALSONIC_PAIN
{SPR_METL, 11, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH
{SPR_METL, 3, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 4, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2
{SPR_METL, 5, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3
{SPR_METL, 4, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4
{SPR_METL, 13, 8, {A_Fall}, 0, 0, S_METALSONIC_DEATH2},// S_METALSONIC_DEATH1
{SPR_METL, 13, 8, {A_BossScream}, 0, 0, S_METALSONIC_DEATH3},// S_METALSONIC_DEATH2
{SPR_METL, 13, 0, {A_Repeat}, 11, S_METALSONIC_DEATH2, S_METALSONIC_DEATH4}, // S_METALSONIC_DEATH3
{SPR_METL, 13, -1, {A_BossDeath}, 0, 0, S_NULL}, // S_METALSONIC_DEATH4
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE2}, // S_METALSONIC_FLEE1
{SPR_METL, 11, 4, {A_BossScream}, 0, 0, S_METALSONIC_FLEE3}, // S_METALSONIC_FLEE2
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE4}, // S_METALSONIC_FLEE3
{SPR_METL, 11, 4, {NULL}, 0, 0, S_METALSONIC_FLEE1}, // S_METALSONIC_FLEE4
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 0, 1, {NULL}, 0, 0, S_MSSHIELD_F2}, // S_MSSHIELD_F1
{SPR_MSCF, FF_FULLBRIGHT|FF_TRANS30| 1, 1, {NULL}, 0, 0, S_MSSHIELD_F3}, // S_MSSHIELD_F2
@ -2808,12 +2815,18 @@ state_t states[NUMSTATES] =
{SPR_ELEM, FF_FULLBRIGHT|20, 1, {NULL}, 0, 0, S_ELEMF10}, // S_ELEMF9
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_ELEMF1 }, // S_ELEMF10
{SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1
{SPR_PITY, FF_TRANS30|1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2
{SPR_PITY, FF_TRANS30|2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3
{SPR_PITY, FF_TRANS20|3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4
{SPR_PITY, FF_TRANS30|4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5
{SPR_PITY, FF_TRANS20|5, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY6
{SPR_PITY, FF_TRANS30 , 2, {NULL}, 0, 0, S_PITY2}, // S_PITY1
{SPR_PITY, FF_TRANS30| 1, 2, {NULL}, 0, 0, S_PITY3}, // S_PITY2
{SPR_PITY, FF_TRANS30| 2, 2, {NULL}, 0, 0, S_PITY4}, // S_PITY3
{SPR_PITY, FF_TRANS30| 3, 2, {NULL}, 0, 0, S_PITY5}, // S_PITY4
{SPR_PITY, FF_TRANS30| 4, 2, {NULL}, 0, 0, S_PITY6}, // S_PITY5
{SPR_PITY, FF_TRANS30| 5, 2, {NULL}, 0, 0, S_PITY7}, // S_PITY6
{SPR_PITY, FF_TRANS30| 6, 2, {NULL}, 0, 0, S_PITY8}, // S_PITY7
{SPR_PITY, FF_TRANS30| 7, 2, {NULL}, 0, 0, S_PITY9}, // S_PITY8
{SPR_PITY, FF_TRANS30| 8, 2, {NULL}, 0, 0, S_PITY10}, // S_PITY9
{SPR_PITY, FF_TRANS30| 9, 2, {NULL}, 0, 0, S_PITY11}, // S_PITY10
{SPR_PITY, FF_TRANS30|10, 2, {NULL}, 0, 0, S_PITY12}, // S_PITY11
{SPR_PITY, FF_TRANS30|11, 2, {NULL}, 0, 0, S_PITY1}, // S_PITY12
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40 , 2, {NULL}, 0, 0, S_FIRS2}, // S_FIRS1
{SPR_FIRS, FF_FULLBRIGHT|FF_TRANS40|1, 2, {NULL}, 0, 0, S_FIRS3}, // S_FIRS2
@ -3316,7 +3329,8 @@ state_t states[NUMSTATES] =
// CTF Sign
{SPR_GFLG, FF_FULLBRIGHT, 2, {NULL}, 0, 0, S_NULL}, // S_GOTFLAG
{SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
{SPR_CORK, 0, -1, {NULL}, 0, 0, S_NULL}, // S_CORK
{SPR_LHRT, FF_FULLBRIGHT, -1, {NULL}, 0, 0, S_NULL}, // S_LHRT
// Red Rings (thrown)
{SPR_RRNG, FF_FULLBRIGHT, 1, {A_ThrownRing}, 0, 0, S_RRNG2}, // S_RRNG1
@ -3873,6 +3887,8 @@ state_t states[NUMSTATES] =
{SPR_ROIO, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEO
{SPR_ROIP, FF_ANIMATE|FF_RANDOMANIM, -1, {NULL}, 4, 2, S_NULL}, // S_ROCKCRUMBLEP
{SPR_BRIC, FF_ANIMATE, -1, {A_DebrisRandom}, 7, 2, S_NULL}, // S_BRICKDEBRIS
#ifdef SEENAMES
{SPR_NULL, 0, 1, {NULL}, 0, 0, S_NULL}, // S_NAMECHECK
#endif
@ -5739,7 +5755,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
0, // mass
3, // damage
sfx_boingf, // activesound
MF_SPECIAL|MF_BOSS|MF_SHOOTABLE, // flags
MF_SPECIAL|MF_BOSS|MF_SHOOTABLE|MF_GRENADEBOUNCE, // flags
S_NULL // raisestate
},
@ -6317,13 +6333,13 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_METALSONIC_DASH, // seestate
sfx_s3k54, // seesound
0, // reactiontime
sfx_trpowr, // attacksound
sfx_bechrg, // attacksound
S_METALSONIC_PAIN, // painstate
S_METALSONIC_VECTOR,// painchance
sfx_dmpain, // painsound
S_METALSONIC_BADBOUNCE, // meleestate
S_METALSONIC_SHOOT, // missilestate
S_METALSONIC_DEATH, // deathstate
S_METALSONIC_DEATH1,// deathstate
S_METALSONIC_FLEE1, // xdeathstate
sfx_s3k6e, // deathsound
MT_ENERGYBALL, // speed
@ -6355,7 +6371,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
sfx_None, // deathsound
0, // speed
32*FRACUNIT, // radius
64*FRACUNIT, // height
52*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
@ -9198,7 +9214,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_ENERGYBALL1, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_s3k54, // seesound
sfx_bexpld, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
@ -17008,6 +17024,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_LHRT
-1, // doomednum
S_LHRT, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_SPRK1, // deathstate
S_SPRK1, // xdeathstate
sfx_None, // deathsound
60*FRACUNIT, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
0, // mass
1, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_MISSILE, // flags
S_NULL // raisestate
},
{ // MT_REDRING
-1, // doomednum
S_RRNG1, // spawnstate
@ -20063,6 +20106,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate
},
{ // MT_BRICKDEBRIS
-1, // doomednum
S_BRICKDEBRIS, // spawnstate
1, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
0, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_None, // deathsound
0, // speed
16*FRACUNIT, // radius
16*FRACUNIT, // height
0, // display offset
100, // mass
0, // damage
sfx_None, // activesound
MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_RUNSPAWNFUNC|MF_NOCLIPHEIGHT|MF_SCENERY, // flags
S_NULL // raisestate
},
#ifdef SEENAMES
{ // MT_NAMECHECK
-1, // doomednum

View File

@ -628,6 +628,7 @@ typedef enum sprite
SPR_GFLG, // Got Flag sign
SPR_CORK,
SPR_LHRT,
// Ring Weapons
SPR_RRNG, // Red Ring
@ -721,6 +722,9 @@ typedef enum sprite
SPR_ROIO,
SPR_ROIP,
// Bricks
SPR_BRIC,
// Gravity Well Objects
SPR_GWLG,
SPR_GWLR,
@ -1892,7 +1896,10 @@ typedef enum state
S_METALSONIC_BADBOUNCE,
S_METALSONIC_SHOOT,
S_METALSONIC_PAIN,
S_METALSONIC_DEATH,
S_METALSONIC_DEATH1,
S_METALSONIC_DEATH2,
S_METALSONIC_DEATH3,
S_METALSONIC_DEATH4,
S_METALSONIC_FLEE1,
S_METALSONIC_FLEE2,
S_METALSONIC_FLEE3,
@ -2930,6 +2937,12 @@ typedef enum state
S_PITY4,
S_PITY5,
S_PITY6,
S_PITY7,
S_PITY8,
S_PITY9,
S_PITY10,
S_PITY11,
S_PITY12,
S_FIRS1,
S_FIRS2,
@ -3428,6 +3441,7 @@ typedef enum state
S_GOTFLAG,
S_CORK,
S_LHRT,
// Red Ring
S_RRNG1,
@ -3934,6 +3948,9 @@ typedef enum state
S_ROCKCRUMBLEO,
S_ROCKCRUMBLEP,
// Bricks
S_BRICKDEBRIS,
#ifdef SEENAMES
S_NAMECHECK,
#endif
@ -4538,6 +4555,7 @@ typedef enum mobj_type
MT_MACHINEAMBIENCE,
MT_CORK,
MT_LHRT,
// Ring Weapons
MT_REDRING,
@ -4671,6 +4689,9 @@ typedef enum mobj_type
MT_ROCKCRUMBLE15,
MT_ROCKCRUMBLE16,
// Bricks
MT_BRICKDEBRIS,
#ifdef SEENAMES
MT_NAMECHECK,
#endif

View File

@ -540,6 +540,7 @@ static int lib_pSpawnLockOn(lua_State *L)
{
mobj_t *visual = P_SpawnMobj(lockon->x, lockon->y, lockon->z, MT_LOCKON); // positioning, flip handled in P_SceneryThinker
visual->target = lockon;
visual->flags2 |= MF2_DONTDRAW;
P_SetMobjStateNF(visual, state);
}
return 0;
@ -951,6 +952,21 @@ static int lib_pResetPlayer(lua_State *L)
return 0;
}
static int lib_pPlayerCanDamage(lua_State *L)
{
player_t *player = *((player_t **)luaL_checkudata(L, 1, META_PLAYER));
mobj_t *thing = *((mobj_t **)luaL_checkudata(L, 2, META_MOBJ));
NOHUD // was hud safe but then i added a lua hook
INLEVEL
if (!player)
return LUA_ErrInvalid(L, "player_t");
if (!thing)
return LUA_ErrInvalid(L, "mobj_t");
lua_pushboolean(L, P_PlayerCanDamage(player, thing));
return 1;
}
static int lib_pIsObjectInGoop(lua_State *L)
{
mobj_t *mo = *((mobj_t **)luaL_checkudata(L, 1, META_MOBJ));
@ -1219,8 +1235,8 @@ static int lib_pHomingAttack(lua_State *L)
INLEVEL
if (!source || !enemy)
return LUA_ErrInvalid(L, "mobj_t");
P_HomingAttack(source, enemy);
return 0;
lua_pushboolean(L, P_HomingAttack(source, enemy));
return 1;
}
static int lib_pSuperReady(lua_State *L)
@ -2774,6 +2790,7 @@ static luaL_Reg lib[] = {
{"P_PlayerInPain",lib_pPlayerInPain},
{"P_DoPlayerPain",lib_pDoPlayerPain},
{"P_ResetPlayer",lib_pResetPlayer},
{"P_PlayerCanDamage",lib_pPlayerCanDamage},
{"P_IsObjectInGoop",lib_pIsObjectInGoop},
{"P_IsObjectOnGround",lib_pIsObjectOnGround},
{"P_InSpaceSector",lib_pInSpaceSector},

View File

@ -48,6 +48,7 @@ enum hook {
hook_MobjMoveBlocked,
hook_MapThingSpawn,
hook_FollowMobj,
hook_PlayerCanDamage,
hook_PlayerQuit,
hook_MAX // last hook
@ -87,7 +88,8 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8
#define LUAh_ShieldSpecial(player) LUAh_PlayerHook(player, hook_ShieldSpecial) // Hook for shield abilities
#define LUAh_MobjMoveBlocked(mo) LUAh_MobjHook(mo, hook_MobjMoveBlocked) // Hook for P_XYMovement (when movement is blocked)
boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing); // Hook for P_SpawnMapThing by mobj type
boolean LUAh_FollowMobj(player_t *player, mobj_t *mo); // Hook for P_PlayerAfterThink Smiles mobj-following
boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj); // Hook for P_PlayerAfterThink Smiles mobj-following
UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj); // Hook for P_PlayerCanDamage
void LUAh_PlayerQuit(player_t *plr, int reason); // Hook for player quitting
#endif

File diff suppressed because it is too large Load Diff

View File

@ -670,8 +670,8 @@ static int libd_getColormap(lua_State *L)
else if (lua_type(L, 1) == LUA_TNUMBER) // skin number
{
skinnum = (INT32)luaL_checkinteger(L, 1);
if (skinnum < TC_ALLWHITE || skinnum >= MAXSKINS)
return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_ALLWHITE, MAXSKINS-1);
if (skinnum < TC_BLINK || skinnum >= MAXSKINS)
return luaL_error(L, "skin number %d is out of range (%d - %d)", skinnum, TC_BLINK, MAXSKINS-1);
}
else // skin name
{

View File

@ -83,12 +83,11 @@ enum mobj_e {
mobj_extravalue1,
mobj_extravalue2,
mobj_cusval,
#ifdef ESLOPE
mobj_cvmem,
mobj_standingslope
#else
mobj_cvmem
#ifdef ESLOPE
mobj_standingslope,
#endif
mobj_colorized
};
static const char *const mobj_opt[] = {
@ -154,6 +153,7 @@ static const char *const mobj_opt[] = {
#ifdef ESLOPE
"standingslope",
#endif
"colorized",
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])
@ -371,6 +371,9 @@ static int mobj_get(lua_State *L)
LUA_PushUserdata(L, mo->standingslope, META_SLOPE);
break;
#endif
case mobj_colorized:
lua_pushboolean(L, mo->colorized);
break;
default: // extra custom variables in Lua memory
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));
@ -692,6 +695,9 @@ static int mobj_set(lua_State *L)
case mobj_standingslope:
return NOSET;
#endif
case mobj_colorized:
mo->colorized = luaL_checkboolean(L, 3);
break;
default:
lua_getfield(L, LUA_REGISTRYINDEX, LREG_EXTVARS);
I_Assert(lua_istable(L, -1));

View File

@ -2953,8 +2953,9 @@ boolean M_Responder(event_t *ev)
return true;
M_StartControlPanel();
M_Options(0);
currentMenu = &OP_SoundOptionsDef;
itemOn = 0;
// Uncomment the below if you want the menu to reset to the top each time like before. M_SetupNextMenu will fix it automatically.
//OP_SoundOptionsDef.lastOn = 0;
M_SetupNextMenu(&OP_SoundOptionsDef);
return true;
case KEY_F5: // Video Mode

View File

@ -2411,6 +2411,8 @@ void A_VultureBlast(mobj_t *actor)
{
mobj_t *dust;
UINT8 i;
angle_t faa;
fixed_t faacos, faasin;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_VultureBlast", actor))
@ -2419,18 +2421,21 @@ void A_VultureBlast(mobj_t *actor)
S_StartSound(actor, actor->info->attacksound);
faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK;
faacos = FINECOSINE(faa);
faasin = FINESINE(faa);
for (i = 0; i <= 7; i++)
{
angle_t fa = ((i*(angle_t)ANGLE_45) >> ANGLETOFINESHIFT) & FINEMASK;
angle_t faa = (actor->angle >> ANGLETOFINESHIFT) & FINEMASK;
dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -FINESINE(faa)), actor->y + 48*FixedMul(FINECOSINE(fa), FINECOSINE(faa)), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE);
dust = P_SpawnMobj(actor->x + 48*FixedMul(FINECOSINE(fa), -faasin), actor->y + 48*FixedMul(FINECOSINE(fa), faacos), actor->z + actor->height/2 + 48*FINESINE(fa), MT_PARTICLE);
P_SetScale(dust, 4*FRACUNIT);
dust->destscale = FRACUNIT;
dust->scalespeed = 4*FRACUNIT/TICRATE;
dust->fuse = TICRATE;
dust->momx = FixedMul(FINECOSINE(fa), -FINESINE(faa))*3;
dust->momy = FixedMul(FINECOSINE(fa), FINECOSINE(faa))*3;
dust->momx = FixedMul(FINECOSINE(fa), -faasin)*3;
dust->momy = FixedMul(FINECOSINE(fa), faacos)*3;
dust->momz = FINESINE(fa)*6;
}
}
@ -6636,6 +6641,9 @@ void A_RecyclePowers(mobj_t *actor)
players[recv_pl].ringweapons = weapons[send_pl];
players[recv_pl].currentweapon = weaponheld[send_pl];
if (((players[recv_pl].powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (players[recv_pl].revitem == MT_LHRT || players[recv_pl].spinitem == MT_LHRT || players[recv_pl].thokitem == MT_LHRT)) // Healers can't keep their buff.
players[recv_pl].powers[pw_shield] &= SH_STACK;
P_SpawnShieldOrb(&players[recv_pl]);
if (P_IsLocalPlayer(&players[recv_pl]))
P_RestoreMusic(&players[recv_pl]);

View File

@ -446,13 +446,7 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
break;
}
if (((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
|| ((player->pflags & PF_JUMPED) && (!(player->pflags & PF_NOJUMPDAMAGE) || (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
|| (player->pflags & (PF_SPINNING|PF_GLIDING))
|| (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2)
|| ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(toucher)*(toucher->z - (special->z + special->height/2)) > 0) && (P_MobjFlip(toucher)*toucher->momz < 0))
|| player->powers[pw_invulnerability] || player->powers[pw_super]
|| elementalpierce) // Do you possess the ability to subdue the object?
if (P_PlayerCanDamage(player, special)) // Do you possess the ability to subdue the object?
{
if ((P_MobjFlip(toucher)*toucher->momz < 0) && (elementalpierce != 1))
{
@ -467,18 +461,12 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
{
toucher->momx = -toucher->momx;
toucher->momy = -toucher->momy;
if (player->charability == CA_FLY && player->panim == PA_ABILITY)
toucher->momz = -toucher->momz/2;
}
P_DamageMobj(special, toucher, toucher, 1, 0);
}
else if (((toucher->z < special->z && !(toucher->eflags & MFE_VERTICALFLIP))
|| (toucher->z + toucher->height > special->z + special->height && (toucher->eflags & MFE_VERTICALFLIP)))
&& player->charability == CA_FLY
&& (player->powers[pw_tailsfly]
|| toucher->state-states == S_PLAY_FLY_TIRED)) // Tails can shred stuff with her propeller.
{
toucher->momz = -toucher->momz/2;
P_DamageMobj(special, toucher, toucher, 1, 0);
if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
P_TwinSpinRejuvenate(player, player->thokitem);
}
else
P_DamageMobj(toucher, special, special, 1, 0);
@ -1836,6 +1824,10 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
deadtarget = (player->mo->health <= 0);
// Don't log every hazard hit if they don't want us to.
if (!deadtarget && !cv_hazardlog.value)
return;
// Target's name
snprintf(targetname, sizeof(targetname), "%s%s%s",
CTFTEAMCODE(player),
@ -1939,7 +1931,7 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
switch (damagetype)
{
case DMG_WATER:
str = M_GetText("%s was %s by chemical water.\n");
str = M_GetText("%s was %s by dangerous water.\n");
break;
case DMG_FIRE:
str = M_GetText("%s was %s by molten lava.\n");
@ -1987,10 +1979,6 @@ static void P_HitDeathMessages(player_t *player, mobj_t *inflictor, mobj_t *sour
if (!str) // Should not happen! Unless we missed catching something above.
return;
// Don't log every hazard hit if they don't want us to.
if (!deadtarget && !cv_hazardlog.value)
return;
if (deathonly)
{
if (!deadtarget)
@ -2909,26 +2897,47 @@ static inline boolean P_TagDamage(mobj_t *target, mobj_t *inflictor, mobj_t *sou
if (player->powers[pw_flashing] || player->powers[pw_invulnerability])
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
return false;
// Don't allow any damage before the round starts.
if (leveltime <= hidetime * TICRATE)
return false;
// Ignore IT players shooting each other, unless friendlyfire is on.
if ((player->pflags & PF_TAGIT && !((cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) &&
source && source->player && source->player->pflags & PF_TAGIT)))
{
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
return false;
}
// Don't allow players on the same team to hurt one another,
// unless cv_friendlyfire is on.
if (!(cv_friendlyfire.value || (damagetype & DMG_CANHURTSELF)) && (player->pflags & PF_TAGIT) == (source->player->pflags & PF_TAGIT))
{
if (!(inflictor->flags & MF_FIRE))
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
else if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(player, 1);
if (inflictor->flags2 & MF2_BOUNCERING)
inflictor->fuse = 0; // bounce ring disappears at -1 not 0
return false;
}
if (inflictor->type == MT_LHRT)
return false;
// The tag occurs so long as you aren't shooting another tagger with friendlyfire on.
if (source->player->pflags & PF_TAGIT && !(player->pflags & PF_TAGIT))
{
@ -2995,7 +3004,17 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
// In COOP/RACE, you can't hurt other players unless cv_friendlyfire is on
if (!cv_friendlyfire.value && (G_PlatformGametype()))
{
if (gametype == GT_COOP && inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK)) // co-op only
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
return false;
}
}
// Tag handling
@ -3009,7 +3028,15 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
// unless cv_friendlyfire is on.
if (!cv_friendlyfire.value && target->player->ctfteam == source->player->ctfteam)
{
if (!(inflictor->flags & MF_FIRE))
if (inflictor->type == MT_LHRT && !(player->powers[pw_shield] & SH_NOSTACK))
{
if (player->revitem != MT_LHRT && player->spinitem != MT_LHRT && player->thokitem != MT_LHRT) // Healers do not get to heal other healers.
{
P_SwitchShield(player, SH_PINK);
S_StartSound(target, mobjinfo[MT_PITY_ICON].seesound);
}
}
else if (!(inflictor->flags & MF_FIRE))
P_GivePlayerRings(target->player, 1);
if (inflictor->flags2 & MF2_BOUNCERING)
inflictor->fuse = 0; // bounce ring disappears at -1 not 0
@ -3018,6 +3045,9 @@ static inline boolean P_PlayerHitsPlayer(mobj_t *target, mobj_t *inflictor, mobj
}
}
if (inflictor->type == MT_LHRT)
return false;
// Add pity.
if (!player->powers[pw_flashing] && !player->powers[pw_invulnerability] && !player->powers[pw_super]
&& source->player->score > player->score)

View File

@ -134,6 +134,7 @@ pflags_t P_GetJumpFlags(player_t *player);
boolean P_PlayerInPain(player_t *player);
void P_DoPlayerPain(player_t *player, mobj_t *source, mobj_t *inflictor);
void P_ResetPlayer(player_t *player);
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing);
boolean P_IsLocalPlayer(player_t *player);
boolean P_IsObjectInGoop(mobj_t *mo);
@ -164,6 +165,7 @@ boolean P_AutoPause(void);
void P_DoJumpShield(player_t *player);
void P_DoBubbleBounce(player_t *player);
void P_DoAbilityBounce(player_t *player, boolean changemomz);
void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type);
void P_BlackOw(player_t *player);
void P_ElementalFire(player_t *player, boolean cropcircle);
@ -180,7 +182,7 @@ void P_InstaThrustEvenIn2D(mobj_t *mo, angle_t angle, fixed_t move);
mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet);
void P_NukeEnemies(mobj_t *inflictor, mobj_t *source, fixed_t radius);
void P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_HomingAttack(mobj_t *source, mobj_t *enemy); /// \todo doesn't belong in p_user
boolean P_SuperReady(player_t *player);
void P_DoJump(player_t *player, boolean soundandstate);
#if 0

View File

@ -135,6 +135,7 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
fixed_t vertispeed = spring->info->mass;
fixed_t horizspeed = spring->info->damage;
boolean final = false;
UINT8 strong = 0;
// Object was already sprung this tic
if (object->eflags & MFE_SPRUNG)
@ -148,6 +149,14 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
if (!spring->health || !object->health)
return false;
if (object->player)
{
if (object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY)
strong = 1;
else if (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2)
strong = 2;
}
if (spring->info->painchance == -1) // Pinball bumper mode.
{
// The first of the entirely different spring modes!
@ -188,6 +197,9 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
{
fixed_t playervelocity;
if (strong)
vertispeed <<= 1;
if (!(object->player->pflags & PF_THOKKED) && !(object->player->homing)
&& ((playervelocity = FixedDiv(9*FixedHypot(object->player->speed, object->momz), 10<<FRACBITS)) > vertispeed))
vertispeed = playervelocity;
@ -260,11 +272,8 @@ boolean P_DoSpring(mobj_t *spring, mobj_t *object)
return false;
}
if (object->player
&& ((object->player->charability == CA_TWINSPIN && object->player->panim == PA_ABILITY)
|| (object->player->charability2 == CA2_MELEE && object->player->panim == PA_ABILITY2)))
if (strong)
{
S_StartSound(object, sfx_s3k8b);
if (horizspeed)
horizspeed = FixedMul(horizspeed, (4*FRACUNIT)/3);
if (vertispeed)
@ -399,6 +408,12 @@ springstate:
P_AddPlayerScore(object->player, 10);
spring->reactiontime--;
}
if (strong)
{
P_TwinSpinRejuvenate(object->player, (strong == 1 ? object->player->thokitem : object->player->revitem));
S_StartSound(object, sfx_sprong); // strong spring. sprong.
}
}
return final;
@ -710,6 +725,27 @@ static boolean PIT_CheckThing(mobj_t *thing)
return true;
}
// vectorise metal - done in a special case as at this point neither has the right flags for touching
if (thing->type == MT_METALSONIC_BATTLE
&& (tmthing->flags & MF_MISSILE)
&& tmthing->target != thing
&& thing->state == &states[thing->info->spawnstate])
{
blockdist = thing->radius + tmthing->radius;
if (abs(thing->x - tmx) >= blockdist || abs(thing->y - tmy) >= blockdist)
return true; // didn't hit it
if (tmthing->z > thing->z + thing->height)
return true; // overhead
if (tmthing->z + tmthing->height < thing->z)
return true; // underneath
thing->flags2 |= MF2_CLASSICPUSH;
return true;
}
if (!(thing->flags & (MF_SOLID|MF_SPECIAL|MF_PAIN|MF_SHOOTABLE|MF_SPRING)))
return true;
@ -1153,7 +1189,7 @@ static boolean PIT_CheckThing(mobj_t *thing)
tmthing->y = thing->y;
P_SetThingPosition(tmthing);
}
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial
else if (!(tmthing->type == MT_SHELL && thing->player)) // player collision handled in touchspecial for shell
{
UINT8 damagetype = tmthing->info->mass;
if (!damagetype && tmthing->flags & MF_FIRE) // BURN!
@ -1482,51 +1518,45 @@ static boolean PIT_CheckThing(mobj_t *thing)
}
// Monitor?
else if (thing->flags & MF_MONITOR
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2)))
&& !((thing->type == MT_RING_REDBOX && tmthing->player->ctfteam != 1) || (thing->type == MT_RING_BLUEBOX && tmthing->player->ctfteam != 2))
&& (!(thing->flags & MF_SOLID) || P_PlayerCanDamage(tmthing->player, thing)))
{
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
UINT8 elementalpierce = (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (tmthing->player->pflags & PF_SHIELDABILITY)
? (((tmthing->player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0);
if (!(thing->flags & MF_SOLID)
|| tmthing->player->pflags & (PF_SPINNING|PF_GLIDING)
|| ((tmthing->player->pflags & PF_JUMPED)
&& (!(tmthing->player->pflags & PF_NOJUMPDAMAGE)
|| (tmthing->player->charability == CA_TWINSPIN && tmthing->player->panim == PA_ABILITY)))
|| (tmthing->player->charability2 == CA2_MELEE && tmthing->player->panim == PA_ABILITY2)
|| ((tmthing->player->charflags & SF_STOMPDAMAGE || tmthing->player->pflags & PF_BOUNCING)
&& (P_MobjFlip(tmthing)*(tmthing->z - (thing->z + thing->height/2)) > 0) && (P_MobjFlip(tmthing)*tmthing->momz < 0))
|| elementalpierce)
if (thing->z - thing->scale <= tmthing->z + tmthing->height
&& thing->z + thing->height + thing->scale >= tmthing->z)
{
if (thing->z - thing->scale <= tmthing->z + tmthing->height
&& thing->z + thing->height + thing->scale >= tmthing->z)
player_t *player = tmthing->player;
// 0 = none, 1 = elemental pierce, 2 = bubble bounce
UINT8 elementalpierce = (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY)
? (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL) ? 1 : 2)
: 0);
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
fixed_t *z = &tmthing->z; // aau.
// Going down? Then bounce back up.
if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
&& (elementalpierce != 1)) // you're not piercing through the monitor...
{
player_t *player = tmthing->player;
SINT8 flipval = P_MobjFlip(thing); // Save this value in case monitor gets removed.
fixed_t *momz = &tmthing->momz; // tmthing gets changed by P_DamageMobj, so we need a new pointer?! X_x;;
fixed_t *z = &tmthing->z; // aau.
// Going down? Then bounce back up.
if (P_DamageMobj(thing, tmthing, tmthing, 1, 0) // break the monitor
&& (flipval*(*momz) < 0) // monitor is on the floor and you're going down, or on the ceiling and you're going up
&& (elementalpierce != 1)) // you're not piercing through the monitor...
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
{
if (elementalpierce == 2)
P_DoBubbleBounce(player);
else if (!(player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
*momz = -*momz; // Therefore, you should be thrust in the opposite direction, vertically.
if (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)
P_TwinSpinRejuvenate(player, player->thokitem);
}
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
{
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
return false;
}
else
*z -= *momz; // to ensure proper collision.
}
return true;
if (!(elementalpierce == 1 && thing->flags & MF_GRENADEBOUNCE)) // prevent gold monitor clipthrough.
{
if (player->pflags & PF_BOUNCING)
P_DoAbilityBounce(player, false);
return false;
}
else
*z -= *momz; // to ensure proper collision.
}
return true;
}
}

View File

@ -281,6 +281,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state)
player->panim = PA_FALL;
break;
case S_PLAY_FLY:
case S_PLAY_FLY_TIRED:
case S_PLAY_SWIM:
case S_PLAY_GLIDE:
case S_PLAY_BOUNCE:
@ -1506,8 +1507,7 @@ fixed_t P_GetMobjGravity(mobj_t *mo)
if (mo->player)
{
if ((mo->player->pflags & PF_GLIDING)
|| (mo->player->charability == CA_FLY && (mo->player->powers[pw_tailsfly]
|| mo->state-states == S_PLAY_FLY_TIRED)))
|| (mo->player->charability == CA_FLY && mo->player->panim == PA_ABILITY))
gravityadd = gravityadd/3; // less gravity while flying/gliding
if (mo->player->climbing || (mo->player->powers[pw_carry] == CR_NIGHTSMODE))
gravityadd = 0;
@ -3393,11 +3393,7 @@ void P_MobjCheckWater(mobj_t *mobj)
if (!((p->powers[pw_super]) || (p->powers[pw_invulnerability])))
{
boolean electric = !!(p->powers[pw_shield] & SH_PROTECTELECTRIC);
#define SH_OP (SH_PROTECTFIRE|SH_PROTECTWATER|SH_PROTECTELECTRIC)
if ((p->powers[pw_shield] & SH_OP) == SH_OP) // No.
P_KillMobj(mobj, NULL, NULL, DMG_INSTAKILL);
#undef SH_OP
else if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER)))
if (electric || ((p->powers[pw_shield] & SH_PROTECTFIRE) && !(p->powers[pw_shield] & SH_PROTECTWATER)))
{ // Water removes electric and non-water fire shields...
P_FlashPal(p,
electric
@ -5435,7 +5431,8 @@ static void P_Boss7Thinker(mobj_t *mobj)
if (mobj->info->activesound)\
S_StartSound(mobj, mobj->info->activesound);\
if (mobj->info->painchance)\
P_SetMobjState(mobj, mobj->info->painchance)
P_SetMobjState(mobj, mobj->info->painchance);\
mobj->flags2 &= ~MF2_INVERTAIMABLE;\
// Metal Sonic battle boss
// You CAN put multiple Metal Sonics in a single map
@ -5521,27 +5518,17 @@ static void P_Boss9Thinker(mobj_t *mobj)
// AI goes here.
{
boolean danger = true;
angle_t angle;
if (mobj->threshold)
if (mobj->threshold || mobj->movecount)
mobj->momz = (mobj->watertop-mobj->z)/16; // Float to your desired position FASTER
else
mobj->momz = (mobj->watertop-mobj->z)/40; // Float to your desired position
if (mobj->movecount == 2) {
if (mobj->movecount == 2)
{
mobj_t *spawner;
fixed_t dist = 0;
angle = 0x06000000*leveltime;
// Alter your energy bubble's size/position
if (mobj->health > 3) {
mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
P_SetScale(mobj->tracer, mobj->tracer->destscale);
P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2);
mobj->tracer->momx = mobj->momx;
mobj->tracer->momy = mobj->momy;
mobj->tracer->momz = mobj->momz;
}
angle = 0x06000000*leveltime; // wtf?
// Face your target
P_BossTargetPlayer(mobj, true);
@ -5552,27 +5539,150 @@ static void P_Boss9Thinker(mobj_t *mobj)
else
mobj->angle -= InvAngle(angle)/8;
// Alter your energy bubble's size/position
if (mobj->health > 3)
{
mobj->tracer->destscale = FRACUNIT + (4*TICRATE - mobj->fuse)*(FRACUNIT/2)/TICRATE + FixedMul(FINECOSINE(angle>>ANGLETOFINESHIFT),FRACUNIT/2);
P_SetScale(mobj->tracer, mobj->tracer->destscale);
}
else
mobj->tracer->frame &= ~FF_TRANSMASK; // this causes a flicker but honestly i like it this way
P_TeleportMove(mobj->tracer, mobj->x, mobj->y, mobj->z + mobj->height/2 - mobj->tracer->height/2);
mobj->tracer->momx = mobj->momx;
mobj->tracer->momy = mobj->momy;
mobj->tracer->momz = mobj->momz;
// Firin' mah lazors - INDICATOR
if (mobj->fuse > TICRATE/2)
{
tic_t shoottime, worktime, calctime;
shoottime = (TICRATE/((mobj->extravalue1 == 3) ? 8 : 4));
shoottime += (shoottime>>1);
worktime = shoottime*(mobj->threshold/2);
calctime = mobj->fuse-(TICRATE/2);
if (calctime <= worktime && (calctime % shoottime == 0))
{
mobj_t *missile;
missile = P_SpawnMissile(mobj, mobj->target, MT_MSGATHER);
S_StopSound(missile);
if (mobj->extravalue1 >= 2)
P_SetScale(missile, FRACUNIT>>1);
missile->destscale = missile->scale>>1;
missile->fuse = TICRATE/2;
missile->scalespeed = abs(missile->destscale - missile->scale)/missile->fuse;
missile->z -= missile->height/2;
missile->momx *= -1;
missile->momy *= -1;
missile->momz *= -1;
if (mobj->extravalue1 == 2)
{
UINT8 i;
mobj_t *spread;
for (i = 0; i < 5; i++)
{
if (i == 2)
continue;
spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type);
spread->angle = missile->angle+(ANGLE_11hh/2)*(i-2);
P_InstaThrust(spread,spread->angle,-spread->info->speed);
spread->momz = missile->momz;
P_SetScale(spread, missile->scale);
spread->destscale = missile->destscale;
spread->scalespeed = missile->scalespeed;
spread->fuse = missile->fuse;
P_UnsetThingPosition(spread);
spread->x -= spread->fuse*spread->momx;
spread->y -= spread->fuse*spread->momy;
spread->z -= spread->fuse*spread->momz;
P_SetThingPosition(spread);
}
P_InstaThrust(missile,missile->angle,-missile->info->speed);
}
else if (mobj->extravalue1 >= 3)
{
UINT8 i;
mobj_t *spread;
mobj->target->z -= (4*missile->height);
for (i = 0; i < 5; i++)
{
if (i != 2)
{
spread = P_SpawnMissile(mobj, mobj->target, missile->type);
P_SetScale(spread, missile->scale);
spread->destscale = missile->destscale;
spread->fuse = missile->fuse;
spread->z -= spread->height/2;
spread->momx *= -1;
spread->momy *= -1;
spread->momz *= -1;
P_UnsetThingPosition(spread);
spread->x -= spread->fuse*spread->momx;
spread->y -= spread->fuse*spread->momy;
spread->z -= spread->fuse*spread->momz;
P_SetThingPosition(spread);
}
mobj->target->z += missile->height*2;
}
mobj->target->z -= (6*missile->height);
}
P_UnsetThingPosition(missile);
missile->x -= missile->fuse*missile->momx;
missile->y -= missile->fuse*missile->momy;
missile->z -= missile->fuse*missile->momz;
P_SetThingPosition(missile);
S_StartSound(mobj, sfx_s3kb3);
}
}
// up...
mobj->z += mobj->height/2;
// Spawn energy particles
for (spawner = mobj->hnext; spawner; spawner = spawner->hnext) {
for (spawner = mobj->hnext; spawner; spawner = spawner->hnext)
{
dist = P_AproxDistance(spawner->x - mobj->x, spawner->y - mobj->y);
if (P_RandomRange(1,(dist>>FRACBITS)/16) == 1)
break;
}
if (spawner) {
if (spawner)
{
mobj_t *missile = P_SpawnMissile(spawner, mobj, MT_MSGATHER);
if (mobj->health > mobj->info->damage)
missile->momz = FixedDiv(missile->momz, 7*FRACUNIT/5);
if (dist == 0)
missile->fuse = 0;
else
missile->fuse = (dist/P_AproxDistance(missile->momx, missile->momy));
if (missile->fuse > mobj->fuse)
P_RemoveMobj(missile);
if (mobj->health > mobj->info->damage)
{
P_SetScale(missile, FRACUNIT/2);
missile->color = SKINCOLOR_GOLD; // sonic cd electric power
}
else
{
P_SetScale(missile, FRACUNIT/4);
missile->color = SKINCOLOR_MAGENTA; // sonic OVA/4 purple power
}
missile->destscale = missile->scale*2;
missile->scalespeed = abs(missile->scale - missile->destscale)/missile->fuse;
missile->colorized = true;
}
// ...then down. easier than changing the missile's momz after-the-fact
mobj->z -= mobj->height/2;
}
// Pre-threshold reactiontime stuff for attack phases
if (mobj->reactiontime && mobj->movecount == 3) {
if (mobj->reactiontime && mobj->movecount == 3)
{
mobj->reactiontime--;
if (mobj->movedir == 0 || mobj->movedir == 2) { // Pausing between bounces in the pinball phase
@ -5593,13 +5703,15 @@ static void P_Boss9Thinker(mobj_t *mobj)
}
// threshold is used for attacks/maneuvers.
if (mobj->threshold) {
if (mobj->threshold && mobj->movecount != 2) {
fixed_t speed = 20*FRACUNIT + FixedMul(40*FRACUNIT, FixedDiv((mobj->info->spawnhealth - mobj->health)<<FRACBITS, mobj->info->spawnhealth<<FRACBITS));
int tries = 0;
UINT8 tries = 0;
// Firin' mah lazors
if (mobj->movecount == 3 && mobj->movedir == 1) {
if (!(mobj->threshold&1)) {
if (mobj->movecount == 3 && mobj->movedir == 1)
{
if (!(mobj->threshold & 1))
{
mobj_t *missile;
if (mobj->info->seesound)
S_StartSound(mobj, mobj->info->seesound);
@ -5611,18 +5723,20 @@ static void P_Boss9Thinker(mobj_t *mobj)
A_FaceTarget(mobj);
missile = P_SpawnMissile(mobj, mobj->target, mobj->info->speed);
if (mobj->extravalue1 == 2 || mobj->extravalue1 == 3) {
if (mobj->extravalue1 >= 2)
{
missile->destscale = FRACUNIT>>1;
P_SetScale(missile, missile->destscale);
}
missile->fuse = 3*TICRATE;
missile->z -= missile->height/2;
if (mobj->extravalue1 == 2) {
int i;
if (mobj->extravalue1 == 2)
{
UINT8 i;
mobj_t *spread;
missile->flags |= MF_MISSILE;
for (i = 0; i < 5; i++) {
for (i = 0; i < 5; i++)
{
if (i == 2)
continue;
spread = P_SpawnMobj(missile->x, missile->y, missile->z, missile->type);
@ -5631,11 +5745,32 @@ static void P_Boss9Thinker(mobj_t *mobj)
spread->momz = missile->momz;
spread->destscale = FRACUNIT>>1;
P_SetScale(spread, spread->destscale);
spread->fuse = 3*TICRATE;
spread->fuse = missile->fuse;
}
missile->flags &= ~MF_MISSILE;
P_InstaThrust(missile,missile->angle,missile->info->speed);
}
} else {
else if (mobj->extravalue1 >= 3)
{
UINT8 i;
mobj_t *spread;
mobj->target->z -= (2*missile->height);
for (i = 0; i < 5; i++)
{
if (i != 2)
{
spread = P_SpawnMissile(mobj, mobj->target, missile->type);
spread->destscale = FRACUNIT>>1;
P_SetScale(spread, spread->destscale);
spread->fuse = missile->fuse;
spread->z -= spread->height/2;
}
mobj->target->z += missile->height;
}
mobj->target->z -= (3*missile->height);
}
}
else
{
P_SetMobjState(mobj, mobj->state->nextstate);
if (mobj->extravalue1 == 3)
mobj->reactiontime = TICRATE/8;
@ -5649,7 +5784,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
P_SpawnGhostMobj(mobj);
// Pinball attack!
if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2)) {
if (mobj->movecount == 3 && (mobj->movedir == 0 || mobj->movedir == 2))
{
if ((statenum_t)(mobj->state-states) != mobj->info->seestate)
P_SetMobjState(mobj, mobj->info->seestate);
if (mobj->movedir == 0) // mobj health == 1
@ -5658,7 +5794,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
P_InstaThrust(mobj, mobj->angle, 22*FRACUNIT);
else // mobj health == 2
P_InstaThrust(mobj, mobj->angle, 30*FRACUNIT);
if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true)) { // Hit a wall? Find a direction to bounce
if (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true))
{ // Hit a wall? Find a direction to bounce
mobj->threshold--;
P_SetMobjState(mobj, mobj->state->nextstate);
if (!mobj->threshold) { // failed bounce!
@ -5671,11 +5808,15 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->movecount = 0;
P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_CYBRAKDEMON_VILE_EXPLOSION);
P_SetMobjState(mobj, mobj->info->meleestate);
} else if (!(mobj->threshold%4)) { // We've decided to lock onto the player this bounce.
}
else if (!(mobj->threshold%4))
{ // We've decided to lock onto the player this bounce.
S_StartSound(mobj, sfx_s3k5a);
mobj->angle = R_PointToAngle2(mobj->x, mobj->y, mobj->target->x + mobj->target->momx*4, mobj->target->y + mobj->target->momy*4);
mobj->reactiontime = TICRATE - 5*(mobj->info->damage - mobj->health); // targetting time
} else { // No homing, just use P_BounceMove
}
else
{ // No homing, just use P_BounceMove
S_StartSound(mobj, sfx_s3kaa); // make the bounces distinct...
P_BounceMove(mobj);
mobj->angle = R_PointToAngle2(0,0,mobj->momx,mobj->momy);
@ -5689,7 +5830,8 @@ static void P_Boss9Thinker(mobj_t *mobj)
// Vector form dodge!
mobj->angle += mobj->movedir;
P_InstaThrust(mobj, mobj->angle, -speed);
while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16) {
while (!P_TryMove(mobj, mobj->x+mobj->momx, mobj->y+mobj->momy, true) && tries++ < 16)
{
S_StartSound(mobj, sfx_mspogo);
P_BounceMove(mobj);
mobj->angle = R_PointToAngle2(mobj->momx, mobj->momy,0,0);
@ -5746,7 +5888,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
if (mobj->flags2 & MF2_FRET)
return;
if (mobj->state == &states[mobj->info->raisestate])
if (mobj->movecount == 1 || mobj->movecount == 2)
{ // Charging energy
if (mobj->momx != 0 || mobj->momy != 0) { // Apply the air breaks
if (abs(mobj->momx)+abs(mobj->momy) < FRACUNIT)
@ -5754,11 +5896,13 @@ static void P_Boss9Thinker(mobj_t *mobj)
else
P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -6*FRACUNIT/8);
}
return;
if (mobj->state == states+mobj->info->raisestate)
return;
}
if (mobj->fuse == 0)
{
mobj->flags2 &= ~MF2_INVERTAIMABLE;
// It's time to attack! What are we gonna do?!
switch(mobj->movecount)
{
@ -5766,6 +5910,7 @@ static void P_Boss9Thinker(mobj_t *mobj)
default:
// Fly up and prepare for an attack!
// We have to charge up first, so let's go up into the air
S_StartSound(mobj, sfx_beflap);
P_SetMobjState(mobj, mobj->info->raisestate);
if (mobj->floorz >= mobj->target->floorz)
mobj->watertop = mobj->floorz + 256*FRACUNIT;
@ -5773,33 +5918,69 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->watertop = mobj->target->floorz + 256*FRACUNIT;
break;
case 1: {
case 1:
// Okay, we're up? Good, time to gather energy...
if (mobj->health > mobj->info->damage)
{ // No more bubble if we're broken (pinch phase)
mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT);
P_SetTarget(&mobj->tracer, shield);
P_SetTarget(&shield->target, mobj);
// Attack 2: Energy shot!
switch (mobj->health)
{
case 8: // shoot once
default:
mobj->extravalue1 = 0;
mobj->threshold = 2;
break;
case 7: // spread shot (vertical)
mobj->extravalue1 = 4;
mobj->threshold = 2;
break;
case 6: // three shots
mobj->extravalue1 = 1;
mobj->threshold = 3*2;
break;
case 5: // spread shot (horizontal)
mobj->extravalue1 = 2;
mobj->threshold = 2;
break;
case 4: // machine gun
mobj->extravalue1 = 3;
mobj->threshold = 5*2;
break;
}
}
else
P_LinedefExecute(LE_PINCHPHASE, mobj, NULL);
{
mobj_t *shield = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_MSSHIELD_FRONT);
P_SetTarget(&mobj->tracer, shield);
P_SetTarget(&shield->target, mobj);
shield->height -= 20*FRACUNIT; // different offset...
shield->color = SKINCOLOR_MAGENTA;
shield->colorized = true;
P_SetMobjState(shield, S_FIRS1);
//P_LinedefExecute(LE_PINCHPHASE, mobj, NULL); -- why does this happen twice? see case 2...
}
mobj->fuse = 4*TICRATE;
mobj->flags |= MF_PAIN;
if (mobj->info->attacksound)
S_StartSound(mobj, mobj->info->attacksound);
A_FaceTarget(mobj);
break;
}
case 2:
// We're all charged and ready now! Unleash the fury!!
if (mobj->health > mobj->info->damage)
S_StopSound(mobj);
mobj_t *removemobj = mobj->tracer;
P_SetTarget(&mobj->tracer, mobj->hnext);
P_RemoveMobj(removemobj);
if (mobj->health <= mobj->info->damage)
{
mobj_t *removemobj = mobj->tracer;
P_SetTarget(&mobj->tracer, mobj->hnext);
P_RemoveMobj(removemobj);
}
if (mobj->health <= mobj->info->damage) {
mobj_t *whoosh;
// Attack 1: Pinball dash!
if (mobj->health == 1)
mobj->movedir = 0;
@ -5814,32 +5995,23 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->threshold = 24; // bounce 24 times
mobj->watertop = mobj->target->floorz + 16*FRACUNIT;
P_LinedefExecute(LE_PINCHPHASE, mobj, NULL);
} else {
whoosh = P_SpawnMobjFromMobj(mobj, 0, 0, 0, MT_GHOST); // done here so the offset is correct
whoosh->frame = FF_FULLBRIGHT;
whoosh->sprite = SPR_ARMA;
whoosh->destscale = whoosh->scale<<1;
whoosh->scalespeed = FixedMul(whoosh->scalespeed, whoosh->scale);
whoosh->height = 38*whoosh->scale;
whoosh->fuse = 10;
whoosh->color = SKINCOLOR_MAGENTA;
whoosh->colorized = true;
whoosh->flags |= MF_NOCLIPHEIGHT;
}
else
{
// Attack 2: Energy shot!
mobj->movedir = 1;
if (mobj->health >= 8)
mobj->extravalue1 = 0;
else if (mobj->health >= 5)
mobj->extravalue1 = 2;
else if (mobj->health >= 4)
mobj->extravalue1 = 1;
else
mobj->extravalue1 = 3;
switch(mobj->extravalue1) {
case 0: // shoot once
case 2: // spread-shot
default:
mobj->threshold = 2;
break;
case 1: // shoot 3 times
mobj->threshold = 3*2;
break;
case 3: // shoot like a goddamn machinegun
mobj->threshold = 8*2;
break;
}
// looking for the number of things to fire? that's done in case 1 now
}
break;
@ -5873,38 +6045,44 @@ static void P_Boss9Thinker(mobj_t *mobj)
mobj->angle -= InvAngle(angle)/8;
//A_FaceTarget(mobj);
// Check if we're being attacked
if (!(mobj->target->player->pflags & (PF_JUMPED|PF_SPINNING)
|| mobj->target->player->powers[pw_tailsfly]
|| mobj->target->player->powers[pw_invulnerability]
|| mobj->target->player->powers[pw_super]))
danger = false;
if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius)
danger = false;
if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius)
danger = false;
if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius)
danger = false;
if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius)
danger = false;
if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z)
danger = false;
if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height)
danger = false;
if (danger) {
// An incoming attack is detected! What should we do?!
// Go into vector form!
vectorise;
return;
if (mobj->flags2 & MF2_CLASSICPUSH)
mobj->flags2 &= ~MF2_CLASSICPUSH; // a missile caught us in PIT_CheckThing!
else
{
// Check if we're being attacked
if (!mobj->target || !mobj->target->player || !P_PlayerCanDamage(mobj->target->player, mobj))
goto nodanger;
if (mobj->target->x+mobj->target->radius+abs(mobj->target->momx*2) < mobj->x-mobj->radius)
goto nodanger;
if (mobj->target->x-mobj->target->radius-abs(mobj->target->momx*2) > mobj->x+mobj->radius)
goto nodanger;
if (mobj->target->y+mobj->target->radius+abs(mobj->target->momy*2) < mobj->y-mobj->radius)
goto nodanger;
if (mobj->target->y-mobj->target->radius-abs(mobj->target->momy*2) > mobj->y+mobj->radius)
goto nodanger;
if (mobj->target->z+mobj->target->height+mobj->target->momz*2 < mobj->z)
goto nodanger;
if (mobj->target->z+mobj->target->momz*2 > mobj->z+mobj->height)
goto nodanger;
}
// An incoming attack is detected! What should we do?!
// Go into vector form!
vectorise;
return;
nodanger:
mobj->flags2 |= MF2_INVERTAIMABLE;
// Move normally: Approach the player using normal thrust and simulated friction.
dist = P_AproxDistance(mobj->x-mobj->target->x, mobj->y-mobj->target->y);
P_Thrust(mobj, R_PointToAngle2(0, 0, mobj->momx, mobj->momy), -3*FRACUNIT/8);
if (dist < 64*FRACUNIT)
if (dist < 64*FRACUNIT && !(mobj->target->player && mobj->target->player->homing))
P_Thrust(mobj, mobj->angle, -4*FRACUNIT);
else if (dist > 180*FRACUNIT)
P_Thrust(mobj, mobj->angle, FRACUNIT);
else
P_Thrust(mobj, mobj->angle + ANGLE_90, FINECOSINE((((angle_t)(leveltime*ANG1))>>ANGLETOFINESHIFT) & FINEMASK)>>1);
mobj->momz += P_AproxDistance(mobj->momx, mobj->momy)/12; // Move up higher the faster you're going.
}
}
@ -7200,6 +7378,9 @@ void P_MobjThinker(mobj_t *mobj)
P_RemoveMobj(mobj);
return;
}
mobj->flags2 &= ~MF2_DONTDRAW;
mobj->x = mobj->target->x;
mobj->y = mobj->target->y;
@ -7374,6 +7555,7 @@ void P_MobjThinker(mobj_t *mobj)
case MT_ROCKCRUMBLE15:
case MT_ROCKCRUMBLE16:
case MT_WOODDEBRIS:
case MT_BRICKDEBRIS:
if (mobj->z <= P_FloorzAtPos(mobj->x, mobj->y, mobj->z, mobj->height)
&& mobj->state != &states[mobj->info->deathstate])
{
@ -7962,6 +8144,10 @@ void P_MobjThinker(mobj_t *mobj)
}
}
break;
case MT_LHRT:
mobj->momx = FixedMul(mobj->momx, mobj->extravalue2);
mobj->momy = FixedMul(mobj->momy, mobj->extravalue2);
break;
case MT_EGGCAPSULE:
if (!mobj->reactiontime)
{
@ -8918,6 +9104,9 @@ for (i = ((mobj->flags2 & MF2_STRONGBOX) ? strongboxamt : weakboxamt); i; --i) s
case MT_CYBRAKDEMON_NAPALM_BOMB_LARGE:
P_SetMobjState(mobj, mobj->info->deathstate);
break;
case MT_LHRT:
P_KillMobj(mobj, NULL, NULL, 0);
break;
case MT_BLUEFLAG:
case MT_REDFLAG:
if (mobj->spawnpoint)
@ -9274,6 +9463,7 @@ void P_SceneryThinker(mobj_t *mobj)
mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
{
const mobjinfo_t *info = &mobjinfo[type];
UINT8 sc = -1;
state_t *st;
mobj_t *mobj = Z_Calloc(sizeof (*mobj), PU_LEVEL, NULL);
@ -9536,6 +9726,13 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
if (nummaprings >= 0)
nummaprings++;
break;
case MT_METALSONIC_BATTLE:
case MT_METALSONIC_RACE:
sc = 3;
break;
case MT_FANG:
sc = 4;
break;
case MT_CORK:
mobj->flags2 |= MF2_SUPERFIRE;
break;
@ -9560,6 +9757,23 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type)
break;
}
if (sc != -1)
{
UINT8 i;
for (i = 0; i < MAXPLAYERS; i++)
{
if (!playeringame[i] || players[i].spectator)
continue;
if (players[i].skin == sc)
{
mobj->color = SKINCOLOR_SILVER;
mobj->colorized = true;
break;
}
}
}
if (!(mobj->flags & MF_NOTHINK))
P_AddThinker(THINK_MOBJ, &mobj->thinker);

View File

@ -371,6 +371,8 @@ typedef struct mobj_s
struct pslope_s *standingslope; // The slope that the object is standing on (shouldn't need synced in savegames, right?)
#endif
boolean colorized; // Whether the mobj uses the rainbow colormap
// WARNING: New fields must be added separately to savegame and Lua.
} mobj_t;

View File

@ -1262,12 +1262,11 @@ typedef enum
MD2_HNEXT = 1<<7,
MD2_HPREV = 1<<8,
MD2_FLOORROVER = 1<<9,
#ifdef ESLOPE
MD2_CEILINGROVER = 1<<10,
MD2_SLOPE = 1<<11
#else
MD2_CEILINGROVER = 1<<10
#ifdef ESLOPE
MD2_SLOPE = 1<<11,
#endif
MD2_COLORIZED = 1<<12,
} mobj_diff2_t;
typedef enum
@ -1485,6 +1484,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (mobj->standingslope)
diff2 |= MD2_SLOPE;
#endif
if (mobj->colorized)
diff2 |= MD2_COLORIZED;
if (diff2 != 0)
diff |= MD_MORE;
@ -1647,6 +1648,8 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type)
if (diff2 & MD2_SLOPE)
WRITEUINT16(save_p, mobj->standingslope->id);
#endif
if (diff2 & MD2_COLORIZED)
WRITEUINT8(save_p, mobj->colorized);
WRITEUINT32(save_p, mobj->mobjnum);
}
@ -2717,7 +2720,8 @@ static thinker_t* LoadMobjThinker(actionf_p1 thinker)
if (diff2 & MD2_SLOPE)
mobj->standingslope = P_SlopeById(READUINT16(save_p));
#endif
if (diff2 & MD2_COLORIZED)
mobj->colorized = READUINT8(save_p);
if (diff & MD_REDFLAG)
{

View File

@ -1282,6 +1282,9 @@ static void P_LoadLineDefs2(void)
// Compile linedef 'text' from both sidedefs 'text' for appropriate specials.
switch(ld->special)
{
case 331: // Trigger linedef executor: Skin - Continuous
case 332: // Trigger linedef executor: Skin - Each time
case 333: // Trigger linedef executor: Skin - Once
case 443: // Calls a named Lua function
if (sides[ld->sidenum[0]].text)
{
@ -1492,6 +1495,9 @@ static void P_LoadRawSideDefs2(void *data)
break;
}
case 331: // Trigger linedef executor: Skin - Continuous
case 332: // Trigger linedef executor: Skin - Each time
case 333: // Trigger linedef executor: Skin - Once
case 443: // Calls a named Lua function
case 459: // Control text prompt (named tag)
{

View File

@ -259,9 +259,9 @@ static void line_SpawnViaLine(const int linenum, const boolean spawnthinker)
boolean backceil = (special == 711 || special == 712 || special == 703);
UINT8 flags = 0; // Slope flags
if (line->flags & ML_NOSONIC)
if (line->flags & ML_NETONLY)
flags |= SL_NOPHYSICS;
if (line->flags & ML_NOTAILS)
if (line->flags & ML_NONET)
flags |= SL_DYNAMIC;
if(!frontfloor && !backfloor && !frontceil && !backceil)
@ -468,9 +468,9 @@ static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
UINT16 tag1, tag2, tag3;
UINT8 flags = 0;
if (line->flags & ML_NOSONIC)
if (line->flags & ML_NETONLY)
flags |= SL_NOPHYSICS;
if (line->flags & ML_NOTAILS)
if (line->flags & ML_NONET)
flags |= SL_DYNAMIC;
switch(line->special)
@ -494,7 +494,7 @@ static void line_SpawnViaVertexes(const int linenum, const boolean spawnthinker)
return;
}
if (line->flags & ML_NOKNUX)
if (line->flags & ML_EFFECT6)
{
tag1 = line->tag;
tag2 = side->textureoffset >> FRACBITS;

View File

@ -36,6 +36,7 @@
#include "m_cond.h" //unlock triggers
#include "lua_hook.h" // LUAh_LinedefExecute
#include "f_finale.h" // control text prompt
#include "r_things.h" // skins
#ifdef HW3SOUND
#include "hardware/hw3sound.h"
@ -98,7 +99,6 @@ typedef struct
thinker_t **thinkers;
} thinkerlist_t;
static void P_SearchForDisableLinedefs(void);
static void P_SpawnScrollers(void);
static void P_SpawnFriction(void);
static void P_SpawnPushers(void);
@ -2008,7 +2008,12 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
if (!P_CheckNightsTriggerLine(triggerline, actor))
return false;
break;
case 331: // continuous
case 332: // each time
case 333: // once
if (!(actor && actor->player && ((stricmp(triggerline->text, skins[actor->player->skin].name) == 0) ^ ((triggerline->flags & ML_NOCLIMB) == ML_NOCLIMB))))
return false;
break;
default:
break;
}
@ -2141,6 +2146,7 @@ boolean P_RunTriggerLinedef(line_t *triggerline, mobj_t *actor, sector_t *caller
|| specialtype == 326 // DeNightserize - Once
|| specialtype == 328 // Nights lap - Once
|| specialtype == 330 // Nights Bonus Time - Once
|| specialtype == 333 // Skin - Once
|| specialtype == 399) // Level Load
triggerline->special = 0; // Clear it out
@ -2181,7 +2187,8 @@ void P_LinedefExecute(INT16 tag, mobj_t *actor, sector_t *caller)
|| lines[masterline].special == 306 // Character ability - Each time
|| lines[masterline].special == 310 // CTF Red team - Each time
|| lines[masterline].special == 312 // CTF Blue team - Each time
|| lines[masterline].special == 322) // Trigger on X calls - Each Time
|| lines[masterline].special == 322 // Trigger on X calls - Each Time
|| lines[masterline].special == 332)// Skin - Each time
continue;
if (lines[masterline].special < 300
@ -6325,7 +6332,7 @@ void P_InitSpecials(void)
static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flatangle, fixed_t xoffs, fixed_t yoffs)
{
if (!(master->flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set
if (!(master->flags & ML_NETONLY)) // Modify floor flat alignment unless ML_NETONLY flag is set
{
sector->spawn_flrpic_angle = sector->floorpic_angle = flatangle;
sector->floor_xoffs += xoffs;
@ -6335,7 +6342,7 @@ static void P_ApplyFlatAlignment(line_t *master, sector_t *sector, angle_t flata
sector->spawn_flr_yoffs = sector->floor_yoffs;
}
if (!(master->flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set
if (!(master->flags & ML_NONET)) // Modify ceiling flat alignment unless ML_NONET flag is set
{
sector->spawn_ceilpic_angle = sector->ceilingpic_angle = flatangle;
sector->ceiling_xoffs += xoffs;
@ -6416,8 +6423,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
}
}
P_SearchForDisableLinedefs(); // Disable linedefs are now allowed to disable *any* line
P_SpawnScrollers(); // Add generalized scrollers
P_SpawnFriction(); // Friction model using linedefs
P_SpawnPushers(); // Pusher model using linedefs
@ -6466,28 +6471,22 @@ void P_SpawnSpecials(INT32 fromnetsave)
// Init line EFFECTs
for (i = 0; i < numlines; i++)
{
if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups...
if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment in netgames...
{
// set line specials to 0 here too, same reason as above
if (netgame || multiplayer)
{
// future: nonet flag?
}
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
{
lines[i].special = 0;
continue;
}
else
{
if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
|| (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
|| (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)))
if (lines[i].flags & ML_NONET)
{
lines[i].special = 0;
continue;
}
}
else if (lines[i].flags & ML_NETONLY)
{
lines[i].special = 0;
continue;
}
}
switch (lines[i].special)
@ -6526,20 +6525,14 @@ void P_SpawnSpecials(INT32 fromnetsave)
P_AddCameraScanner(&sectors[sec], &sectors[s], R_PointToAngle2(lines[i].v2->x, lines[i].v2->y, lines[i].v1->x, lines[i].v1->y));
break;
#ifdef PARANOIA
case 6: // Disable tags if level not cleared
I_Error("Failed to catch a disable linedef");
break;
#endif
case 7: // Flat alignment - redone by toast
if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something...
if ((lines[i].flags & (ML_NETONLY|ML_NONET)) != (ML_NETONLY|ML_NONET)) // If you can do something...
{
angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y));
fixed_t xoffs;
fixed_t yoffs;
if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set
if (lines[i].flags & ML_EFFECT6) // Set offset through x and y texture offsets if ML_EFFECT6 flag is set
{
xoffs = sides[lines[i].sidenum[0]].textureoffset;
yoffs = sides[lines[i].sidenum[0]].rowoffset;
@ -7178,6 +7171,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 301:
case 310:
case 312:
case 332:
sec = sides[*lines[i].sidenum].sector - sectors;
P_AddEachTimeThinker(&sectors[sec], &lines[i]);
break;
@ -7226,6 +7220,11 @@ void P_SpawnSpecials(INT32 fromnetsave)
case 330:
break;
// Skin trigger executors
case 331:
case 333:
break;
case 399: // Linedef execute on map load
// This is handled in P_RunLevelLoadExecutors.
break;
@ -9181,40 +9180,4 @@ static void P_SpawnPushers(void)
Add_Pusher(p_downwind, l->dx, l->dy, NULL, s, -1, l->flags & ML_NOCLIMB, l->flags & ML_EFFECT4);
break;
}
}
static void P_SearchForDisableLinedefs(void)
{
size_t i;
INT32 j;
// Look for disable linedefs
for (i = 0; i < numlines; i++)
{
if (lines[i].special == 6)
{
// Remove special
// Do *not* remove tag. That would mess with the tag lists
// that P_InitTagLists literally just created!
lines[i].special = 0;
// Ability flags can disable disable linedefs now, lol
if (netgame || multiplayer)
{
// future: nonet flag?
}
else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY)
continue; // Net-only never triggers in single player
else if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC))
continue;
else if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS))
continue;
else if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))
continue;
// Disable any linedef specials with our tag.
for (j = -1; (j = P_FindLineFromLineTag(&lines[i], j)) >= 0;)
lines[j].special = 0;
}
}
}
}

View File

@ -962,6 +962,68 @@ void P_ResetPlayer(player_t *player)
CV_SetValue(&cv_analog2, true);
}
// P_PlayerCanDamage
//
// Can player do damage?
//
boolean P_PlayerCanDamage(player_t *player, mobj_t *thing)
{
if (!player->mo || player->spectator || !thing || P_MobjWasRemoved(thing))
return false;
#ifdef HAVE_BLUA
{
UINT8 shouldCollide = LUAh_PlayerCanDamage(player, thing);
if (P_MobjWasRemoved(thing))
return false; // removed???
if (shouldCollide == 1)
return true; // force yes
else if (shouldCollide == 2)
return false; // force no
}
#endif
// Invinc/super. Not for Monitors.
if (!(thing->flags & MF_MONITOR) && (player->powers[pw_invulnerability] || player->powers[pw_super]))
return true;
// NiGHTS drill. Wasn't originally for monitors, but that's more an oversight being corrected than anything else.
if ((player->powers[pw_carry] == CR_NIGHTSMODE) && (player->pflags & PF_DRILLING))
return true;
// Jumping.
if ((player->pflags & PF_JUMPED)
&& (!(player->pflags & PF_NOJUMPDAMAGE)
|| (player->charability == CA_TWINSPIN && player->panim == PA_ABILITY)))
return true;
// Spinning.
if (player->pflags & PF_SPINNING)
return true;
// From the front.
if (((player->pflags & PF_GLIDING) || (player->charability2 == CA2_MELEE && player->panim == PA_ABILITY2))
&& (player->drawangle - R_PointToAngle2(player->mo->x - player->mo->momx, player->mo->y - player->mo->momy, thing->x, thing->y) + + ANGLE_90) < ANGLE_180)
return true;
// From the top/bottom.
if (P_MobjFlip(player->mo)*(player->mo->z - (thing->z + thing->height/2)) > 0)
{
if ((player->charflags & SF_STOMPDAMAGE || player->pflags & PF_BOUNCING) && (P_MobjFlip(player->mo)*player->mo->momz < 0))
return true;
}
else if (player->charability == CA_FLY && player->panim == PA_ABILITY)
return true;
// Shield stomp.
if (((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL || (player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP) && (player->pflags & PF_SHIELDABILITY))
return true;
return false;
}
//
// P_GivePlayerRings
//
@ -1536,6 +1598,7 @@ void P_SpawnShieldOrb(player_t *player)
orbtype = MT_ARMAGEDDON_ORB;
break;
case SH_PITY:
case SH_PINK: // PITY IN PINK
orbtype = MT_PITY_ORB;
break;
case SH_FLAMEAURA:
@ -1563,7 +1626,13 @@ void P_SpawnShieldOrb(player_t *player)
shieldobj = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, orbtype);
shieldobj->flags2 |= MF2_SHIELD;
P_SetTarget(&shieldobj->target, player->mo);
shieldobj->color = (UINT8)shieldobj->info->painchance;
if ((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK)
{
shieldobj->color = SKINCOLOR_PINK;
shieldobj->colorized = true;
}
else
shieldobj->color = (UINT8)shieldobj->info->painchance;
shieldobj->threshold = (player->powers[pw_shield] & SH_FORCE) ? SH_FORCE : (player->powers[pw_shield] & SH_NOSTACK);
if (shieldobj->info->seestate)
@ -1669,6 +1738,7 @@ mobj_t *P_SpawnGhostMobj(mobj_t *mobj)
}
ghost->color = mobj->color;
ghost->colorized = mobj->colorized; // alternatively, "true" for sonic advance style colourisation
ghost->angle = (mobj->player ? mobj->player->drawangle : mobj->angle);
ghost->sprite = mobj->sprite;
@ -1711,6 +1781,9 @@ void P_SpawnThokMobj(player_t *player)
if (player->spectator)
return;
if (!type)
return;
if (type == MT_GHOST)
mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us
else
@ -1771,6 +1844,9 @@ void P_SpawnSpinMobj(player_t *player, mobjtype_t type)
if (player->spectator)
return;
if (!type)
return;
if (type == MT_GHOST)
mobj = P_SpawnGhostMobj(player->mo); // virtually does everything here for us
else
@ -1926,10 +2002,45 @@ boolean P_PlayerHitFloor(player_t *player)
}
else if (player->charability2 == CA2_MELEE && (player->panim == PA_ABILITY2 && player->mo->state-states != S_PLAY_MELEE_LANDING))
{
mobjtype_t type = player->revitem;
P_SetPlayerMobjState(player->mo, S_PLAY_MELEE_LANDING);
player->mo->tics = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS;
S_StartSound(player->mo, sfx_s3k8b);
player->pflags |= PF_FULLSTASIS;
// hearticles
if (type)
{
UINT8 i = 0;
angle_t throwang = -(2*ANG30);
fixed_t xo = P_ReturnThrustX(player->mo, player->drawangle, 16*player->mo->scale);
fixed_t yo = P_ReturnThrustY(player->mo, player->drawangle, 16*player->mo->scale);
fixed_t zo = 6*player->mo->scale;
fixed_t mu = FixedMul(player->maxdash, player->mo->scale);
fixed_t mu2 = FixedHypot(player->mo->momx, player->mo->momy);
fixed_t ev;
mobj_t *missile;
if (mu2 < mu)
mu2 = mu;
ev = (50*FRACUNIT - (mu/25))/50;
while (i < 5)
{
missile = P_SpawnMobjFromMobj(player->mo, xo, yo, zo, type);
P_SetTarget(&missile->target, player->mo);
missile->angle = throwang + player->drawangle;
P_Thrust(missile, player->drawangle + ANGLE_90,
P_ReturnThrustY(missile, throwang, mu)); // side to side component
P_Thrust(missile, player->drawangle, mu2); // forward component
P_SetObjectMomZ(missile, (4 + ((i&1)<<1))*FRACUNIT, true);
missile->fuse = TICRATE/2;
missile->extravalue2 = ev;
i++;
throwang += ANG30;
}
if (mobjinfo[type].seesound)
S_StartSound(missile, missile->info->seesound);
}
}
else if (player->pflags & PF_JUMPED || !(player->pflags & PF_SPINNING)
|| player->powers[pw_tailsfly] || player->mo->state-states == S_PLAY_FLY_TIRED)
@ -4270,7 +4381,11 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
P_SetObjectMomZ(player->mo, player->mindash, false);
if (player->mo->eflags & MFE_UNDERWATER)
player->mo->momz >>= 1;
#if 0
if (FixedMul(player->speed, FINECOSINE(((player->mo->angle - R_PointToAngle2(0, 0, player->rmomx, player->rmomy)) >> ANGLETOFINESHIFT) & FINEMASK)) < FixedMul(player->maxdash, player->mo->scale))
#else
if (player->speed < FixedMul(player->maxdash, player->mo->scale))
#endif
{
player->drawangle = player->mo->angle;
P_InstaThrust(player->mo, player->mo->angle, FixedMul(player->maxdash, player->mo->scale));
@ -4404,6 +4519,57 @@ void P_DoAbilityBounce(player_t *player, boolean changemomz)
player->pflags |= PF_BOUNCING|PF_THOKKED;
}
//
// P_TwinSpinRejuvenate
//
// CA_TWINSPIN landing handling
//
void P_TwinSpinRejuvenate(player_t *player, mobjtype_t type)
{
fixed_t actionspd;
angle_t movang, ang, fa;
fixed_t v, h;
UINT8 i;
if (!player->mo || !type)
return;
actionspd = FixedMul(player->actionspd, player->mo->scale);
fa = (R_PointToAngle2(0, 0, player->mo->momz, FixedHypot(player->mo->momx, player->mo->momy))>>ANGLETOFINESHIFT) & FINEMASK;
movang = R_PointToAngle2(0, 0, player->mo->momx, player->mo->momy);
ang = 0;
v = FixedMul(actionspd, FINESINE(fa));
h = actionspd - FixedMul(actionspd, FINECOSINE(fa));
// hearticles
for (i = 0; i <= 7; i++)
{
fixed_t side = actionspd - FixedMul(h, abs(FINESINE((ang>>ANGLETOFINESHIFT) & FINEMASK)));
fixed_t xo = P_ReturnThrustX(NULL, ang + movang, side);
fixed_t yo = P_ReturnThrustY(NULL, ang + movang, side);
fixed_t zo = -FixedMul(FINECOSINE(((ang>>ANGLETOFINESHIFT) & FINEMASK)), v);
mobj_t *missile = P_SpawnMobjFromMobj(player->mo,
xo,
yo,
player->mo->height/2 + zo,
type);
P_SetTarget(&missile->target, player->mo);
P_SetScale(missile, (missile->destscale >>= 1));
missile->angle = ang + movang;
missile->fuse = TICRATE/2;
missile->extravalue2 = (99*FRACUNIT)/100;
missile->momx = xo;
missile->momy = yo;
missile->momz = zo;
ang += ANGLE_45;
}
player->pflags &= ~PF_THOKKED;
}
//
// P_Telekinesis
//
@ -4616,10 +4782,10 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->mo->momx /= 2;
player->mo->momy /= 2;
}
else if (player->charability == CA_HOMINGTHOK)
if (player->charability == CA_HOMINGTHOK)
{
player->mo->momx /= 3;
player->mo->momy /= 3;
player->mo->momx /= 2;
player->mo->momy /= 2;
}
if (player->charability == CA_HOMINGTHOK)
@ -7721,7 +7887,7 @@ static void P_MovePlayer(player_t *player)
if (!(player->pflags & (PF_USEDOWN|PF_GLIDING|PF_SLIDING|PF_SHIELDABILITY)) // If the player is not holding down BT_USE, or having used an ability previously
&& (!(player->powers[pw_shield] & SH_NOSTACK) || !(player->pflags & PF_THOKKED) || ((player->powers[pw_shield] & SH_NOSTACK) == SH_BUBBLEWRAP && player->secondjump == UINT8_MAX))) // thokked is optional if you're bubblewrapped/turning super
{
// Force shield activation
// Force stop
if ((player->powers[pw_shield] & ~(SH_FORCEHP|SH_STACK)) == SH_FORCE)
{
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
@ -7737,17 +7903,17 @@ static void P_MovePlayer(player_t *player)
if (P_SuperReady(player))
P_DoSuperTransformation(player, false);
break;
// Whirlwind/Thundercoin shield activation
// Whirlwind jump/Thunder jump
case SH_WHIRLWIND:
case SH_THUNDERCOIN:
P_DoJumpShield(player);
break;
// Armageddon shield activation
// Armageddon pow
case SH_ARMAGEDDON:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
P_BlackOw(player);
break;
// Attract shield activation
// Attraction blast
case SH_ATTRACT:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
player->homing = 2;
@ -7756,13 +7922,14 @@ static void P_MovePlayer(player_t *player)
{
player->mo->angle = R_PointToAngle2(player->mo->x, player->mo->y, lockon->x, lockon->y);
player->pflags &= ~PF_NOJUMPDAMAGE;
P_SetPlayerMobjState(player->mo, S_PLAY_ROLL);
S_StartSound(player->mo, sfx_s3k40);
player->homing = 3*TICRATE;
}
else
S_StartSound(player->mo, sfx_s3ka6);
break;
// Elemental/Bubblewrap shield activation
// Elemental stomp/Bubble bounce
case SH_ELEMENTAL:
case SH_BUBBLEWRAP:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
@ -7776,7 +7943,7 @@ static void P_MovePlayer(player_t *player)
? sfx_s3k43
: sfx_s3k44);
break;
// Flame shield activation
// Flame burst
case SH_FLAMEAURA:
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
P_Thrust(player->mo, player->mo->angle, FixedMul(30*FRACUNIT - FixedSqrt(FixedDiv(player->speed, player->mo->scale)), player->mo->scale));
@ -7797,8 +7964,7 @@ static void P_MovePlayer(player_t *player)
{
if (player->homing && player->mo->tracer)
{
P_HomingAttack(player->mo, player->mo->tracer);
if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET))
if (!P_HomingAttack(player->mo, player->mo->tracer))
{
P_SetObjectMomZ(player->mo, 6*FRACUNIT, false);
if (player->mo->eflags & MFE_UNDERWATER)
@ -7817,10 +7983,9 @@ static void P_MovePlayer(player_t *player)
if (player->homing && player->mo->tracer)
{
P_SpawnThokMobj(player);
P_HomingAttack(player->mo, player->mo->tracer);
// But if you don't, then stop homing.
if (player->mo->tracer->health <= 0 || (player->mo->tracer->flags2 & MF2_FRET))
if (!P_HomingAttack(player->mo, player->mo->tracer))
{
if (player->mo->eflags & MFE_UNDERWATER)
P_SetObjectMomZ(player->mo, FixedDiv(457*FRACUNIT,72*FRACUNIT), false);
@ -8400,7 +8565,7 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
mo = (mobj_t *)think;
if (!(mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR|MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
if (!((mo->flags & (MF_ENEMY|MF_BOSS|MF_MONITOR) && (mo->flags & MF_SHOOTABLE)) || (mo->flags & MF_SPRING)) == !(mo->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
continue; // not a valid target
if (mo->health <= 0) // dead
@ -8412,9 +8577,6 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
if (mo->flags2 & MF2_FRET)
continue;
if ((mo->flags & (MF_ENEMY|MF_BOSS)) && !(mo->flags & MF_SHOOTABLE)) // don't aim at something you can't shoot at anyway (see Egg Guard or Minus)
continue;
if (!nonenemies && mo->flags & (MF_MONITOR|MF_SPRING))
continue;
@ -8468,17 +8630,23 @@ mobj_t *P_LookForEnemies(player_t *player, boolean nonenemies, boolean bullet)
return closestmo;
}
void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
boolean P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
{
fixed_t zdist;
fixed_t dist;
fixed_t ns = 0;
if (!enemy)
return;
return false;
if (!(enemy->health))
return;
if (!enemy->health)
return false;
if (enemy->flags2 & MF2_FRET)
return false;
if (!(enemy->flags & (MF_SHOOTABLE|MF_SPRING)) == !(enemy->flags2 & MF2_INVERTAIMABLE)) // allows if it has the flags desired XOR it has the invert aimable flag
return false;
// change angle
source->angle = R_PointToAngle2(source->x, source->y, enemy->x, enemy->y);
@ -8521,6 +8689,8 @@ void P_HomingAttack(mobj_t *source, mobj_t *enemy) // Home in on your target
source->momx = FixedMul(FixedDiv(enemy->x - source->x, dist), ns);
source->momy = FixedMul(FixedDiv(enemy->y - source->y, dist), ns);
source->momz = FixedMul(FixedDiv(zdist, dist), ns);
return true;
}
// Search for emeralds
@ -9687,12 +9857,12 @@ void P_DoPityCheck(player_t *player)
// Apply pity shield if available.
if ((player->pity >= 3 || player->pity < 0) && player->powers[pw_shield] == SH_NONE)
{
P_SwitchShield(player, SH_PITY);
if (player->pity > 0)
S_StartSound(player->mo, mobjinfo[MT_PITY_ICON].seesound);
player->pity = 0;
player->powers[pw_shield] = SH_PITY;
P_SpawnShieldOrb(player);
}
}

View File

@ -126,10 +126,12 @@ UINT32 nflatxshift, nflatyshift, nflatshiftup, nflatmask;
#define BOSS_TT_CACHE_INDEX (MAXSKINS + 1)
#define METALSONIC_TT_CACHE_INDEX (MAXSKINS + 2)
#define ALLWHITE_TT_CACHE_INDEX (MAXSKINS + 3)
#define RAINBOW_TT_CACHE_INDEX (MAXSKINS + 4)
#define BLINK_TT_CACHE_INDEX (MAXSKINS + 5)
#define DEFAULT_STARTTRANSCOLOR 96
#define NUM_PALETTE_ENTRIES 256
static UINT8** translationtablecache[MAXSKINS + 4] = {NULL};
static UINT8** translationtablecache[MAXSKINS + 6] = {NULL};
const UINT8 Color_Index[MAXTRANSLATIONS-1][16] = {
// {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, // SKINCOLOR_NONE
@ -457,17 +459,82 @@ void R_InitTranslationTables(void)
\return void
*/
// 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)) / 3)
/** \brief Generates the rainbow colourmaps that are used when a player has the invincibility power... stolen from kart, with permission
\param dest_colormap colormap to populate
\param skincolor translation color
*/
static void R_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(Color_Index[skincolor-1][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] = Color_Index[skincolor-1][j];
}
}
}
}
#undef SETBRIGHTNESS
static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, UINT8 color)
{
INT32 i, starttranscolor, skinramplength;
// Handle a couple of simple special cases
if (skinnum == TC_BOSS || skinnum == TC_ALLWHITE || skinnum == TC_METALSONIC || color == SKINCOLOR_NONE)
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)
memset(dest_colormap, 0, NUM_PALETTE_ENTRIES * sizeof(UINT8));
else if (skinnum == TC_BLINK && color != SKINCOLOR_NONE)
memset(dest_colormap, Color_Index[color-1][3], NUM_PALETTE_ENTRIES * sizeof(UINT8));
else
{
if (skinnum == TC_ALLWHITE) dest_colormap[i] = 0;
else dest_colormap[i] = (UINT8)i;
for (i = 0; i < NUM_PALETTE_ENTRIES; i++)
dest_colormap[i] = (UINT8)i;
}
// White!
@ -478,6 +545,11 @@ static void R_GenerateTranslationColormap(UINT8 *dest_colormap, INT32 skinnum, U
return;
}
else if (skinnum == TC_RAINBOW)
{
R_RainbowColormap(dest_colormap, color);
return;
}
if (color >= MAXTRANSLATIONS)
I_Error("Invalid skin color #%hu.", (UINT16)color);
@ -522,6 +594,8 @@ UINT8* R_GetTranslationColormap(INT32 skinnum, skincolors_t color, UINT8 flags)
else if (skinnum == TC_BOSS) skintableindex = BOSS_TT_CACHE_INDEX;
else if (skinnum == TC_METALSONIC) skintableindex = METALSONIC_TT_CACHE_INDEX;
else if (skinnum == TC_ALLWHITE) skintableindex = ALLWHITE_TT_CACHE_INDEX;
else if (skinnum == TC_RAINBOW) skintableindex = RAINBOW_TT_CACHE_INDEX;
else if (skinnum == TC_BLINK) skintableindex = BLINK_TT_CACHE_INDEX;
else skintableindex = skinnum;
if (flags & GTC_CACHE)

View File

@ -105,6 +105,8 @@ extern lumpnum_t viewborderlump[8];
#define TC_BOSS -2
#define TC_METALSONIC -3 // For Metal Sonic battle
#define TC_ALLWHITE -4 // For Cy-Brak-demon
#define TC_RAINBOW -5 // For single colour
#define TC_BLINK -6 // For item blinking, according to kart
// Initialize color translation tables, for player rendering etc.
void R_InitTranslationTables(void);

View File

@ -719,11 +719,11 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = basecolfunc; // hack: this isn't resetting properly somewhere.
dc_colormap = vis->colormap;
if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && (leveltime & 1)) // Bosses "flash"
if (!(vis->cut & SC_PRECIP) && (vis->mobj->flags & (MF_ENEMY|MF_BOSS)) && (vis->mobj->flags2 & MF2_FRET) && !(vis->mobj->flags & MF_GRENADEBOUNCE) && (leveltime & 1)) // Bosses "flash"
{
// translate certain pixels to white
colfunc = transcolfunc;
if (vis->mobj->type == MT_CYBRAKDEMON)
if (vis->mobj->type == MT_CYBRAKDEMON || vis->mobj->colorized)
dc_translation = R_GetTranslationColormap(TC_ALLWHITE, 0, GTC_CACHE);
else if (vis->mobj->type == MT_METALSONIC_BATTLE)
dc_translation = R_GetTranslationColormap(TC_METALSONIC, 0, GTC_CACHE);
@ -734,7 +734,9 @@ static void R_DrawVisSprite(vissprite_t *vis)
{
colfunc = transtransfunc;
dc_transmap = vis->transmap;
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // MT_GHOST LOOKS LIKE A PLAYER SO USE THE PLAYER TRANSLATION TABLES. >_>
{
size_t skinnum = (skin_t*)vis->mobj->skin-skins;
dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
@ -753,7 +755,9 @@ static void R_DrawVisSprite(vissprite_t *vis)
colfunc = transcolfunc;
// New colormap stuff for skins Tails 06-07-2002
if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
if (!(vis->cut & SC_PRECIP) && vis->mobj->colorized)
dc_translation = R_GetTranslationColormap(TC_RAINBOW, vis->mobj->color, GTC_CACHE);
else if (!(vis->cut & SC_PRECIP) && vis->mobj->skin && vis->mobj->sprite == SPR_PLAY) // This thing is a player!
{
size_t skinnum = (skin_t*)vis->mobj->skin-skins;
dc_translation = R_GetTranslationColormap((INT32)skinnum, vis->mobj->color, GTC_CACHE);
@ -2700,6 +2704,9 @@ void SetPlayerSkinByNum(INT32 playernum, INT32 skinnum)
player->revitem = skin->revitem < 0 ? (mobjtype_t)mobjinfo[MT_PLAYER].raisestate : (UINT32)skin->revitem;
player->followitem = skin->followitem;
if (((player->powers[pw_shield] & SH_NOSTACK) == SH_PINK) && (player->revitem == MT_LHRT || player->spinitem == MT_LHRT || player->thokitem == MT_LHRT)) // Healers can't keep their buff.
player->powers[pw_shield] &= SH_STACK;
player->actionspd = skin->actionspd;
player->mindash = skin->mindash;
player->maxdash = skin->maxdash;

View File

@ -137,7 +137,7 @@ sfxinfo_t S_sfx[NUMSFX] =
// Game objects, etc
{"appear", false, 127, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Appearing platform"},
{"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon explosion"},
{"bkpoof", false, 70, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Armageddon pow"},
{"bnce1", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bounce"}, // Boing!
{"bnce2", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Scatter"}, // Boing!
{"cannon", false, 64, 8, -1, NULL, 0, -1, -1, LUMPERROR, "Powerful shot"},
@ -198,6 +198,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"bowl", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bowling"},
{"chuchu", false, 32, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Train horn"},
{"bsnipe", false, 200, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Home-run smash"},
{"sprong", false, 112, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Power spring"},
// Menu, interface
{"chchng", false, 120, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Score"},
@ -304,7 +305,7 @@ sfxinfo_t S_sfx[NUMSFX] =
{"s3k3e", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame Shield"},
{"s3k3f", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble Shield"},
{"s3k40", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Attraction blast"},
{"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Lightning Shield"},
{"s3k41", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Thunder Shield"},
{"s3k42", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Twinspin"},
{"s3k43", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Flame burst"},
{"s3k44", false, 64, 0, -1, NULL, 0, -1, -1, LUMPERROR, "Bubble bounce"},

View File

@ -264,6 +264,7 @@ typedef enum
sfx_bowl,
sfx_chuchu,
sfx_bsnipe,
sfx_sprong,
// Menu, interface
sfx_chchng,

View File

@ -95,6 +95,7 @@ static patch_t *ringshield;
static patch_t *watershield;
static patch_t *bombshield;
static patch_t *pityshield;
static patch_t *pinkshield;
static patch_t *flameshield;
static patch_t *bubbleshield;
static patch_t *thundershield;
@ -285,6 +286,7 @@ void ST_LoadGraphics(void)
watershield = W_CachePatchName("TVELICON", PU_HUDGFX);
bombshield = W_CachePatchName("TVARICON", PU_HUDGFX);
pityshield = W_CachePatchName("TVPIICON", PU_HUDGFX);
pinkshield = W_CachePatchName("TVPPICON", PU_HUDGFX);
flameshield = W_CachePatchName("TVFLICON", PU_HUDGFX);
bubbleshield = W_CachePatchName("TVBBICON", PU_HUDGFX);
thundershield = W_CachePatchName("TVZPICON", PU_HUDGFX);
@ -1250,6 +1252,7 @@ static void ST_drawPowerupHUD(void)
case SH_ARMAGEDDON: p = bombshield; break;
case SH_ATTRACT: p = ringshield; break;
case SH_PITY: p = pityshield; break;
case SH_PINK: p = pinkshield; break;
case SH_FLAMEAURA: p = flameshield; break;
case SH_BUBBLEWRAP: p = bubbleshield; break;
case SH_THUNDERCOIN: p = thundershield; break;