diff --git a/src/d_player.h b/src/d_player.h index cdc899f5e..c133af703 100644 --- a/src/d_player.h +++ b/src/d_player.h @@ -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, diff --git a/src/dehacked.c b/src/dehacked.c index 97af54f8b..8bff80869 100644 --- a/src/dehacked.c +++ b/src/dehacked.c @@ -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<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); diff --git a/src/hardware/hw_md2.c b/src/hardware/hw_md2.c index d69233a9b..e26aa98ff 100644 --- a/src/hardware/hw_md2.c +++ b/src/hardware/hw_md2.c @@ -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); + blendcolor.s.green = (UINT8)(FixedSqrt((g/div)<>FRACBITS); + blendcolor.s.blue = (UINT8)(FixedSqrt((b/div)<>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 { diff --git a/src/info.c b/src/info.c index 1da0922a4..27ee15957 100644 --- a/src/info.c +++ b/src/info.c @@ -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 diff --git a/src/info.h b/src/info.h index 6034dfc7e..5540dc33d 100644 --- a/src/info.h +++ b/src/info.h @@ -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 diff --git a/src/lua_baselib.c b/src/lua_baselib.c index 755b76835..81a17ef20 100644 --- a/src/lua_baselib.c +++ b/src/lua_baselib.c @@ -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}, diff --git a/src/lua_hook.h b/src/lua_hook.h index 9fcc36594..45e116c34 100644 --- a/src/lua_hook.h +++ b/src/lua_hook.h @@ -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 diff --git a/src/lua_hooklib.c b/src/lua_hooklib.c index d605499e2..7f7e8adc6 100644 --- a/src/lua_hooklib.c +++ b/src/lua_hooklib.c @@ -59,6 +59,7 @@ const char *const hookNames[hook_MAX+1] = { "MobjMoveBlocked", "MapThingSpawn", "FollowMobj", + "PlayerCanDamage", "PlayerQuit", NULL }; @@ -200,6 +201,7 @@ static int lib_addHook(lua_State *L) case hook_JumpSpinSpecial: case hook_PlayerSpawn: case hook_FollowMobj: + case hook_PlayerCanDamage: case hook_ShieldSpawn: case hook_ShieldSpecial: lastp = &playerhooks; @@ -250,44 +252,48 @@ boolean LUAh_MobjHook(mobj_t *mo, enum hook which) // Look for all generic mobj hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == which) - { - if (lua_gettop(gL) == 0) - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + LUA_PushUserdata(gL, mo, META_MOBJ); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - if (hookp->type == which) - { - if (lua_gettop(gL) == 0) - LUA_PushUserdata(gL, mo, META_MOBJ); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + LUA_PushUserdata(gL, mo, META_MOBJ); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -303,24 +309,26 @@ boolean LUAh_PlayerHook(player_t *plr, enum hook which) lua_settop(gL, 0); for (hookp = playerhooks; hookp; hookp = hookp->next) - if (hookp->type == which) - { - if (lua_gettop(gL) == 0) - LUA_PushUserdata(gL, plr, META_PLAYER); - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - if (lua_pcall(gL, 1, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) + LUA_PushUserdata(gL, plr, META_PLAYER); + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + if (lua_pcall(gL, 1, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); lua_pop(gL, 1); + hookp->error = true; + continue; } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -337,13 +345,15 @@ void LUAh_MapChange(INT16 mapnumber) lua_pushinteger(gL, mapnumber); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MapChange) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_MapChange) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } lua_settop(gL, 0); } @@ -359,13 +369,15 @@ void LUAh_MapLoad(void) lua_pushinteger(gL, gamemap); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_MapLoad) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_MapLoad) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } lua_settop(gL, 0); } @@ -381,13 +393,15 @@ void LUAh_PlayerJoin(int playernum) lua_pushinteger(gL, playernum); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerJoin) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_PlayerJoin) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); + LUA_Call(gL, 1); + } lua_settop(gL, 0); } @@ -400,17 +414,19 @@ void LUAh_ThinkFrame(void) return; for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_ThinkFrame) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - if (lua_pcall(gL, 0, 0, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - } + { + if (hookp->type != hook_ThinkFrame) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + if (lua_pcall(gL, 0, 0, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; } + } } // Hook for mobj collisions @@ -427,62 +443,66 @@ UINT8 LUAh_MobjCollideHook(mobj_t *thing1, mobj_t *thing2, enum hook which) // Look for all generic mobj collision hooks for (hookp = mobjcollidehooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == which) + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, thing1, META_MOBJ); + LUA_PushUserdata(gL, thing2, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } for (hookp = mobjcollidehooks[thing1->type]; hookp; hookp = hookp->next) - if (hookp->type == which) + { + if (hookp->type != which) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, thing1, META_MOBJ); - LUA_PushUserdata(gL, thing2, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { // if nil, leave shouldCollide = 0. - if (lua_toboolean(gL, -1)) - shouldCollide = 1; // Force yes - else - shouldCollide = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, thing1, META_MOBJ); + LUA_PushUserdata(gL, thing2, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldCollide; @@ -557,52 +577,56 @@ boolean LUAh_TouchSpecial(mobj_t *special, mobj_t *toucher) // Look for all generic touch special hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_TouchSpecial) + { + if (hookp->type != hook_TouchSpecial) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[special->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_TouchSpecial) + { + if (hookp->type != hook_TouchSpecial) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, special, META_MOBJ); - LUA_PushUserdata(gL, toucher, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, special, META_MOBJ); + LUA_PushUserdata(gL, toucher, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -622,72 +646,75 @@ UINT8 LUAh_ShouldDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 // Look for all generic should damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldDamage) + { + if (hookp->type != hook_ShouldDamage) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_ShouldDamage) + { + if (hookp->type != hook_ShouldDamage) + continue; + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (!lua_isnil(gL, -1)) - { - if (lua_toboolean(gL, -1)) - shouldDamage = 1; // Force yes - else - shouldDamage = 2; // Force no - } - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { + if (lua_toboolean(gL, -1)) + shouldDamage = 1; // Force yes + else + shouldDamage = 2; // Force no + } + lua_pop(gL, 1); + } lua_settop(gL, 0); return shouldDamage; @@ -707,62 +734,66 @@ boolean LUAh_MobjDamage(mobj_t *target, mobj_t *inflictor, mobj_t *source, INT32 // Look for all generic mobj damage hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDamage) + { + if (hookp->type != hook_MobjDamage) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDamage) + { + if (hookp->type != hook_MobjDamage) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damage); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - lua_pushvalue(gL, -6); - if (lua_pcall(gL, 5, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damage); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + lua_pushvalue(gL, -6); + if (lua_pcall(gL, 5, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -782,58 +813,62 @@ boolean LUAh_MobjDeath(mobj_t *target, mobj_t *inflictor, mobj_t *source, UINT8 // Look for all generic mobj death hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDeath) + { + if (hookp->type != hook_MobjDeath) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - if (lua_pcall(gL, 3, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + if (lua_pcall(gL, 3, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[target->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MobjDeath) + { + if (hookp->type != hook_MobjDeath) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, target, META_MOBJ); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, target, META_MOBJ); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -850,28 +885,30 @@ boolean LUAh_BotTiccmd(player_t *bot, ticcmd_t *cmd) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_BotTiccmd) + { + if (hookp->type != hook_BotTiccmd) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, bot, META_PLAYER); - LUA_PushUserdata(gL, cmd, META_TICCMD); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, bot, META_PLAYER); + LUA_PushUserdata(gL, cmd, META_TICCMD); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -888,51 +925,53 @@ boolean LUAh_BotAI(mobj_t *sonic, mobj_t *tails, ticcmd_t *cmd) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_BotAI - && (hookp->s.skinname == NULL || !strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + { + if (hookp->type != hook_BotAI + || (hookp->s.skinname && strcmp(hookp->s.skinname, ((skin_t*)tails->skin)->name))) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, sonic, META_MOBJ); - LUA_PushUserdata(gL, tails, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 8, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - - // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. - if (lua_istable(gL, 2+1)) { - boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; -#define CHECKFIELD(field) \ - lua_getfield(gL, 2+1, #field);\ - if (lua_toboolean(gL, -1))\ - field = true;\ - lua_pop(gL, 1); - - CHECKFIELD(forward) - CHECKFIELD(backward) - CHECKFIELD(left) - CHECKFIELD(right) - CHECKFIELD(strafeleft) - CHECKFIELD(straferight) - CHECKFIELD(jump) - CHECKFIELD(spin) -#undef CHECKFIELD - B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); - } else - B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); - - lua_pop(gL, 8); - hooked = true; + LUA_PushUserdata(gL, sonic, META_MOBJ); + LUA_PushUserdata(gL, tails, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 8, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + + // This turns forward, backward, left, right, jump, and spin into a proper ticcmd for tails. + if (lua_istable(gL, 2+1)) { + boolean forward=false, backward=false, left=false, right=false, strafeleft=false, straferight=false, jump=false, spin=false; +#define CHECKFIELD(field) \ + lua_getfield(gL, 2+1, #field);\ + if (lua_toboolean(gL, -1))\ + field = true;\ + lua_pop(gL, 1); + + CHECKFIELD(forward) + CHECKFIELD(backward) + CHECKFIELD(left) + CHECKFIELD(right) + CHECKFIELD(strafeleft) + CHECKFIELD(straferight) + CHECKFIELD(jump) + CHECKFIELD(spin) +#undef CHECKFIELD + B_KeysToTiccmd(tails, cmd, forward, backward, left, right, strafeleft, straferight, jump, spin); + } else + B_KeysToTiccmd(tails, cmd, lua_toboolean(gL, 2+1), lua_toboolean(gL, 2+2), lua_toboolean(gL, 2+3), lua_toboolean(gL, 2+4), lua_toboolean(gL, 2+5), lua_toboolean(gL, 2+6), lua_toboolean(gL, 2+7), lua_toboolean(gL, 2+8)); + + lua_pop(gL, 8); + hooked = true; + } lua_settop(gL, 0); return hooked; @@ -949,22 +988,24 @@ boolean LUAh_LinedefExecute(line_t *line, mobj_t *mo, sector_t *sector) lua_settop(gL, 0); for (hookp = linedefexecutorhooks; hookp; hookp = hookp->next) - if (!strcmp(hookp->s.funcname, line->text)) + { + if (strcmp(hookp->s.funcname, line->text)) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, line, META_LINE); - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, sector, META_SECTOR); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - lua_pushvalue(gL, -4); - LUA_Call(gL, 3); - hooked = true; + LUA_PushUserdata(gL, line, META_LINE); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, sector, META_SECTOR); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + lua_pushvalue(gL, -4); + LUA_Call(gL, 3); + hooked = true; + } lua_settop(gL, 0); return hooked; @@ -981,43 +1022,45 @@ boolean LUAh_PlayerMsg(int source, int target, int flags, char *msg) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerMsg) + { + if (hookp->type != hook_PlayerMsg) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player - if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c - lua_pushinteger(gL, 3); // type - lua_pushnil(gL); // target - } else if (target == -1) { // sayteam - lua_pushinteger(gL, 1); // type - lua_pushnil(gL); // target - } else if (target == 0) { // say - lua_pushinteger(gL, 0); // type - lua_pushnil(gL); // target - } else { // sayto - lua_pushinteger(gL, 2); // type - LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target - } - lua_pushstring(gL, msg); // msg + LUA_PushUserdata(gL, &players[source], META_PLAYER); // Source player + if (flags & 2 /*HU_CSAY*/) { // csay TODO: make HU_CSAY accessible outside hu_stuff.c + lua_pushinteger(gL, 3); // type + lua_pushnil(gL); // target + } else if (target == -1) { // sayteam + lua_pushinteger(gL, 1); // type + lua_pushnil(gL); // target + } else if (target == 0) { // say + lua_pushinteger(gL, 0); // type + lua_pushnil(gL); // target + } else { // sayto + lua_pushinteger(gL, 2); // type + LUA_PushUserdata(gL, &players[target-1], META_PLAYER); // target } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + lua_pushstring(gL, msg); // msg } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1035,33 +1078,35 @@ boolean LUAh_HurtMsg(player_t *player, mobj_t *inflictor, mobj_t *source, UINT8 lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_HurtMsg - && (hookp->s.mt == MT_NULL || (inflictor && hookp->s.mt == inflictor->type))) + { + if (hookp->type != hook_HurtMsg + || (hookp->s.mt && !(inflictor && hookp->s.mt == inflictor->type))) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, inflictor, META_MOBJ); - LUA_PushUserdata(gL, source, META_MOBJ); - lua_pushinteger(gL, damagetype); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - lua_pushvalue(gL, -5); - if (lua_pcall(gL, 4, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, inflictor, META_MOBJ); + LUA_PushUserdata(gL, source, META_MOBJ); + lua_pushinteger(gL, damagetype); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + lua_pushvalue(gL, -5); + if (lua_pcall(gL, 4, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1084,13 +1129,15 @@ void LUAh_NetArchiveHook(lua_CFunction archFunc) // stack: tables, archFunc for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_NetVars) - { - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -2); // archFunc - LUA_Call(gL, 1); - } + { + if (hookp->type != hook_NetVars) + continue; + + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -2); // archFunc + LUA_Call(gL, 1); + } lua_pop(gL, 1); // pop archFunc // stack: tables @@ -1107,52 +1154,56 @@ boolean LUAh_MapThingSpawn(mobj_t *mo, mapthing_t *mthing) // Look for all generic mobj map thing spawn hooks for (hookp = mobjhooks[MT_NULL]; hookp; hookp = hookp->next) - if (hookp->type == hook_MapThingSpawn) + { + if (hookp->type != hook_MapThingSpawn) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, mthing, META_MAPTHING); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, mthing, META_MAPTHING); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } for (hookp = mobjhooks[mo->type]; hookp; hookp = hookp->next) - if (hookp->type == hook_MapThingSpawn) + { + if (hookp->type != hook_MapThingSpawn) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, mo, META_MOBJ); - LUA_PushUserdata(gL, mthing, META_MAPTHING); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, mo, META_MOBJ); + LUA_PushUserdata(gL, mthing, META_MAPTHING); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; @@ -1169,33 +1220,80 @@ boolean LUAh_FollowMobj(player_t *player, mobj_t *mobj) lua_settop(gL, 0); for (hookp = playerhooks; hookp; hookp = hookp->next) - if (hookp->type == hook_FollowMobj) + { + if (hookp->type != hook_FollowMobj) + continue; + + if (lua_gettop(gL) == 0) { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, player, META_PLAYER); - LUA_PushUserdata(gL, mobj, META_MOBJ); - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - if (lua_pcall(gL, 2, 1, 0)) { - if (!hookp->error || cv_debug & DBG_LUA) - CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); - lua_pop(gL, 1); - hookp->error = true; - continue; - } - if (lua_toboolean(gL, -1)) - hooked = true; - lua_pop(gL, 1); + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (lua_toboolean(gL, -1)) + hooked = true; + lua_pop(gL, 1); + } lua_settop(gL, 0); return hooked; } +// Hook for P_PlayerCanDamage +UINT8 LUAh_PlayerCanDamage(player_t *player, mobj_t *mobj) +{ + hook_p hookp; + UINT8 shouldCollide = 0; // 0 = default, 1 = force yes, 2 = force no. + if (!gL || !(hooksAvailable[hook_PlayerCanDamage/8] & (1<<(hook_PlayerCanDamage%8)))) + return 0; + + lua_settop(gL, 0); + + for (hookp = playerhooks; hookp; hookp = hookp->next) + { + if (hookp->type != hook_PlayerCanDamage) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, player, META_PLAYER); + LUA_PushUserdata(gL, mobj, META_MOBJ); + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + if (lua_pcall(gL, 2, 1, 0)) { + if (!hookp->error || cv_debug & DBG_LUA) + CONS_Alert(CONS_WARNING,"%s\n",lua_tostring(gL, -1)); + lua_pop(gL, 1); + hookp->error = true; + continue; + } + if (!lua_isnil(gL, -1)) + { // if nil, leave shouldCollide = 0. + if (lua_toboolean(gL, -1)) + shouldCollide = 1; // Force yes + else + shouldCollide = 2; // Force no + } + lua_pop(gL, 1); + } + + lua_settop(gL, 0); + return shouldCollide; +} + void LUAh_PlayerQuit(player_t *plr, int reason) { hook_p hookp; @@ -1205,19 +1303,21 @@ void LUAh_PlayerQuit(player_t *plr, int reason) lua_settop(gL, 0); for (hookp = roothook; hookp; hookp = hookp->next) - if (hookp->type == hook_PlayerQuit) - { - if (lua_gettop(gL) == 0) - { - LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit - lua_pushinteger(gL, reason); // Reason for quitting - } - lua_pushfstring(gL, FMT_HOOKID, hookp->id); - lua_gettable(gL, LUA_REGISTRYINDEX); - lua_pushvalue(gL, -3); - lua_pushvalue(gL, -3); - LUA_Call(gL, 2); - } + { + if (hookp->type != hook_PlayerQuit) + continue; + + if (lua_gettop(gL) == 0) + { + LUA_PushUserdata(gL, plr, META_PLAYER); // Player that quit + lua_pushinteger(gL, reason); // Reason for quitting + } + lua_pushfstring(gL, FMT_HOOKID, hookp->id); + lua_gettable(gL, LUA_REGISTRYINDEX); + lua_pushvalue(gL, -3); + lua_pushvalue(gL, -3); + LUA_Call(gL, 2); + } lua_settop(gL, 0); } diff --git a/src/lua_hudlib.c b/src/lua_hudlib.c index f3a1ba210..8c1134bca 100644 --- a/src/lua_hudlib.c +++ b/src/lua_hudlib.c @@ -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 { diff --git a/src/lua_mobjlib.c b/src/lua_mobjlib.c index 0835e5cc0..0a3d356c9 100644 --- a/src/lua_mobjlib.c +++ b/src/lua_mobjlib.c @@ -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)); diff --git a/src/m_menu.c b/src/m_menu.c index cebdd1bbd..dca2e552d 100644 --- a/src/m_menu.c +++ b/src/m_menu.c @@ -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 diff --git a/src/p_enemy.c b/src/p_enemy.c index 175431df5..fb2cd5729 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -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]); diff --git a/src/p_inter.c b/src/p_inter.c index 3e1b74e56..3136a04fa 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -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) diff --git a/src/p_local.h b/src/p_local.h index a92640c76..5216286c0 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -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 diff --git a/src/p_map.c b/src/p_map.c index 86fa68ad8..e78dd1e84 100644 --- a/src/p_map.c +++ b/src/p_map.c @@ -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< 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; } } diff --git a/src/p_mobj.c b/src/p_mobj.c index dd7479060..a59e1b807 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -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)<info->spawnhealth<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); diff --git a/src/p_mobj.h b/src/p_mobj.h index 936be3bb0..bfcb09210 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -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; diff --git a/src/p_saveg.c b/src/p_saveg.c index 664aa2f64..06baa9528 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -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) { diff --git a/src/p_setup.c b/src/p_setup.c index e7dc271a4..7aaad233d 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -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) { diff --git a/src/p_slopes.c b/src/p_slopes.c index 8f9489100..d6080c15d 100644 --- a/src/p_slopes.c +++ b/src/p_slopes.c @@ -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; diff --git a/src/p_spec.c b/src/p_spec.c index 6c65da8f0..3dd3b22bb 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -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(§ors[sec], §ors[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(§ors[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; - } - } -} +} \ No newline at end of file diff --git a/src/p_user.c b/src/p_user.c index 9e84d0339..a093196b3 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -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); } } diff --git a/src/r_draw.c b/src/r_draw.c index 13ac691d5..f8e435624 100644 --- a/src/r_draw.c +++ b/src/r_draw.c @@ -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) diff --git a/src/r_draw.h b/src/r_draw.h index 0c04fee2a..82498eb11 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -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); diff --git a/src/r_things.c b/src/r_things.c index 50ee8e6ef..155d0f83f 100644 --- a/src/r_things.c +++ b/src/r_things.c @@ -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; diff --git a/src/sounds.c b/src/sounds.c index de043493a..11ba1e0bc 100644 --- a/src/sounds.c +++ b/src/sounds.c @@ -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"}, diff --git a/src/sounds.h b/src/sounds.h index a9f28ffb2..20f89d9fb 100644 --- a/src/sounds.h +++ b/src/sounds.h @@ -264,6 +264,7 @@ typedef enum sfx_bowl, sfx_chuchu, sfx_bsnipe, + sfx_sprong, // Menu, interface sfx_chchng, diff --git a/src/st_stuff.c b/src/st_stuff.c index 9620681d5..132eada06 100644 --- a/src/st_stuff.c +++ b/src/st_stuff.c @@ -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;