From a4fcf9ee2bc936cf42a65c24465d003a794f525b Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 24 Nov 2019 21:21:15 +0100 Subject: [PATCH 01/22] - fixed savegame writing for Ion Fury. The composite's writers may not be deleted, they are needed for creating the final savegame file. --- source/duke3d/src/player.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/source/duke3d/src/player.cpp b/source/duke3d/src/player.cpp index 461530148..9b354139e 100644 --- a/source/duke3d/src/player.cpp +++ b/source/duke3d/src/player.cpp @@ -5731,7 +5731,6 @@ int portableBackupSave(const char * path, const char * name, int volume, int lev } fil->Write(encoded, strlen(encoded)); - delete fil; sjson_free_string(ctx, encoded); sjson_destroy_context(ctx); From 6e3bd75b1affce7ef958ed4ab9dd949206074281 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Sun, 24 Nov 2019 19:07:23 +0100 Subject: [PATCH 02/22] - fixed Blood fullscreen tinting. The lookup table for blend equations was missing one entry at the start. No idea why this became apparent only now. --- source/glbackend/glbackend.cpp | 2 +- source/glbackend/hw_draw2d.cpp | 2 +- .../demolition/shaders/glsl/polymost.fpp | 235 ------------------ 3 files changed, 2 insertions(+), 237 deletions(-) delete mode 100644 wadsrc/static/demolition/shaders/glsl/polymost.fpp diff --git a/source/glbackend/glbackend.cpp b/source/glbackend/glbackend.cpp index 7201c5406..4b222a273 100644 --- a/source/glbackend/glbackend.cpp +++ b/source/glbackend/glbackend.cpp @@ -427,7 +427,7 @@ void GLInstance::SetBlendFunc(int src, int dst) glBlendFunc(blendstyles[src], blendstyles[dst]); } -static int renderops[] = { GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT }; +static int renderops[] = { GL_FUNC_ADD, GL_FUNC_ADD, GL_FUNC_SUBTRACT, GL_FUNC_REVERSE_SUBTRACT }; void GLInstance::SetBlendOp(int op) { diff --git a/source/glbackend/hw_draw2d.cpp b/source/glbackend/hw_draw2d.cpp index 46b278652..68e62bd9b 100644 --- a/source/glbackend/hw_draw2d.cpp +++ b/source/glbackend/hw_draw2d.cpp @@ -264,7 +264,7 @@ void fullscreen_tint_gl_blood(int tint_blood_r, int tint_blood_g, int tint_blood vt[2].Set(.0f, -2.5f); GLInterface.Draw(DT_TRIANGLES, data.first, 3); GLInterface.SetBlendOp(STYLEOP_Add); - GLInterface.SetColorub(0, 0, 0, 0); + GLInterface.SetColorub(255, 255, 255, 255); GLInterface.SetBlendFunc(STYLEALPHA_Src, STYLEALPHA_InvSrc); GLInterface.UseColorOnly(false); diff --git a/wadsrc/static/demolition/shaders/glsl/polymost.fpp b/wadsrc/static/demolition/shaders/glsl/polymost.fpp deleted file mode 100644 index e9dba291b..000000000 --- a/wadsrc/static/demolition/shaders/glsl/polymost.fpp +++ /dev/null @@ -1,235 +0,0 @@ -#version 330 - -const int RF_ColorOnly = 1; -const int RF_UsePalette = 2; -const int RF_DetailMapping = 4; -const int RF_GlowMapping = 8; -const int RF_Brightmapping = 16; -const int RF_NPOTEmulation = 32; -const int RF_ShadeInterpolate = 64; -const int RF_FogDisabled = 128; - -const int RF_HICTINT_Grayscale = 0x10000; -const int RF_HICTINT_Invert = 0x20000; -const int RF_HICTINT_Colorize = 0x40000; -const int RF_HICTINT_BLEND_Screen = 0x80000; -const int RF_HICTINT_BLEND_Overlay = 0x100000; -const int RF_HICTINT_BLEND_Hardlight = 0x200000; -const int RF_HICTINT_BLENDMASK = RF_HICTINT_BLEND_Screen | RF_HICTINT_BLEND_Overlay | RF_HICTINT_BLEND_Hardlight; - - -//s_texture points to an indexed color texture -uniform sampler2D s_texture; -//s_palswap is the palette swap texture where u is the color index and v is the shade -uniform sampler2D s_palswap; -//s_palette is the base palette texture where u is the color index -uniform sampler2D s_palette; - -uniform sampler2D s_detail; -uniform sampler2D s_glow; -uniform sampler2D s_brightmap; - -uniform float u_shade; -uniform float u_numShades; -uniform float u_shadeDiv; -uniform float u_visFactor; -uniform int u_flags; -uniform float u_alphaThreshold; - -uniform float u_npotEmulationFactor; -uniform float u_npotEmulationXOffset; -uniform float u_brightness; -uniform vec4 u_fogColor; -uniform vec3 u_tintcolor; -uniform vec3 u_tintmodulate; - -in vec4 v_color; -in float v_distance; -in vec4 v_texCoord; -in vec4 v_detailCoord; -in float v_fogCoord; - -const float c_basepalScale = 255.0/256.0; -const float c_basepalOffset = 0.5/256.0; - -const float c_zero = 0.0; -const float c_one = 1.0; -const float c_two = 2.0; -const vec4 c_vec4_one = vec4(c_one); -const float c_wrapThreshold = 0.9; - -layout(location=0) out vec4 fragColor; - -//=========================================================================== -// -// Color to grayscale -// -//=========================================================================== - -float grayscale(vec4 color) -{ - return dot(color.rgb, vec3(0.3, 0.56, 0.14)); -} - -//=========================================================================== -// -// Hightile tinting code. (hictinting[dapalnum]) This can be done inside the shader -// to avoid costly texture duplication (but needs a more modern GLSL than 1.10.) -// -//=========================================================================== - -vec4 convertColor(vec4 color, int effect, vec3 tint) -{ -#if 0 - - if (effect & RF_HICTINT_Grayscale) - { - float g = grayscale(color); - color = vec4(g, g, g, color.a); - } - - if (effect & RF_HICTINT_Invert) - { - color = vec4(1.0 - color.r, 1.0 - color.g, 1.0 - color.b); - } - - vec3 tcol = color.rgb * 255.0; // * 255.0 to make it easier to reuse the integer math. - tint *= 255.0; - - if (effect & RF_HICTINT_Colorize) - { - tcol.b = min(((tcol.b) * tint.r) / 64.0, 255.0); - tcol.g = min(((tcol.g) * tint.g) / 64.0, 255.0); - tcol.r = min(((tcol.r) * tint.b) / 64.0, 255.0); - } - - switch (effect & RF_HICTINT_BLENDMASK) - { - case RF_HICTINT_BLEND_Screen: - tcol.b = 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 256.0); - tcol.g = 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 256.0); - tcol.r = 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 256.0); - break; - case RF_HICTINT_BLEND_Overlay: - tcol.b = tcol.b < 128.0? (tcol.b * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - tint.r)) / 128.0); - tcol.g = tcol.g < 128.0? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - tint.g)) / 128.0); - tcol.r = tcol.r < 128.0? (tcol.r * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - tint.b)) / 128.0); - break; - case RF_HICTINT_BLEND_Hardlight: - tcol.b = tint.r < 128.0 ? (tcol.b * tint.r) / 128.0 : 255.0 - (((255.0 - tcol.b) * (255.0 - r)) / 128.0); - tcol.g = tint.g < 128.0 ? (tcol.g * tint.g) / 128.0 : 255.0 - (((255.0 - tcol.g) * (255.0 - g)) / 128.0); - tcol.r = tint.b < 128.0 ? (tcol.r * tint.b) / 128.0 : 255.0 - (((255.0 - tcol.r) * (255.0 - b)) / 128.0); - break; - } - color.rgb = tcol / 255.0; -#endif - return color; -} - -//=========================================================================== -// -// -// -//=========================================================================== - -void main() -{ - float fullbright = 0.0; - vec4 color; - if ((u_flags & RF_ColorOnly) == 0) - { - float coordX = v_texCoord.x; - float coordY = v_texCoord.y; - vec2 newCoord; - - // Coordinate adjustment for NPOT textures (something must have gone very wrong to make this necessary...) - if ((u_flags & RF_NPOTEmulation) != 0) - { - float period = floor(coordY / u_npotEmulationFactor); - coordX += u_npotEmulationXOffset * floor(mod(coordY, u_npotEmulationFactor)); - coordY = period + mod(coordY, u_npotEmulationFactor); - } - newCoord = vec2(coordX, coordY); - - // Paletted textures are stored in column major order rather than row major so coordinates need to be swapped here. - color = texture2D(s_texture, newCoord); - - // This was further down but it really should be done before applying any kind of depth fading, not afterward. - vec4 detailColor = vec4(1.0); - if ((u_flags & RF_DetailMapping) != 0) - { - detailColor = texture2D(s_detail, v_detailCoord.xy); - detailColor = mix(vec4(1.0), 2.0 * detailColor, detailColor.a); - // Application of this differs based on render mode because for paletted rendering with palettized shade tables it can only be done after processing the shade table. We only have a palette index before. - } - - float visibility = max(u_visFactor * v_distance - ((u_flags & RF_ShadeInterpolate) != 0.0? 0.5 : 0.0), 0.0); - float shade = clamp((u_shade + visibility), 0.0, u_numShades - 1.0); - - - if ((u_flags & RF_UsePalette) != 0) - { - int palindex = int(color.r * 255.0 + 0.1); // The 0.1 is for roundoff error compensation. - int shadeindex = int(floor(shade)); - float colorIndexF = texelFetch(s_palswap, ivec2(palindex, shadeindex), 0).r; - int colorIndex = int(colorIndexF * 255.0 + 0.1); // The 0.1 is for roundoff error compensation. - vec4 palettedColor = texelFetch(s_palette, ivec2(colorIndex, 0), 0); - - if ((u_flags & RF_ShadeInterpolate) != 0) - { - // Get the next shaded palette index for interpolation - colorIndexF = texelFetch(s_palswap, ivec2(palindex, shadeindex+1), 0).r; - colorIndex = int(colorIndexF * 255.0 + 0.1); // The 0.1 is for roundoff error compensation. - vec4 palettedColorNext = texelFetch(s_palette, ivec2(colorIndex, 0), 0); - float shadeFrac = mod(shade, 1.0); - palettedColor.rgb = mix(palettedColor.rgb, palettedColorNext.rgb, shadeFrac); - } - - fullbright = palettedColor.a; // This only gets set for paletted rendering. - palettedColor.a = c_one-floor(color.r); - color = palettedColor; - color.rgb *= detailColor.rgb; // with all this palettizing, this can only be applied afterward, even though it is wrong to do it this way. - if (fullbright == 0.0) color.rgb *= v_color.rgb; // Well, this is dead wrong but unavoidable. For colored fog it applies the light to the fog as well... - } - else - { - color.rgb *= detailColor.rgb; - - shade = clamp(shade * u_shadeDiv, 0.0, 1.0); // u_shadeDiv is really 1/shadeDiv. - vec3 lightcolor = v_color.rgb; - if ((u_flags & RF_FogDisabled) == 0) - { - lightcolor *= shade; - } - if ((u_flags & RF_Brightmapping) != 0) - { - vec4 brightcolor = texture2D(s_brightmap, v_texCoord.xy); - lightcolor = clamp(brightcolor.rgb + lightcolor, 0.0, 1.0); - } - color.rgb *= lightcolor; - - if ((u_flags & RF_FogDisabled) == 0 && u_fogColor.rgb != vec3(0)) - { - // Apply the shade as a linear depth fade ramp. - color.rgb += u_fogColor.rgb * (1.0 - shade); - } - } - if (color.a < u_alphaThreshold) discard; // it's only here that we have the alpha value available to be able to perform the alpha test. - - color.a *= v_color.a; - } - else - { - // untextured rendering - color = v_color; - } - - if ((u_flags & (RF_ColorOnly|RF_GlowMapping)) == RF_GlowMapping) - { - vec4 glowColor = texture2D(s_glow, v_texCoord.xy); - color.rgb = mix(color.rgb, glowColor.rgb, glowColor.a); - } - - color.rgb = pow(color.rgb, vec3(u_brightness)); - fragColor = color; -} From 0dbf3bbb1ea6be204d9cf9ac1206ddc48c70ddfe Mon Sep 17 00:00:00 2001 From: Grind Core Date: Sun, 24 Nov 2019 23:53:51 +0300 Subject: [PATCH 03/22] - Custom Dude updates and refactor - Player Control updates - Minor modern types updates - There was removed GDX prefix for all modern stuff # Conflicts: # source/blood/src/aiunicult.cpp # source/blood/src/aiunicult.h # source/blood/src/mapedit.cpp # source/blood/src/player.h # source/blood/src/sfx.h --- source/blood/src/actor.cpp | 126 +++-- source/blood/src/ai.cpp | 260 ++++----- source/blood/src/ai.h | 16 +- source/blood/src/aiburn.cpp | 20 +- source/blood/src/aiburn.h | 10 +- source/blood/src/aiunicult.cpp | 984 +++++++++++++++++++++------------ source/blood/src/aiunicult.h | 131 +++-- source/blood/src/blood.cpp | 1 + source/blood/src/callback.cpp | 8 + source/blood/src/callback.h | 1 + source/blood/src/common_game.h | 21 +- source/blood/src/db.h | 6 +- source/blood/src/dude.cpp | 6 +- source/blood/src/endgame.cpp | 39 -- source/blood/src/eventq.cpp | 8 +- source/blood/src/eventq.h | 78 +-- source/blood/src/levels.cpp | 2 +- source/blood/src/player.cpp | 34 +- source/blood/src/player.h | 6 +- source/blood/src/seq.h | 2 +- source/blood/src/sfx.cpp | 22 - source/blood/src/sfx.h | 25 + source/blood/src/triggers.cpp | 204 ++++--- 23 files changed, 1185 insertions(+), 825 deletions(-) diff --git a/source/blood/src/actor.cpp b/source/blood/src/actor.cpp index e49b40984..cf68e2570 100644 --- a/source/blood/src/actor.cpp +++ b/source/blood/src/actor.cpp @@ -2737,7 +2737,7 @@ void actInit(bool bSaveLoad) { case kDudeModernCustom: case kDudeModernCustomBurning: pSprite->cstat |= 4096 + CSTAT_SPRITE_BLOCK_HITSCAN + CSTAT_SPRITE_BLOCK; - seqStartId = getSeqStartId(pXSprite); // by NoOne: Custom Dude stores it's SEQ in data2 + seqStartId = genDudeSeqStartId(pXSprite); // by NoOne: Custom Dude stores it's SEQ in data2 pXSprite->sysData1 = pXSprite->data3; // by NoOne move sndStartId to sysData1, because data3 used by the game; pXSprite->data3 = 0; break; @@ -3127,10 +3127,10 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) && pXSprite->medium == kMediumNormal) { if (gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) { pSprite->type = kDudeModernCustomBurning; - if (pXSprite->data2 == kDefaultAnimationBase) // don't inherit palette for burning if using default animation + if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation pSprite->pal = 0; - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); + aiGenDudeNewState(pSprite, &genDudeBurnGoto); actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth); if (pXSprite->burnTime <= 0) pXSprite->burnTime = 1200; gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; @@ -3147,7 +3147,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, } else { pXSprite->locked = 1; // lock while transforming - + aiSetGenIdleState(pSprite, pXSprite); // set idle state if (pXSprite->key > 0) // drop keys @@ -3156,13 +3156,13 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, if (pXSprite->dropMsg > 0) // drop items actDropObject(pSprite, pXSprite->dropMsg); - + pSprite->flags &= ~kPhysMove; xvel[pSprite->index] = yvel[pSprite->index] = 0; int seqId = pXSprite->data2 + 18; if (!gSysRes.Lookup(seqId, "SEQ")) { seqKill(3, nXSprite); - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTransforming); + playGenDudeSound(pSprite, kGenDudeSndTransforming); spritetype* pEffect = gFX.fxSpawn((FX_ID)52, pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z, pSprite->ang); if (pEffect != NULL) { pEffect->cstat = CSTAT_SPRITE_ALIGNMENT_FACING; @@ -3187,7 +3187,10 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, return; } seqSpawn(seqId, 3, nXSprite, -1); - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTransforming); + playGenDudeSound(pSprite, kGenDudeSndTransforming); + + pXSprite->sysData1 = kGenDudeTransformStatus; // in transform + return; } break; @@ -3287,7 +3290,7 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, switch (pSprite->type) { case kDudeModernCustom: case kDudeModernCustomBurning: - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndDeathExplode); + playGenDudeSound(pSprite, kGenDudeSndDeathExplode); break; case kDudeCultistTommy: case kDudeCultistShotgun: @@ -3406,26 +3409,25 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, seqSpawn(dudeInfo[nType].seqStartID+15, 3, nXSprite, nDudeToGibClient2); break; case kDudeModernCustom: - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndDeathNormal); + playGenDudeSound(pSprite, kGenDudeSndDeathNormal); if (nSeq == 3) { - bool seq15 = gSysRes.Lookup(pXSprite->data2 + 15, "SEQ"); bool seq16 = gSysRes.Lookup(pXSprite->data2 + 16, "SEQ"); - if (seq15 && seq16) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); - else if (seq16) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); - else if (seq15) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); - else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ")) seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); - else seqKill(3, nXSprite); + GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); + if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else if (gSysRes.Lookup(pXSprite->data2 + nSeq, "SEQ"))seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); + else seqSpawn(1 + pXSprite->data2, 3, nXSprite, nDudeToGibClient2); } else { seqSpawn(nSeq + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); - } + } pXSprite->txID = 0; // to avoid second trigger. break; - case kDudeModernCustomBurning: - { - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndDeathExplode); + case kDudeModernCustomBurning: { + playGenDudeSound(pSprite, kGenDudeSndDeathExplode); damageType = DAMAGE_TYPE_3; if (Chance(0x4000)) { @@ -3436,14 +3438,11 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, GibSprite(pSprite, GIBTYPE_7, &gibPos, &gibVel); } - int seqId = pXSprite->data2; - bool seq15 = gSysRes.Lookup(pXSprite->data2 + 15, "SEQ"); bool seq16 = gSysRes.Lookup(pXSprite->data2 + 16, "SEQ"); - - if (seq15 && seq16) seqId += (15 + Random(2)); - else if (seq16) seqId += 16; - else seqId += 15; - - seqSpawn(seqId, 3, nXSprite, nDudeToGibClient1); + GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); + if (pExtra->availDeaths[kDmgBurn] == 3) seqSpawn((15 + Random(2)) + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); + else if (pExtra->availDeaths[kDmgBurn] == 2) seqSpawn(16 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); + else if (pExtra->availDeaths[kDmgBurn] == 1) seqSpawn(15 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); + else seqSpawn(1 + pXSprite->data2, 3, nXSprite, nDudeToGibClient1); break; } case kDudeBurningZombieAxe: @@ -3571,29 +3570,37 @@ void actKillDude(int nKillerSprite, spritetype *pSprite, DAMAGE_TYPE damageType, seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); break; case kDudePodGreen: - if (Chance(0x4000) && nSeq == 3) - sfxPlay3DSound(pSprite, 2205, -1, 0); - else - sfxPlay3DSound(pSprite, 2203+Random(2), -1, 0); - seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); - break; case kDudeTentacleGreen: - if (damage == 5) - sfxPlay3DSound(pSprite, 2471, -1, 0); - else - sfxPlay3DSound(pSprite, 2472, -1, 0); - seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); - break; case kDudePodFire: - if (damage == 5) - sfxPlay3DSound(pSprite, 2451, -1, 0); - else - sfxPlay3DSound(pSprite, 2452, -1, 0); - seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); - break; case kDudeTentacleFire: - sfxPlay3DSound(pSprite, 2501, -1, 0); - seqSpawn(dudeInfo[nType].seqStartID+nSeq, 3, nXSprite, -1); + if ((pSprite->cstat & CSTAT_SPRITE_YFLIP)) pSprite->cstat &= ~CSTAT_SPRITE_YFLIP; + switch (pSprite->type) { + case kDudePodGreen: + if (Chance(0x4000) && nSeq == 3) + sfxPlay3DSound(pSprite, 2205, -1, 0); + else + sfxPlay3DSound(pSprite, 2203 + Random(2), -1, 0); + seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1); + break; + case kDudeTentacleGreen: + if (damage == 5) + sfxPlay3DSound(pSprite, 2471, -1, 0); + else + sfxPlay3DSound(pSprite, 2472, -1, 0); + seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1); + break; + case kDudePodFire: + if (damage == 5) + sfxPlay3DSound(pSprite, 2451, -1, 0); + else + sfxPlay3DSound(pSprite, 2452, -1, 0); + seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1); + break; + case kDudeTentacleFire: + sfxPlay3DSound(pSprite, 2501, -1, 0); + seqSpawn(dudeInfo[nType].seqStartID + nSeq, 3, nXSprite, -1); + break; + } break; case kDudePodMother: if (Chance(0x4000) && nSeq == 3) @@ -4717,7 +4724,10 @@ void MoveDude(spritetype *pSprite) PLAYER *pPlayer = NULL; if (IsPlayerSprite(pSprite)) pPlayer = &gPlayer[pSprite->type-kDudePlayer1]; - dassert(pSprite->type >= kDudeBase && pSprite->type < kDudeMax); + if (!(pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) { + consoleSysMsg("pSprite->type >= kDudeBase && pSprite->type < kDudeMax"); + return; + } DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; int top, bottom; GetSpriteExtents(pSprite, &top, &bottom); @@ -6141,9 +6151,10 @@ void actProcessSprites(void) } // By NoOne: handle incarnations of custom dude - if (pSprite->type == kDudeModernCustom && pXSprite->txID > 0 && pXSprite->health <= 0 && seqGetStatus(3, nXSprite) < 0) { + if (pSprite->type == kDudeModernCustom && pXSprite->txID > 0 && pXSprite->health <= 0 && pXSprite->sysData1 == kGenDudeTransformStatus) { + xvel[pSprite->index] = ClipLow(xvel[pSprite->index] >> 4, 0); yvel[pSprite->index] = ClipLow(yvel[pSprite->index] >> 4, 0); XSPRITE* pXIncarnation = getNextIncarnation(pXSprite); - if (pXIncarnation != NULL) { + if (seqGetStatus(3, nXSprite) < 0 && pXIncarnation != NULL) { spritetype* pIncarnation = &sprite[pXIncarnation->reference]; pXSprite->key = pXSprite->dropMsg = pXSprite->locked = 0; @@ -6158,7 +6169,6 @@ void actProcessSprites(void) // trigger dude death before transform trTriggerSprite(nSprite, pXSprite, kCmdOff, pSprite->owner); - pSprite->type = pIncarnation->type; pSprite->flags = pIncarnation->flags; pSprite->pal = pIncarnation->pal; @@ -6211,8 +6221,8 @@ void actProcessSprites(void) break; case kDudeModernCustom: case kDudeModernCustomBurning: - seqId = getSeqStartId(pXSprite); - getSpriteMassBySize(pSprite); // create or refresh mass cache + seqId = genDudeSeqStartId(pXSprite); + genDudePrepare(pSprite, kGenDudePropertyMass); fallthrough__; // go below default: seqSpawn(seqId, 3, nXSprite, -1); @@ -7510,7 +7520,7 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) { pXDude->data3 = 0; // spawn seq - seqSpawn(getSeqStartId(pXDude), 3, pDude->extra, -1); + seqSpawn(genDudeSeqStartId(pXDude), 3, pDude->extra, -1); // inherit movement speed. pXDude->busyTime = pXSource->busyTime; @@ -7550,6 +7560,12 @@ spritetype* actSpawnCustomDude(spritetype* pSprite, int nDist) { } } + // inherit sprite size (useful for seqs with zero repeats) + if (pSource->flags & kModernTypeFlag2) { + pDude->xrepeat = pSource->xrepeat; + pDude->yrepeat = pSource->yrepeat; + } + aiInitSprite(pDude); return pDude; } @@ -7650,7 +7666,7 @@ int getSpriteMassBySize(spritetype* pSprite) { cached->picnum = pSprite->picnum; cached->seqId = seqId; cached->clipdist = pSprite->clipdist; - viewSetSystemMessage("MASS: %d", cached->mass); + //viewSetSystemMessage("MASS: %d", cached->mass); return cached->mass; } diff --git a/source/blood/src/ai.cpp b/source/blood/src/ai.cpp index bf54680de..75ab9ab5f 100644 --- a/source/blood/src/ai.cpp +++ b/source/blood/src/ai.cpp @@ -110,25 +110,20 @@ void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4) void aiNewState(spritetype *pSprite, XSPRITE *pXSprite, AISTATE *pAIState) { DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; - pXSprite->stateTimer = pAIState->at8; + pXSprite->stateTimer = pAIState->stateTicks; pXSprite->aiState = pAIState; int seqStartId = pDudeInfo->seqStartID; - if (pAIState->at0 >= 0) { - // By NoOne: Custom dude uses data2 to keep it's seqStartId - switch (pSprite->type) { - case kDudeModernCustom: - case kDudeModernCustomBurning: - seqStartId = pXSprite->data2; - break; - } - seqStartId += pAIState->at0; + if (pAIState->seqId >= 0) { + seqStartId += pAIState->seqId; if (gSysRes.Lookup(seqStartId, "SEQ")) - seqSpawn(seqStartId, 3, pSprite->extra, pAIState->at4); + seqSpawn(seqStartId, 3, pSprite->extra, pAIState->funcId); } - if (pAIState->atc) pAIState->atc(pSprite, pXSprite); // entry function + if (pAIState->enterFunc) + pAIState->enterFunc(pSprite, pXSprite); } + bool dudeIsImmune(spritetype* pSprite, int dmgType) { if (dmgType < 0 || dmgType > 6) return true; else if (dudeInfo[pSprite->type - kDudeBase].startDamage[dmgType] == 0) return true; @@ -417,31 +412,18 @@ void aiActivateDude(spritetype *pSprite, XSPRITE *pXSprite) pDudeExtraE->at8 = 1; pDudeExtraE->at0 = 0; if (pXSprite->target == -1) { - if (spriteIsUnderwater(pSprite, false)) - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - else { - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); - if (Chance(0x4000)) - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTargetSpot); - } - } - else { - if (Chance(0x4000)) - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTargetSpot); - - if (spriteIsUnderwater(pSprite, false)) - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchW); + else aiGenDudeNewState(pSprite, &genDudeSearchL); + } else { + if (Chance(0x4000)) playGenDudeSound(pSprite, kGenDudeSndTargetSpot); + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseW); + else aiGenDudeNewState(pSprite, &genDudeChaseL); } break; } case kDudeModernCustomBurning: - if (pXSprite->target == -1) - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); - else - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnChase); + if (pXSprite->target == -1) aiGenDudeNewState(pSprite, &genDudeBurnSearch); + else aiGenDudeNewState(pSprite, &genDudeBurnChase); break; case kDudeCultistTommyProne: { DUDEEXTRA_at6_u1 *pDudeExtraE = &gDudeExtra[pSprite->extra].at6.u1; @@ -1026,7 +1008,7 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T break; case kDudeModernCustomBurning: if (Chance(0x2000) && gDudeExtra[pSprite->extra].at0 < (int)gFrameClock) { - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndBurning); + playGenDudeSound(pSprite, kGenDudeSndBurning); gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; } if (pXSprite->burnTime == 0) pXSprite->burnTime = 2400; @@ -1034,63 +1016,61 @@ int aiDamageSprite(spritetype *pSprite, XSPRITE *pXSprite, int nSource, DAMAGE_T pSprite->type = kDudeModernCustom; pXSprite->burnTime = 0; pXSprite->health = 1; // so it can be killed with flame weapons while underwater and if already was burning dude before. - aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); + aiGenDudeNewState(pSprite, &genDudeGotoW); } break; - case kDudeModernCustom: - { + case kDudeModernCustom: { + GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); + if (nDmgType == DAMAGE_TYPE_1) { - if (pXSprite->health <= pDudeInfo->fleeHealth) { - if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) { - removeDudeStuff(pSprite); + if (pXSprite->health > pDudeInfo->fleeHealth) break; + else if (pXSprite->txID <= 0 || getNextIncarnation(pXSprite) == NULL) { + removeDudeStuff(pSprite); + + if (pExtra->curWeapon >= kTrapExploder && pExtra->curWeapon < (kTrapExploder + kExplodeMax) - 1) + doExplosion(pSprite, pXSprite->data1 - kTrapExploder); - if (pXSprite->data1 >= kTrapExploder && pXSprite->data1 < (kTrapExploder + kExplodeMax) - 1) - doExplosion(pSprite, pXSprite->data1 - kTrapExploder); - - if (spriteIsUnderwater(pSprite, false)) { - pXSprite->health = 0; - break; - } - - if (pXSprite->burnTime <= 0) - pXSprite->burnTime = 1200; - - if ((gSysRes.Lookup(pXSprite->data2 + 15, "SEQ") || gSysRes.Lookup(pXSprite->data2 + 16, "SEQ")) - && gSysRes.Lookup(pXSprite->data2 + 3, "SEQ")) { - - aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1); - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndBurning); - pSprite->type = kDudeModernCustomBurning; - - if (pXSprite->data2 == kDefaultAnimationBase) // don't inherit palette for burning if using default animation - pSprite->pal = 0; - - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); - actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth); - gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; - evKill(nSprite, 3, kCallbackFXFlameLick); - - } - - } else { - actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535); + if (spriteIsUnderwater(pSprite, false)) { + pXSprite->health = 0; + break; } + + if (pXSprite->burnTime <= 0) + pXSprite->burnTime = 1200; + + if (pExtra->canBurn && pExtra->availDeaths[DAMAGE_TYPE_1] > 0) { + + aiPlay3DSound(pSprite, 361, AI_SFX_PRIORITY_0, -1); + playGenDudeSound(pSprite, kGenDudeSndBurning); + pSprite->type = kDudeModernCustomBurning; + + if (pXSprite->data2 == kGenDudeDefaultSeq) // don't inherit palette for burning if using default animation + pSprite->pal = 0; + + aiGenDudeNewState(pSprite, &genDudeBurnGoto); + actHealDude(pXSprite, dudeInfo[55].startHealth, dudeInfo[55].startHealth); + gDudeExtra[pSprite->extra].at0 = (int)gFrameClock + 360; + evKill(nSprite, 3, kCallbackFXFlameLick); + + } + + } else { + actKillDude(nSource, pSprite, DAMAGE_TYPE_0, 65535); } - } else if (!inDodge(pXSprite->aiState)) { - - if (Chance(getDodgeChance(pSprite)) || inIdle(pXSprite->aiState)) { + } else if (canWalk(pSprite) && !inDodge(pXSprite->aiState) && !inRecoil(pXSprite->aiState)) { + if (inIdle(pXSprite->aiState) || inSearch(pXSprite->aiState) || Chance(getDodgeChance(pSprite))) { if (!spriteIsUnderwater(pSprite, false)) { - if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgL); - else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgD); + if (!canDuck(pSprite) || !sub_5BDA8(pSprite, 14)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL); + else aiGenDudeNewState(pSprite, &genDudeDodgeShortD); if (Chance(0x0200)) - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit); + playGenDudeSound(pSprite, kGenDudeSndGotHit); + + } else if (sub_5BDA8(pSprite, 13)) { + aiGenDudeNewState(pSprite, &genDudeDodgeShortW); } - else if (sub_5BDA8(pSprite, 13)) - aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeDmgW); } } - break; } case kDudeCultistBeast: @@ -1123,43 +1103,53 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite) { char v4 = Chance(0x8000); DUDEEXTRA *pDudeExtra = &gDudeExtra[pSprite->extra]; - if (pSprite->statnum == kStatDude && (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) - { + if (pSprite->statnum == kStatDude && (pSprite->type >= kDudeBase && pSprite->type < kDudeMax)) { DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type-kDudeBase]; - switch (pSprite->type) - { - case kDudeModernCustom: - { - int mass = getSpriteMassBySize(pSprite); int chance4 = getRecoilChance(pSprite); bool chance3 = Chance(chance4); - if (pDudeExtra->at4 && (inIdle(pXSprite->aiState) || mass < 155 || (mass >= 155 && chance3)) && !spriteIsUnderwater(pSprite, false)) - { - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit); + switch (pSprite->type) { + case kDudeModernCustom: { + GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); int rChance = getRecoilChance(pSprite); + if (pExtra->canElectrocute && pDudeExtra->at4 && !spriteIsUnderwater(pSprite, false)) { - if (gSysRes.Lookup(pXSprite->data2 + 4, "SEQ")) { - GDXGenDudeRTesla.at18 = (Chance(chance4 * 2) ? &GDXGenDudeDodgeL : &GDXGenDudeDodgeDmgL); - aiNewState(pSprite, pXSprite, &GDXGenDudeRTesla); + if (Chance(rChance << 3) || (dudeIsMelee(pXSprite) && Chance(rChance << 4))) aiGenDudeNewState(pSprite, &genDudeRecoilTesla); + else if (pExtra->canRecoil && Chance(rChance)) aiGenDudeNewState(pSprite, &genDudeRecoilL); + else if (canWalk(pSprite)) { + + if (Chance(rChance >> 2)) aiGenDudeNewState(pSprite, &genDudeDodgeL); + else if (Chance(rChance >> 1)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL); + } - else if (canDuck(pSprite) && (Chance(chance4) || gGameOptions.nDifficulty == 0)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilD); - else if (canSwim(pSprite) && spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilL); - break; + + } else if (pExtra->canRecoil && Chance(rChance)) { + + if (inDuck(pXSprite->aiState) && Chance(rChance >> 2)) aiGenDudeNewState(pSprite, &genDudeRecoilD); + else if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeRecoilW); + else aiGenDudeNewState(pSprite, &genDudeRecoilL); + } + + short rState = inRecoil(pXSprite->aiState); + if (rState > 0) { + + if (!canWalk(pSprite)) { + if (rState == 1) pXSprite->aiState->nextState = &genDudeChaseNoWalkL; + else if (rState == 2) pXSprite->aiState->nextState = &genDudeChaseNoWalkD; + else pXSprite->aiState->nextState = &genDudeChaseNoWalkW; - if (inDodge(pXSprite->aiState)) { - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit); - break; - } + } else if (!dudeIsMelee(pXSprite) || Chance(rChance >> 2)) { + if (rState == 1) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeL : &genDudeDodgeShortL); + else if (rState == 2) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeD : &genDudeDodgeShortD); + else if (rState == 1) pXSprite->aiState->nextState = (Chance(rChance) ? &genDudeDodgeW : &genDudeDodgeShortW); - if (inIdle(pXSprite->aiState) || chance3 || Chance(getRecoilChance(pSprite)) || (!dudeIsMelee(pXSprite) && mass < 155)) { + } + else if (rState == 1) pXSprite->aiState->nextState = &genDudeChaseL; + else if (rState == 2) pXSprite->aiState->nextState = &genDudeChaseD; + else pXSprite->aiState->nextState = &genDudeChaseW; - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndGotHit); - - if (canDuck(pSprite) && (Chance(chance4) || gGameOptions.nDifficulty == 0)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilD); - else if (canSwim(pSprite) && spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeRecoilL); + playGenDudeSound(pSprite, kGenDudeSndGotHit); } + pDudeExtra->at4 = 0; break; } case kDudeCultistTommy: @@ -1193,7 +1183,7 @@ void RecoilDude(spritetype *pSprite, XSPRITE *pXSprite) aiNewState(pSprite, pXSprite, &cultistBurnGoto); break; case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); + aiGenDudeNewState(pSprite, &genDudeBurnGoto); break; case kDudeZombieButcher: aiPlay3DSound(pSprite, 1202, AI_SFX_PRIORITY_2, -1); @@ -1453,45 +1443,39 @@ void sub_5F15C(spritetype *pSprite, XSPRITE *pXSprite) } } -void aiProcessDudes(void) -{ +void aiProcessDudes(void) { for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { spritetype *pSprite = &sprite[nSprite]; if (pSprite->flags & 32) continue; int nXSprite = pSprite->extra; - XSPRITE *pXSprite = &xsprite[nXSprite]; - DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; + XSPRITE *pXSprite = &xsprite[nXSprite]; DUDEINFO *pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; if (IsPlayerSprite(pSprite) || pXSprite->health == 0) continue; pXSprite->stateTimer = ClipLow(pXSprite->stateTimer-4, 0); - if (pXSprite->aiState->at10) - pXSprite->aiState->at10(pSprite, pXSprite); - if (pXSprite->aiState->at14 && (gFrame&3) == (nSprite&3)) - pXSprite->aiState->at14(pSprite, pXSprite); - if (pXSprite->stateTimer == 0 && pXSprite->aiState->at18) { - if (pXSprite->aiState->at8 > 0) - aiNewState(pSprite, pXSprite, pXSprite->aiState->at18); - else if (seqGetStatus(3, nXSprite) < 0) - aiNewState(pSprite, pXSprite, pXSprite->aiState->at18); - } + if (pSprite->type >= kDudeVanillaMax && pSprite->type < kDudeMax) + genDudeProcess(pSprite, pXSprite); - if (pXSprite->health > 0 && ((pDudeInfo->hinderDamage << 4) <= cumulDamage[nXSprite])) { - pXSprite->data3 = cumulDamage[nXSprite]; - RecoilDude(pSprite, pXSprite); - } - - if (pSprite->type >= kDudeVanillaMax) { - switch (pSprite->type) { - case kDudeModernCustom: - case kDudeModernCustomBurning: - GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; - if (pExtra->slaveCount > 0) updateTargetOfSlaves(pSprite); - if (pExtra->nLifeLeech >= 0) updateTargetOfLeech(pSprite); - break; + else { + + if (pXSprite->aiState->moveFunc) + pXSprite->aiState->moveFunc(pSprite, pXSprite); + + if (pXSprite->aiState->thinkFunc && (gFrame & 3) == (nSprite & 3)) + pXSprite->aiState->thinkFunc(pSprite, pXSprite); + + if (pXSprite->stateTimer == 0 && pXSprite->aiState->nextState) { + if (pXSprite->aiState->stateTicks > 0) + aiNewState(pSprite, pXSprite, pXSprite->aiState->nextState); + else if (seqGetStatus(3, nXSprite) < 0) + aiNewState(pSprite, pXSprite, pXSprite->aiState->nextState); } + + if (pXSprite->health > 0 && ((pDudeInfo->hinderDamage << 4) <= cumulDamage[nXSprite])) { + pXSprite->data3 = cumulDamage[nXSprite]; + RecoilDude(pSprite, pXSprite); + } + } - - } memset(cumulDamage, 0, sizeof(cumulDamage)); } @@ -1520,12 +1504,12 @@ void aiInitSprite(spritetype *pSprite) case kDudeModernCustom: { DUDEEXTRA_at6_u1* pDudeExtraE = &gDudeExtra[nXSprite].at6.u1; pDudeExtraE->at8 = pDudeExtraE->at0 = 0; - aiNewState(pSprite, pXSprite, &GDXGenDudeIdleL); + aiGenDudeNewState(pSprite, &genDudeIdleL); genDudePrepare(pSprite); break; } case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); + aiGenDudeNewState(pSprite, &genDudeBurnGoto); pXSprite->burnTime = 1200; break; case kDudeCultistTommy: diff --git a/source/blood/src/ai.h b/source/blood/src/ai.h index e6f8789b1..e2bff58cb 100644 --- a/source/blood/src/ai.h +++ b/source/blood/src/ai.h @@ -32,13 +32,13 @@ BEGIN_BLD_NS struct AISTATE { int stateType; // By NoOne: current type of state. Basically required for kModernDudeTargetChanger, but can be used for something else. - int at0; // seq - int at4; // seq callback - int at8; - void(*atc)(spritetype *, XSPRITE *); - void(*at10)(spritetype *, XSPRITE *); - void(*at14)(spritetype *, XSPRITE *); - AISTATE *at18; // next state ? + int seqId; + int funcId; // seq callback + int stateTicks; + void(*enterFunc)(spritetype *, XSPRITE *); + void(*moveFunc)(spritetype *, XSPRITE *); + void(*thinkFunc)(spritetype *, XSPRITE *); + AISTATE *nextState; }; extern AISTATE aiState[]; @@ -86,6 +86,7 @@ struct TARGETTRACK { extern int dword_138BB0[5]; extern DUDEEXTRA gDudeExtra[]; extern int gDudeSlope[]; +extern int cumulDamage[]; bool sub_5BDA8(spritetype *pSprite, int nSeq); void aiPlay3DSound(spritetype *pSprite, int a2, AI_SFX_PRIORITY a3, int a4); @@ -104,6 +105,7 @@ void aiProcessDudes(void); void aiInit(void); void aiInitSprite(spritetype *pSprite); bool CanMove(spritetype* pSprite, int a2, int nAngle, int nRange); +void RecoilDude(spritetype* pSprite, XSPRITE* pXSprite); // By NoOne: this function required for kModernDudeTargetChanger void aiSetGenIdleState(spritetype* pSprite, XSPRITE* pXSprite); diff --git a/source/blood/src/aiburn.cpp b/source/blood/src/aiburn.cpp index cf6fff060..3606ae29e 100644 --- a/source/blood/src/aiburn.cpp +++ b/source/blood/src/aiburn.cpp @@ -81,11 +81,11 @@ AISTATE tinycalebBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, th AISTATE tinycalebBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &tinycalebBurnSearch }; AISTATE tinycalebBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &tinycalebBurnChase }; -AISTATE GDXGenDudeBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL }; -AISTATE GDXGenDudeBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL }; -AISTATE GDXGenDudeBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &GDXGenDudeBurnSearch }; -AISTATE GDXGenDudeBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &GDXGenDudeBurnSearch }; -AISTATE GDXGenDudeBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &GDXGenDudeBurnChase }; +AISTATE genDudeBurnIdle = { kAiStateIdle, 3, -1, 0, NULL, NULL, aiThinkTarget, NULL }; +AISTATE genDudeBurnChase = { kAiStateChase, 3, -1, 0, NULL, aiMoveForward, thinkChase, NULL }; +AISTATE genDudeBurnGoto = { kAiStateMove, 3, -1, 3600, NULL, aiMoveForward, thinkGoto, &genDudeBurnSearch }; +AISTATE genDudeBurnSearch = { kAiStateSearch, 3, -1, 3600, NULL, aiMoveForward, thinkSearch, &genDudeBurnSearch }; +AISTATE genDudeBurnAttack = { kAiStateChase, 3, nBurnClient, 120, NULL, NULL, NULL, &genDudeBurnChase }; static void BurnSeqCallback(int, int) { @@ -129,7 +129,7 @@ static void thinkGoto(spritetype *pSprite, XSPRITE *pXSprite) aiNewState(pSprite, pXSprite, &tinycalebBurnSearch); break; case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); + aiNewState(pSprite, pXSprite, &genDudeBurnSearch); break; } } @@ -161,7 +161,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) aiNewState(pSprite, pXSprite, &tinycalebBurnGoto); break; case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnGoto); + aiNewState(pSprite, pXSprite, &genDudeBurnGoto); break; } return; @@ -197,7 +197,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) aiNewState(pSprite, pXSprite, &tinycalebBurnSearch); break; case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); + aiNewState(pSprite, pXSprite, &genDudeBurnSearch); break; } return; @@ -235,7 +235,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) aiNewState(pSprite, pXSprite, &tinycalebBurnAttack); break; case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); + aiNewState(pSprite, pXSprite, &genDudeBurnSearch); break; } } @@ -265,7 +265,7 @@ static void thinkChase(spritetype *pSprite, XSPRITE *pXSprite) aiNewState(pSprite, pXSprite, &tinycalebBurnGoto); break; case kDudeModernCustomBurning: - aiNewState(pSprite, pXSprite, &GDXGenDudeBurnSearch); + aiNewState(pSprite, pXSprite, &genDudeBurnSearch); break; } pXSprite->target = -1; diff --git a/source/blood/src/aiburn.h b/source/blood/src/aiburn.h index 120ebb078..aa58046cc 100644 --- a/source/blood/src/aiburn.h +++ b/source/blood/src/aiburn.h @@ -50,10 +50,10 @@ extern AISTATE tinycalebBurnChase; extern AISTATE tinycalebBurnGoto; extern AISTATE tinycalebBurnSearch; extern AISTATE tinycalebBurnAttack; -extern AISTATE GDXGenDudeBurnIdle; -extern AISTATE GDXGenDudeBurnChase; -extern AISTATE GDXGenDudeBurnGoto; -extern AISTATE GDXGenDudeBurnSearch; -extern AISTATE GDXGenDudeBurnAttack; +extern AISTATE genDudeBurnIdle; +extern AISTATE genDudeBurnChase; +extern AISTATE genDudeBurnGoto; +extern AISTATE genDudeBurnSearch; +extern AISTATE genDudeBurnAttack; END_BLD_NS diff --git a/source/blood/src/aiunicult.cpp b/source/blood/src/aiunicult.cpp index a626ee08e..73e726a2b 100644 --- a/source/blood/src/aiunicult.cpp +++ b/source/blood/src/aiunicult.cpp @@ -47,10 +47,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "triggers.h" #include "endgame.h" #include "view.h" +#include "tile.h" BEGIN_BLD_NS - -static void GDXCultistAttack1(int, int); +static void genDudeAttack1(int, int); static void punchCallback(int, int); static void ThrowCallback1(int, int); static void ThrowCallback2(int, int); @@ -60,69 +60,100 @@ static void thinkGoto(spritetype*, XSPRITE*); static void thinkChase(spritetype*, XSPRITE*); static void forcePunch(spritetype*, XSPRITE*); -static int nGDXGenDudeAttack1 = seqRegisterClient(GDXCultistAttack1); -static int nGDXGenDudePunch = seqRegisterClient(punchCallback); -static int nGDXGenDudeThrow1 = seqRegisterClient(ThrowCallback1); -static int nGDXGenDudeThrow2 = seqRegisterClient(ThrowCallback2); +static int nGenDudeAttack1 = seqRegisterClient(genDudeAttack1); +static int nGenDudePunch = seqRegisterClient(punchCallback); +static int nGenDudeThrow1 = seqRegisterClient(ThrowCallback1); +static int nGenDudeThrow2 = seqRegisterClient(ThrowCallback2); -AISTATE GDXGenDudeIdleL = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL }; -AISTATE GDXGenDudeIdleW = { kAiStateIdle, 13, -1, 0, NULL, NULL, aiThinkTarget, NULL }; -AISTATE GDXGenDudeSearchL = { kAiStateSearch, 9, -1, 600, NULL, aiGenDudeMoveForward, thinkSearch, &GDXGenDudeIdleL }; -AISTATE GDXGenDudeSearchW= { kAiStateSearch, 13, -1, 600, NULL, aiGenDudeMoveForward, thinkSearch, &GDXGenDudeIdleW }; -AISTATE GDXGenDudeGotoL = { kAiStateMove, 9, -1, 600, NULL, aiGenDudeMoveForward, thinkGoto, &GDXGenDudeIdleL }; -AISTATE GDXGenDudeGotoW = { kAiStateMove, 13, -1, 600, NULL, aiGenDudeMoveForward, thinkGoto, &GDXGenDudeIdleW }; -AISTATE GDXGenDudeDodgeL = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeDodgeD = { kAiStateMove, 14, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseD }; -AISTATE GDXGenDudeDodgeW = { kAiStateMove, 13, -1, 90, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseW }; -// Dodge when get damage -AISTATE GDXGenDudeDodgeDmgL = { kAiStateMove, 9, -1, 60, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeDodgeDmgD = { kAiStateMove, 14, -1, 60, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseD }; -AISTATE GDXGenDudeDodgeDmgW = { kAiStateMove, 13, -1, 60, NULL, aiMoveDodge, NULL, &GDXGenDudeChaseW }; +AISTATE genDudeIdleL = { kAiStateIdle, 0, -1, 0, NULL, NULL, aiThinkTarget, NULL }; +AISTATE genDudeIdleW = { kAiStateIdle, 13, -1, 0, NULL, NULL, aiThinkTarget, NULL }; +// --------------------- +AISTATE genDudeSearchL = { kAiStateSearch, 9, -1, 600, NULL, aiGenDudeMoveForward, thinkSearch, &genDudeIdleL }; +AISTATE genDudeSearchW = { kAiStateSearch, 13, -1, 600, NULL, aiGenDudeMoveForward, thinkSearch, &genDudeIdleW }; +// --------------------- +AISTATE genDudeSearchShortL = { kAiStateSearch, 9, -1, 200, NULL, aiGenDudeMoveForward, thinkSearch, &genDudeIdleL }; +AISTATE genDudeSearchShortW = { kAiStateSearch, 13, -1, 200, NULL, aiGenDudeMoveForward, thinkSearch, &genDudeIdleW }; +// --------------------- +AISTATE genDudeSearchNoWalkL = { kAiStateSearch, 0, -1, 600, NULL, aiMoveTurn, thinkSearch, &genDudeIdleL }; +AISTATE genDudeSearchNoWalkW = { kAiStateSearch, 13, -1, 600, NULL, aiMoveTurn, thinkSearch, &genDudeIdleW }; +// --------------------- +AISTATE genDudeGotoL = { kAiStateMove, 9, -1, 600, NULL, aiGenDudeMoveForward, thinkGoto, &genDudeIdleL }; +AISTATE genDudeGotoW = { kAiStateMove, 13, -1, 600, NULL, aiGenDudeMoveForward, thinkGoto, &genDudeIdleW }; +// --------------------- +AISTATE genDudeDodgeL = { kAiStateMove, 9, -1, 90, NULL, aiMoveDodge, NULL, &genDudeChaseL }; +AISTATE genDudeDodgeD = { kAiStateMove, 14, -1, 90, NULL, aiMoveDodge, NULL, &genDudeChaseD }; +AISTATE genDudeDodgeW = { kAiStateMove, 13, -1, 90, NULL, aiMoveDodge, NULL, &genDudeChaseW }; +// --------------------- +AISTATE genDudeDodgeShortL = { kAiStateMove, 9, -1, 60, NULL, aiMoveDodge, NULL, &genDudeChaseL }; +AISTATE genDudeDodgeShortD = { kAiStateMove, 14, -1, 60, NULL, aiMoveDodge, NULL, &genDudeChaseD }; +AISTATE genDudeDodgeShortW = { kAiStateMove, 13, -1, 60, NULL, aiMoveDodge, NULL, &genDudeChaseW }; +// --------------------- +AISTATE genDudeChaseL = { kAiStateChase, 9, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; +AISTATE genDudeChaseD = { kAiStateChase, 14, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; +AISTATE genDudeChaseW = { kAiStateChase, 13, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; +// --------------------- +AISTATE genDudeChaseNoWalkL = { kAiStateChase, 0, -1, 0, NULL, aiMoveTurn, thinkChase, NULL }; +AISTATE genDudeChaseNoWalkD = { kAiStateChase, 14, -1, 0, NULL, aiMoveTurn, thinkChase, NULL }; +AISTATE genDudeChaseNoWalkW = { kAiStateChase, 13, -1, 0, NULL, aiMoveTurn, thinkChase, NULL }; +// --------------------- +AISTATE genDudeFireL = { kAiStateChase, 6, nGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &genDudeFireL }; +AISTATE genDudeFireD = { kAiStateChase, 8, nGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &genDudeFireD }; +AISTATE genDudeFireW = { kAiStateChase, 8, nGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &genDudeFireW }; +// ---------------------z +AISTATE genDudeRecoilL = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &genDudeChaseL }; +AISTATE genDudeRecoilD = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &genDudeChaseD }; +AISTATE genDudeRecoilW = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &genDudeChaseW }; +AISTATE genDudeRecoilTesla = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &genDudeDodgeShortL }; +// --------------------- +AISTATE genDudeThrow = { kAiStateChase, 7, nGenDudeThrow1, 0, NULL, NULL, NULL, &genDudeChaseL }; +AISTATE genDudeThrow2 = { kAiStateChase, 7, nGenDudeThrow2, 0, NULL, NULL, NULL, &genDudeChaseL }; +// --------------------- +AISTATE genDudePunch = { kAiStateChase,10, nGenDudePunch, 0, NULL, NULL, forcePunch, &genDudeChaseL }; // --------------------- -AISTATE GDXGenDudeChaseL = { kAiStateChase, 9, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; -AISTATE GDXGenDudeChaseD = { kAiStateChase, 14, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; -AISTATE GDXGenDudeChaseW = { kAiStateChase, 13, -1, 0, NULL, aiGenDudeMoveForward, thinkChase, NULL }; -AISTATE GDXGenDudeFireL = { kAiStateChase, 6, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &GDXGenDudeFireL }; -AISTATE GDXGenDudeFireD = { kAiStateChase, 8, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &GDXGenDudeFireD }; -AISTATE GDXGenDudeFireW = { kAiStateChase, 8, nGDXGenDudeAttack1, 0, NULL, aiMoveTurn, thinkChase, &GDXGenDudeFireW }; -AISTATE GDXGenDudeRecoilL = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeRecoilD = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &GDXGenDudeChaseD }; -AISTATE GDXGenDudeRecoilW = { kAiStateRecoil, 5, -1, 0, NULL, NULL, NULL, &GDXGenDudeChaseW }; -AISTATE GDXGenDudeThrow = { kAiStateChase, 7, nGDXGenDudeThrow1, 0, NULL, NULL, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeThrow2 = { kAiStateChase, 7, nGDXGenDudeThrow2, 0, NULL, NULL, NULL, &GDXGenDudeChaseL }; -AISTATE GDXGenDudeRTesla = { kAiStateRecoil, 4, -1, 0, NULL, NULL, NULL, &GDXGenDudeDodgeDmgL }; -AISTATE GDXGenDudePunch = { kAiStateChase,10, nGDXGenDudePunch, 0, NULL, NULL, forcePunch, &GDXGenDudeChaseL }; GENDUDESND gCustomDudeSnd[] = { - { 1003, 2, 0, true }, // spot sound - { 1013, 2, 2, true }, // pain sound - { 1018, 2, 4, false }, // death sound - { 1031, 2, 6, true }, // burning state sound - { 1018, 2, 8, false }, // explosive death or end of burning state sound - { 4021, 2, 10, true }, // target of dude is dead - { 1005, 2, 12, true }, // chase sound - { -1, 0, 14, false }, // weapon attack - { -1, 0, 15, false }, // throw attack - { -1, 0, 16, false }, // melee attack - { 9008, 0, 17, false }, // transforming in other dude + { 1003, 2, 0, true, false }, // spot sound + { 1013, 2, 2, true, true }, // pain sound + { 1018, 2, 4, false, true }, // death sound + { 1031, 2, 6, true, true }, // burning state sound + { 1018, 2, 8, false, true }, // explosive death or end of burning state sound + { 4021, 2, 10, true, false }, // target of dude is dead + { 1005, 2, 12, true, false }, // chase sound + { -1, 0, 14, false, true }, // weapon attack + { -1, 0, 15, false, true }, // throw attack + { -1, 0, 16, false, true }, // melee attack + { 9008, 0, 17, false, false }, // transforming in other dude }; GENDUDEEXTRA gGenDudeExtra[kMaxSprites]; static void forcePunch(spritetype* pSprite, XSPRITE* pXSprite) { - - // Required for those who don't have fire trigger in punch seq and for default animation - if (pXSprite->data2 != kDefaultAnimationBase) { - Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(pXSprite->data2 + 10, "SEQ"); - if ((pSeq = (Seq*)gSysRes.Load(hSeq)) != NULL) { - for (int i = 0; i < pSeq->nFrames; i++) - if (pSeq->frames[i].at5_5) return; - } - } - - if (seqGetStatus(3, pSprite->extra) == -1) + if (gGenDudeExtra[pSprite->index].forcePunch && seqGetStatus(3, pSprite->extra) == -1) punchCallback(0,pSprite->extra); +} +void genDudeProcess(spritetype* pSprite, XSPRITE* pXSprite) { + GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; + + if (pExtra->slaveCount > 0) + updateTargetOfSlaves(pSprite); + + if (pExtra->nLifeLeech >= 0) + updateTargetOfLeech(pSprite); + + if (pXSprite->aiState->moveFunc) + pXSprite->aiState->moveFunc(pSprite, pXSprite); + + if (pXSprite->aiState->thinkFunc && (gFrame & 3) == (pSprite->index & 3)) + pXSprite->aiState->thinkFunc(pSprite, pXSprite); + + if (pXSprite->stateTimer == 0 && pXSprite->aiState->nextState && (pXSprite->aiState->stateTicks > 0 || seqGetStatus(3, pSprite->extra) < 0)) + aiGenDudeNewState(pSprite, pXSprite->aiState->nextState); + + if (pXSprite->health > 0 && ((dudeInfo[pSprite->type - kDudeBase].hinderDamage << 4) <= cumulDamage[pSprite->extra])) { + pXSprite->data3 = cumulDamage[pSprite->extra]; + RecoilDude(pSprite, pXSprite); + } } void genDudeUpdate(spritetype* pSprite) { @@ -149,14 +180,14 @@ static void punchCallback(int, int nXIndex) { int dy = Sin(pSprite->ang) >> 16; int dz = nZOffset1 - nZOffset2; - if (!sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndAttackMelee)) + if (!playGenDudeSound(pSprite, kGenDudeSndAttackMelee)) sfxPlay3DSound(pSprite, 530, 1, 0); actFireVector(pSprite, 0, 0, dx, dy, dz,VECTOR_TYPE_22); } } -static void GDXCultistAttack1(int, int nXIndex) { +static void genDudeAttack1(int, int nXIndex) { if (!(nXIndex >= 0 && nXIndex < kMaxXSprites)) { consoleSysMsg("nXIndex >= 0 && nXIndex < kMaxXSprites"); return; @@ -173,7 +204,8 @@ static void GDXCultistAttack1(int, int nXIndex) { xvel[pSprite->index] = yvel[pSprite->index] = 0; short curWeapon = gGenDudeExtra[nSprite].curWeapon; - short disperion = gGenDudeExtra[nSprite].baseDispersion; + short dispersion = gGenDudeExtra[nSprite].baseDispersion; + if (inDuck(pXSprite->aiState)) dispersion = ClipLow(dispersion >> 1, 250); if (curWeapon >= 0 && curWeapon < kVectorMax) { @@ -184,12 +216,12 @@ static void GDXCultistAttack1(int, int nXIndex) { // dispersal modifiers here in case if non-melee enemy if (vdist <= 0 || vdist > 1280) { - dx += Random3(disperion); dy += Random3(disperion); - dz += Random3(disperion); + dx += Random3(dispersion); dy += Random3(dispersion); + dz += Random3(dispersion); } actFireVector(pSprite, 0, 0, dx, dy, dz,(VECTOR_TYPE)curWeapon); - if (!sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndAttackNormal)) + if (!playGenDudeSound(pSprite, kGenDudeSndAttackNormal)) sfxPlayVectorSound(pSprite, curWeapon); } else if (curWeapon >= kDudeBase && curWeapon < kDudeMax) { @@ -210,7 +242,7 @@ static void GDXCultistAttack1(int, int nXIndex) { gGenDudeExtra[pSprite->index].slave[slaveCnt] = pSpawned->index; gGenDudeExtra[pSprite->index].slaveCount++; - if (!sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndAttackNormal)) + if (!playGenDudeSound(pSprite, kGenDudeSndAttackNormal)) sfxPlay3DSoundCP(pSprite, 379, 1, 0, 0x10000 - Random3(0x3000)); } @@ -221,11 +253,11 @@ static void GDXCultistAttack1(int, int nXIndex) { dz = gDudeSlope[nXIndex]; // dispersal modifiers here - dx += Random3(disperion); dy += Random3(disperion); - dz += Random3(disperion >> 1); + dx += Random3(dispersion); dy += Random3(dispersion); + dz += Random3(dispersion >> 1); actFireMissile(pSprite, 0, 0, dx, dy, dz, curWeapon); - if (!sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndAttackNormal)) + if (!playGenDudeSound(pSprite, kGenDudeSndAttackNormal)) sfxPlayMissileSound(pSprite, curWeapon); } } @@ -255,7 +287,7 @@ static void ThrowThing(int nXIndex, bool impact) { THINGINFO* pThinkInfo = &thingInfo[curWeapon - kThingBase]; if (!pThinkInfo->allowThrow) return; - if (!sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndAttackThrow)) + if (!playGenDudeSound(pSprite, kGenDudeSndAttackThrow)) sfxPlay3DSound(pSprite, 455, -1, 0); int zThrow = 14500; @@ -344,11 +376,8 @@ static void ThrowThing(int nXIndex, bool impact) { } static void thinkSearch( spritetype* pSprite, XSPRITE* pXSprite ) { - - int velocity = ClipLow(pSprite->clipdist / 2, 1); - aiGenDudeChooseDirection(pSprite, pXSprite, pXSprite->goalAng, velocity, velocity); + aiChooseDirection(pSprite, pXSprite, pXSprite->goalAng); sub_5F15C(pSprite, pXSprite); - } static void thinkGoto(spritetype* pSprite, XSPRITE* pXSprite) { @@ -362,13 +391,12 @@ static void thinkGoto(spritetype* pSprite, XSPRITE* pXSprite) { int dy = pXSprite->targetY - pSprite->y; int nAngle = getangle(dx, dy); - int velocity = ClipLow(pSprite->clipdist / 2, 1); - aiGenDudeChooseDirection(pSprite, pXSprite, nAngle, velocity, velocity); + aiChooseDirection(pSprite, pXSprite, nAngle); // if reached target, change to search mode if (approxDist(dx, dy) < 5120 && klabs(pSprite->ang - nAngle) < dudeInfo[pSprite->type - kDudeBase].periphery) { - if (spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchW); + else aiGenDudeNewState(pSprite, &genDudeSearchL); } aiThinkTarget(pSprite, pXSprite); } @@ -377,8 +405,8 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { if (pSprite->type < kDudeBase || pSprite->type >= kDudeMax) return; else if (pXSprite->target < 0 || pXSprite->target >= kMaxSprites) { - if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeGotoL); + if(spriteIsUnderwater(pSprite,false)) aiGenDudeNewState(pSprite, &genDudeGotoW); + else aiGenDudeNewState(pSprite, &genDudeGotoL); return; } else { @@ -386,47 +414,68 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { } + + spritetype* pTarget = &sprite[pXSprite->target]; XSPRITE* pXTarget = (!IsDudeSprite(pTarget) || pTarget->extra < 0) ? NULL : &xsprite[pTarget->extra]; + if (pXTarget == NULL) { // target lost + if(spriteIsUnderwater(pSprite,false)) aiGenDudeNewState(pSprite, &genDudeSearchShortW); + else aiGenDudeNewState(pSprite, &genDudeSearchShortL); + return; + } else if (pXTarget->health <= 0) { // target is dead + PLAYER* pPlayer = NULL; + if ((!IsPlayerSprite(pTarget) && pSprite->index == pTarget->owner) + || ((pPlayer = getPlayerById(pTarget->type)) != NULL && pPlayer->fraggerId == pSprite->index)) { + + playGenDudeSound(pSprite, kGenDudeSndTargetDead); + + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchShortW); + else aiGenDudeNewState(pSprite, &genDudeSearchShortL); + } + else if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeGotoW); + else aiGenDudeNewState(pSprite, &genDudeGotoL); - if (pXTarget == NULL || pXTarget->health <= 0) { - // target is dead - if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - else { - aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTargetDead); - } return; } // check target int dx = pTarget->x - pSprite->x; int dy = pTarget->y - pSprite->y; - int dist = ClipLow((int)approxDist(dx, dy), 1); + int dist = ClipLow((int)approxDist(dx, dy), 1); // quick hack to prevent spinning around or changing attacker's sprite angle on high movement speeds // when attacking the target. It happens because vanilla function takes in account x and y velocity, // so i use fake velocity with fixed value and pass it as argument. - int velocity = ClipLow(pSprite->clipdist / 2, 1); - aiGenDudeChooseDirection(pSprite, pXSprite, getangle(dx, dy), velocity, velocity); - // aiChooseDirection(pSprite, pXSprite, getangle(dx, dy)); + int xvelocity = xvel[pSprite->index]; int yvelocity = yvel[pSprite->index]; + if (inAttack(pXSprite->aiState)) + xvelocity = yvelocity = ClipLow(pSprite->clipdist >> 1, 1); + + aiGenDudeChooseDirection(pSprite, pXSprite, getangle(dx, dy), xvelocity, yvelocity); + + GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; + if (!pExtra->canAttack) { + aiSetTarget(pXSprite, pSprite->index); + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeGotoW); + else aiGenDudeNewState(pSprite, &genDudeGotoL); + return; + } if (IsPlayerSprite(pTarget)) { PLAYER* pPlayer = &gPlayer[ pTarget->type - kDudePlayer1 ]; if (powerupCheck(pPlayer, kPwUpShadowCloak) > 0) { - if(spriteIsUnderwater(pSprite,false)) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchShortW); + else aiGenDudeNewState(pSprite, &genDudeSearchShortL); return; } } - DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; - int eyeAboveZ = pDudeInfo->eyeHeight * pSprite->yrepeat << 2; int seeDist = getSeeDist(pSprite, 51200, 35000, 85000); + DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; + int eyeAboveZ = pDudeInfo->eyeHeight * pSprite->yrepeat << 2; if (dist > pDudeInfo->seeDist || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pSprite->x, pSprite->y, pSprite->z - eyeAboveZ, pSprite->sectnum)) { - if (spriteIsUnderwater(pSprite, false)) aiNewState(pSprite, pXSprite, &GDXGenDudeGotoW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeGotoL); + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeSearchW); + else aiGenDudeNewState(pSprite, &genDudeSearchL); pXSprite->target = -1; return; } @@ -438,14 +487,15 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { if (dist < pDudeInfo->seeDist && klabs(losAngle) <= pDudeInfo->periphery) { if (((int)gFrameClock & 64) == 0 && Chance(0x3000) && !spriteIsUnderwater(pSprite, false)) - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndChasing); + playGenDudeSound(pSprite, kGenDudeSndChasing); gDudeSlope[sprite[pXSprite->reference].extra] = (int)divscale(pTarget->z - pSprite->z, dist, 10); short curWeapon = gGenDudeExtra[pSprite->index].curWeapon; spritetype* pLeech = leechIsDropped(pSprite); VECTORDATA* meleeVector = &gVectorData[22]; - if (pExtra->updReq[kGenDudePropertyAttack]) genDudePrepare(pSprite, kGenDudePropertyAttack); + if (pExtra->updReq[kGenDudePropertyAttack]) + genDudePrepare(pSprite, kGenDudePropertyAttack); if (curWeapon >= kThingBase && curWeapon < kThingMax) { if (klabs(losAngle) < kAng15) { @@ -456,16 +506,16 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { case 4: return; default: - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow); + aiGenDudeNewState(pSprite, &genDudeThrow); return; } - } else if (dist > 4072 && dist <= 9072 && !spriteIsUnderwater(pSprite, false) && pSprite->owner != (kMaxSprites - 1)) { + } else if (dist > 4072 && dist <= 11072 && !spriteIsUnderwater(pSprite, false) && pSprite->owner != (kMaxSprites - 1)) { switch (curWeapon) { case kModernThingEnemyLifeLeech: { if (pLeech == NULL) { - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - GDXGenDudeThrow2.at18 = &GDXGenDudeDodgeL; + aiGenDudeNewState(pSprite, &genDudeThrow2); + genDudeThrow2.nextState = &genDudeDodgeShortL; return; } @@ -474,50 +524,50 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { if (ldist > 3 || !cansee(pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pLeech->x, pLeech->y, pLeech->z, pLeech->sectnum) || pXLeech->target == -1) { - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - GDXGenDudeThrow2.at18 = &GDXGenDudeDodgeL; + aiGenDudeNewState(pSprite, &genDudeThrow2); + genDudeThrow2.nextState = &genDudeDodgeShortL; } else { - GDXGenDudeThrow2.at18 = &GDXGenDudeChaseL; + genDudeThrow2.nextState = &genDudeChaseL; if (dist > 5072 && Chance(0x5000)) { - if (!canDuck(pSprite) || Chance(0x4000)) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); - else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeD); + if (!canDuck(pSprite) || Chance(0x4000)) aiGenDudeNewState(pSprite, &genDudeDodgeShortL); + else aiGenDudeNewState(pSprite, &genDudeDodgeShortD); } else { - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + aiGenDudeNewState(pSprite, &genDudeChaseL); } } } return; case kModernThingThrowableRock: - if (Chance(0x4000)) aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); - else sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndTargetSpot); + if (Chance(0x4000)) aiGenDudeNewState(pSprite, &genDudeThrow2); + else playGenDudeSound(pSprite, kGenDudeSndTargetSpot); return; default: - aiNewState(pSprite, pXSprite, &GDXGenDudeThrow2); + aiGenDudeNewState(pSprite, &genDudeThrow2); return; } } else if (dist <= meleeVector->maxDist) { if (spriteIsUnderwater(pSprite, false)) { - if (Chance(0x9000)) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); + if (Chance(0x9000)) aiGenDudeNewState(pSprite, &genDudePunch); + else aiGenDudeNewState(pSprite, &genDudeDodgeW); } - else if (Chance(0x9000)) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); + else if (Chance(0x9000)) aiGenDudeNewState(pSprite, &genDudePunch); + else aiGenDudeNewState(pSprite, &genDudeDodgeL); return; } else { int state = checkAttackState(pSprite, pXSprite); - if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); + if (state == 1) aiGenDudeNewState(pSprite, &genDudeChaseW); else if (state == 2) { - if (Chance(0x5000)) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + if (Chance(0x5000)) aiGenDudeNewState(pSprite, &genDudeChaseD); + else aiGenDudeNewState(pSprite, &genDudeChaseL); } - else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + else aiGenDudeNewState(pSprite, &genDudeChaseL); return; } } @@ -538,13 +588,13 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { return; } else if (gGenDudeExtra[pSprite->index].slaveCount > gGameOptions.nDifficulty || dist < meleeVector->maxDist) { if (dist <= meleeVector->maxDist) { - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); + aiGenDudeNewState(pSprite, &genDudePunch); return; } else { int state = checkAttackState(pSprite, pXSprite); - if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - else if (state == 2) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + if (state == 1) aiGenDudeNewState(pSprite, &genDudeChaseW); + else if (state == 2) aiGenDudeNewState(pSprite, &genDudeChaseD); + else aiGenDudeNewState(pSprite, &genDudeChaseL); return; } } @@ -565,17 +615,17 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { case kMissileFireballTchernobog: if (dist > mdist || pXSprite->locked == 1) break; else if (dist <= meleeVector->maxDist && Chance(0x9000)) - aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - else if (state == 2) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - else aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + aiGenDudeNewState(pSprite, &genDudePunch); + else if (state == 1) aiGenDudeNewState(pSprite, &genDudeChaseW); + else if (state == 2) aiGenDudeNewState(pSprite, &genDudeChaseD); + else aiGenDudeNewState(pSprite, &genDudeChaseL); return; case kMissileFlameSpray: case kMissileFlameHound: if (spriteIsUnderwater(pSprite, false)) { - if (dist > meleeVector->maxDist) aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - else if (Chance(0x8000)) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); + if (dist > meleeVector->maxDist) aiGenDudeNewState(pSprite, &genDudeChaseW); + else if (Chance(0x8000)) aiGenDudeNewState(pSprite, &genDudePunch); + else aiGenDudeNewState(pSprite, &genDudeDodgeW); return; } @@ -585,75 +635,52 @@ static void thinkChase( spritetype* pSprite, XSPRITE* pXSprite ) { } else if (curWeapon >= kTrapExploder && curWeapon < (kTrapExploder + kExplodeMax) - 1) { int nType = curWeapon - kTrapExploder; EXPLOSION* pExpl = &explodeInfo[nType]; if (CheckProximity(pSprite, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum, pExpl->radius / 2)) { - xvel[pSprite->xvel] = zvel[pSprite->xvel] = yvel[pSprite->xvel] = 0; - if (doExplosion(pSprite, nType) && pXSprite->health > 0) actDamageSprite(pSprite->xvel, pSprite, DAMAGE_TYPE_3, 65535); - } return; - // scared dude - no weapon. Still can punch you sometimes. - } else { - - int state = checkAttackState(pSprite, pXSprite); - if (Chance(0x0500) && !spriteIsUnderwater(pSprite, false)) - sfxPlayGDXGenDudeSound(pSprite, kGenDudeSndChasing); - - if (Chance(0x0200)) { - if (dist <= meleeVector->maxDist) aiNewState(pSprite, pXSprite, &GDXGenDudePunch); - else if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeW); - else if (state == 2) aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeD); - else aiNewState(pSprite, pXSprite, &GDXGenDudeDodgeL); } - else if (state == 1) aiNewState(pSprite, pXSprite, &GDXGenDudeSearchW); - else aiNewState(pSprite, pXSprite, &GDXGenDudeSearchL); - aiSetTarget(pXSprite, pSprite->x, pSprite->y, pSprite->z); - return; - } - - if (dist <= vdist && pXSprite->aiState == &GDXGenDudeChaseD) - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); + //if (dist <= vdist && pXSprite->aiState == &genDudeChaseD) + //aiGenDudeNewState(pSprite, &genDudeChaseL); int state = checkAttackState(pSprite, pXSprite); - int kAngle = (dist <= 2048) ? kAngle = pDudeInfo->periphery : kAng5; - if (dist < vdist && klabs(losAngle) < kAngle) { + if (dist < vdist && klabs(losAngle) < kAngle) { switch (state) { case 1: - aiNewState(pSprite, pXSprite, &GDXGenDudeFireW); - pXSprite->aiState->at18 = &GDXGenDudeFireW; + aiGenDudeNewState(pSprite, &genDudeFireW); + pXSprite->aiState->nextState = &genDudeFireW; return; case 2: - aiNewState(pSprite, pXSprite, &GDXGenDudeFireD); - pXSprite->aiState->at18 = &GDXGenDudeFireD; + aiGenDudeNewState(pSprite, &genDudeFireD); + pXSprite->aiState->nextState = &genDudeFireD; return; default: - aiNewState(pSprite, pXSprite, &GDXGenDudeFireL); - pXSprite->aiState->at18 = &GDXGenDudeFireL; + aiGenDudeNewState(pSprite, &genDudeFireL); + pXSprite->aiState->nextState = &genDudeFireL; return; } - } else { if (seqGetID(3, pSprite->extra) == pXSprite->data2 + (state < 3) ? 8 : 6) { - if (state == 1) pXSprite->aiState->at18 = &GDXGenDudeChaseW; - else if (state == 2) pXSprite->aiState->at18 = &GDXGenDudeChaseD; - else pXSprite->aiState->at18 = &GDXGenDudeChaseL; + if (state == 1) pXSprite->aiState->nextState = &genDudeChaseW; + else if (state == 2) pXSprite->aiState->nextState = &genDudeChaseD; + else pXSprite->aiState->nextState = &genDudeChaseL; - } else if (state == 1 && pXSprite->aiState != &GDXGenDudeChaseW && pXSprite->aiState != &GDXGenDudeFireW) { - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseW); - pXSprite->aiState->at18 = &GDXGenDudeFireW; + } else if (state == 1 && pXSprite->aiState != &genDudeChaseW && pXSprite->aiState != &genDudeFireW) { + aiGenDudeNewState(pSprite, &genDudeChaseW); + pXSprite->aiState->nextState = &genDudeFireW; - } else if (state == 2 && pXSprite->aiState != &GDXGenDudeChaseD && pXSprite->aiState != &GDXGenDudeFireD) { - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseD); - pXSprite->aiState->at18 = &GDXGenDudeFireD; + } else if (state == 2 && pXSprite->aiState != &genDudeChaseD && pXSprite->aiState != &genDudeFireD) { + aiGenDudeNewState(pSprite, &genDudeChaseD); + pXSprite->aiState->nextState = &genDudeFireD; - } else if (pXSprite->aiState != &GDXGenDudeChaseL && pXSprite->aiState != &GDXGenDudeFireL) { - aiNewState(pSprite, pXSprite, &GDXGenDudeChaseL); - pXSprite->aiState->at18 = &GDXGenDudeFireL; + } else if (pXSprite->aiState != &genDudeChaseL && pXSprite->aiState != &genDudeFireL) { + aiGenDudeNewState(pSprite, &genDudeChaseL); + pXSprite->aiState->nextState = &genDudeFireL; } } @@ -732,22 +759,52 @@ int getGenDudeMoveSpeed(spritetype* pSprite,int which, bool mul, bool shift) { void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite ) { DUDEINFO* pDudeInfo = &dudeInfo[pSprite->type - kDudeBase]; - + GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; int maxTurn = pDudeInfo->angSpeed * 4 >> 4; + + if (pExtra->canFly) { + int nAng = ((pXSprite->goalAng + 1024 - pSprite->ang) & 2047) - 1024; + int nTurnRange = (pDudeInfo->angSpeed << 2) >> 4; + pSprite->ang = (pSprite->ang + ClipRange(nAng, -nTurnRange, nTurnRange)) & 2047; + int nAccel = pDudeInfo->frontSpeed << 2; + if (klabs(nAng) > 341) + return; + if (pXSprite->target == -1) + pSprite->ang = (pSprite->ang + 256) & 2047; + int dx = pXSprite->targetX - pSprite->x; + int dy = pXSprite->targetY - pSprite->y; + int UNUSED(nAngle) = getangle(dx, dy); + int nDist = approxDist(dx, dy); + if ((unsigned int)Random(64) < 32 && nDist <= 0x400) + return; + int nCos = Cos(pSprite->ang); + int nSin = Sin(pSprite->ang); + int vx = xvel[pSprite->index]; + int vy = yvel[pSprite->index]; + int t1 = dmulscale30(vx, nCos, vy, nSin); + int t2 = dmulscale30(vx, nSin, -vy, nCos); + if (pXSprite->target == -1) + t1 += nAccel; + else + t1 += nAccel >> 1; + xvel[pSprite->index] = dmulscale30(t1, nCos, t2, nSin); + yvel[pSprite->index] = dmulscale30(t1, nSin, -t2, nCos); + } else { int dang = ((kAng180 + pXSprite->goalAng - pSprite->ang) & 2047) - kAng180; pSprite->ang = ((pSprite->ang + ClipRange(dang, -maxTurn, maxTurn)) & 2047); - + // don't move forward if trying to turn around - if ( klabs(dang) > kAng60 ) + if (klabs(dang) > kAng60) return; - + int sin = Sin(pSprite->ang); int cos = Cos(pSprite->ang); int frontSpeed = gGenDudeExtra[pSprite->index].frontSpeed; xvel[pSprite->xvel] += mulscale(cos, frontSpeed, 30); yvel[pSprite->xvel] += mulscale(sin, frontSpeed, 30); + } } void aiGenDudeChooseDirection(spritetype* pSprite, XSPRITE* pXSprite, int a3, int xvel, int yvel) { @@ -756,6 +813,8 @@ void aiGenDudeChooseDirection(spritetype* pSprite, XSPRITE* pXSprite, int a3, in return; } + // TO-DO: Take in account if sprite is flip-x, so enemy select correct angle + int vc = ((a3 + 1024 - pSprite->ang) & 2047) - 1024; int t1 = dmulscale30(xvel, Cos(pSprite->ang), yvel, Sin(pSprite->ang)); int vsi = ((t1 * 15) >> 12) / 2; int v8 = (vc >= 0) ? 341 : -341; @@ -783,13 +842,83 @@ void aiGenDudeChooseDirection(spritetype* pSprite, XSPRITE* pXSprite, int a3, in pXSprite->dodgeDir = 0; } } + +void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState) { + if (!xspriRangeIsFine(pSprite->extra)) { + consoleSysMsg("!xspriRangeIsFine(pSprite->extra)"); + return; + } + + XSPRITE* pXSprite = &xsprite[pSprite->extra]; + + // redirect dudes which cannot walk to non-walk states + if (!gGenDudeExtra[pSprite->index].canWalk) { -bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode) { + if (pAIState == &genDudeDodgeL || pAIState == &genDudeDodgeShortL) + pAIState = &genDudeRecoilL; + + else if (pAIState == &genDudeDodgeD || pAIState == &genDudeDodgeShortD) + pAIState = &genDudeRecoilD; + + else if (pAIState == &genDudeDodgeW || pAIState == &genDudeDodgeD) + pAIState = &genDudeRecoilW; + + else if (pAIState == &genDudeSearchL) pAIState = &genDudeSearchNoWalkL; + else if (pAIState == &genDudeSearchW) pAIState = &genDudeSearchNoWalkW; + else if (pAIState == &genDudeGotoL) pAIState = &genDudeIdleL; + else if (pAIState == &genDudeGotoW) pAIState = &genDudeIdleW; + else if (pAIState == &genDudeChaseL) pAIState = &genDudeChaseNoWalkL; + else if (pAIState == &genDudeChaseD) pAIState = &genDudeChaseNoWalkD; + else if (pAIState == &genDudeChaseW) pAIState = &genDudeChaseNoWalkW; + else if (pAIState == &genDudeRecoilTesla) { + + if (spriteIsUnderwater(pSprite, false)) pAIState = &genDudeRecoilW; + else pAIState = &genDudeRecoilL; + + } + + } + + pXSprite->stateTimer = pAIState->stateTicks; pXSprite->aiState = pAIState; + int seqStartId = pXSprite->data2; + + if (pAIState->seqId >= 0 && gSysRes.Lookup((seqStartId += pAIState->seqId), "SEQ")) + seqSpawn(seqStartId, 3, pSprite->extra, pAIState->funcId); + + if (pAIState->enterFunc) + pAIState->enterFunc(pSprite, pXSprite); + +} + + +bool playGenDudeSound(spritetype* pSprite, int mode, bool forceInterrupt) { if (mode < kGenDudeSndTargetSpot || mode >= kGenDudeSndMax) return false; GENDUDESND* sndInfo =& gCustomDudeSnd[mode]; bool gotSnd = false; short sndStartId = xsprite[pSprite->extra].sysData1; int rand = sndInfo->randomRange; int sndId = (sndStartId <= 0) ? sndInfo->defaultSndId : sndStartId + sndInfo->sndIdOffset; + GENDUDEEXTRA* pExtra = genDudeExtra(pSprite); + + // let's check if there same sounds already played by other dudes + // so we won't get a lot of annoying screams in the same time and ensure sound played in it's full length (if not interruptable) + if (pExtra->sndPlaying && !sndInfo->interruptable) { + for (int i = 0; i < 256; i++) { + if (Bonkle[i].atc <= 0) continue; + for (int a = 0; a < rand; a++) { + if (sndId + a == Bonkle[i].atc) { + if (Bonkle[i].at0 <= 0) { + pExtra->sndPlaying = false; + break; + } + //viewSetSystemMessage("PLAYING %d / %d / %d", Bonkle[i].atc, (sndId + a), Bonkle[i].at0); + return true; + } + } + } + + pExtra->sndPlaying = false; + + } if (sndId < 0) return false; else if (sndStartId <= 0) { sndId += Random(rand); gotSnd = true; } @@ -820,22 +949,15 @@ bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode) { if (gotSnd == false) return false; else if (sndInfo->aiPlaySound) aiPlay3DSound(pSprite, sndId, AI_SFX_PRIORITY_2, -1); else sfxPlay3DSound(pSprite, sndId, -1, 0); + + pExtra->sndPlaying = true; return true; } -bool spriteIsUnderwater(spritetype* pSprite,bool oldWay) { - if (oldWay){ - if (xsprite[pSprite->extra].medium == kMediumWater || xsprite[pSprite->extra].medium == kMediumGoo) - return true; - return false; - } - - if (sector[pSprite->sectnum].extra < 0) return false; - else if (xsector[sector[pSprite->sectnum].extra].Underwater) - return true; - - return false; +bool spriteIsUnderwater(spritetype* pSprite, bool oldWay) { + return ((sector[pSprite->sectnum].extra >= 0 && xsector[sector[pSprite->sectnum].extra].Underwater) + || (oldWay && (xsprite[pSprite->extra].medium == kMediumWater || xsprite[pSprite->extra].medium == kMediumGoo))); } spritetype* leechIsDropped(spritetype* pSprite) { @@ -929,33 +1051,9 @@ void scaleDamage(XSPRITE* pXSprite) { for (int i = 0; i < kDmgMax; i++) curScale[i] = dudeInfo[kDudeModernCustom - kDudeBase].startDamage[i]; + // all enemies with vector weapons gets extra resistance to bullet damage if (curWeapon > 0 && curWeapon < kVectorMax) { - - switch (gVectorData[curWeapon].dmgType) { - case kDmgFall: - curScale[kDmgFall] = 64 + Random(64); - break; - case kDmgBurn: - curScale[kDmgBurn] = 64; - curScale[kDmgExplode] = 82; - break; - case kDmgBullet: - curScale[kDmgBullet] = 82 + Random(28); - break; - case kDmgExplode: - curScale[kDmgBurn] = 82; - curScale[kDmgExplode] = 64; - break; - case kDmgChoke: - curScale[kDmgChoke] = 16 + Random(16); - break; - case kDmgSpirit: - curScale[kDmgSpirit] = 32 + Random(10); - break; - case kDmgElectric: - curScale[kDmgElectric] = 64 + Random(16); - break; - } + //curScale[kDmgBullet] -= 10; // just copy damage resistance of dude that should be summoned } else if (curWeapon >= kDudeBase && curWeapon < kDudeMax) { @@ -966,7 +1064,7 @@ void scaleDamage(XSPRITE* pXSprite) { // these does not like the explosions and burning } else if (curWeapon >= kTrapExploder && curWeapon < (kTrapExploder + kExplodeMax) - 1) { - curScale[kDmgBurn] = 255; curScale[kDmgExplode] = 512; + curScale[kDmgBurn] = curScale[kDmgExplode] = 512; } else if (curWeapon >= kMissileBase && curWeapon < kThingMax) { @@ -1045,7 +1143,7 @@ void scaleDamage(XSPRITE* pXSprite) { curScale[kDmgBullet] -= 20; break; case kItemArmorFire: - curScale[kDmgBurn] -= 10; + curScale[kDmgBurn] -= 20; curScale[kDmgExplode] -= 10; break; case kItemArmorSpirit: @@ -1062,14 +1160,77 @@ void scaleDamage(XSPRITE* pXSprite) { // take in account yrepeat of sprite short yrepeat = sprite[pXSprite->reference].yrepeat; - if (yrepeat == 0) { - for (int i = 0; i < kDmgMax; i++) { - if (i != kDmgSpirit && i != kDmgChoke) curScale[i] = 500; - } - } else if (yrepeat < 64) { + if (yrepeat < 64) { for (int i = 0; i < kDmgMax; i++) curScale[i] += (64 - yrepeat); } else if (yrepeat > 64) { - for (int i = 0; i < kDmgMax; i++) curScale[i] -= (yrepeat - 64); + for (int i = 0; i < kDmgMax; i++) curScale[i] -= ((yrepeat - 64) / 2); + } + + // take surface type into account + int surfType = tileGetSurfType(sprite[pXSprite->reference].index + 0xc000); + //int surfType = 4; + switch (surfType) { + case 1: // stone + curScale[kDmgFall] = 0; + curScale[kDmgBullet] -= 128; + curScale[kDmgBurn] -= 50; + curScale[kDmgExplode] -= 40; + curScale[kDmgChoke] += 30; + curScale[kDmgElectric] += 20; + break; + case 2: // metal + curScale[kDmgFall] = 16; + curScale[kDmgBullet] -= 64; + curScale[kDmgBurn] -= 45; + curScale[kDmgExplode] -= 35; + curScale[kDmgChoke] += 20; + curScale[kDmgElectric] += 30; + break; + case 3: // wood + curScale[kDmgBullet] -= 5; + curScale[kDmgBurn] += 50; + curScale[kDmgExplode] += 40; + curScale[kDmgChoke] += 10; + curScale[kDmgElectric] -= 30; + break; + case 5: // water + case 6: // dirt + case 7: // clay + case 13: // goo + curScale[kDmgFall] = 8; + curScale[kDmgBullet] -= 10; + curScale[kDmgBurn] -= 128; + curScale[kDmgExplode] -= 30; + curScale[kDmgChoke] = 0; + curScale[kDmgElectric] += 40; + break; + case 8: // snow + case 9: // ice + curScale[kDmgFall] = 8; + curScale[kDmgBullet] -= 10; + curScale[kDmgBurn] -= 60; + curScale[kDmgExplode] -= 40; + curScale[kDmgChoke] = 0; + curScale[kDmgElectric] += 40; + break; + case 10: // leaves + case 12: // plant + curScale[kDmgFall] = 0; + curScale[kDmgBullet] -= 5; + curScale[kDmgBurn] += 70; + curScale[kDmgExplode] += 50; + break; + case 11: // cloth + curScale[kDmgFall] = 8; + curScale[kDmgBullet] -= 5; + curScale[kDmgBurn] += 30; + curScale[kDmgExplode] += 20; + break; + case 14: // lava + curScale[kDmgBurn] = 0; + curScale[kDmgExplode] = 0; + curScale[kDmgChoke] += 30; + break; } // finally, scale dmg for difficulty @@ -1077,13 +1238,18 @@ void scaleDamage(XSPRITE* pXSprite) { curScale[i] = mulscale8(DudeDifficulty[gGameOptions.nDifficulty], ClipLow(curScale[i], 1)); short* dc = curScale; - //viewSetSystemMessage("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]); + if (gGenDudeExtra[sprite[pXSprite->reference].index].canFly) { + curScale[0] = -1; + } + + if (pXSprite->rxID == 788) + viewSetSystemMessage("0: %d, 1: %d, 2: %d, 3: %d, 4: %d, 5: %d, 6: %d", dc[0], dc[1], dc[2], dc[3], dc[4], dc[5], dc[6]); } int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp) { // the faster fire rate, the less frames = more dispersion Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(xsprite[pSprite->extra].data2 + 6, "SEQ"); int disp = 1; - if ((pSeq = (Seq*)gSysRes.Load(hSeq)) != NULL) { + if (hSeq != NULL && (pSeq = (Seq*)gSysRes.Load(hSeq)) != NULL) { int nFrames = pSeq->nFrames; int ticks = pSeq->at8; int shots = 0; for (int i = 0; i <= pSeq->nFrames; i++) { if (pSeq->frames[i].at5_5) shots++; @@ -1124,42 +1290,26 @@ int getRangeAttackDist(spritetype* pSprite, int minDist, int maxDist) { return dist; } -// the distance counts from sprite size (the bigger sprite, the greater distance) -int getSeeDist(spritetype* pSprite, int startDist, int minDist, int maxDist) { - short y = tilesiz[pSprite->picnum].y; short yrepeat = pSprite->yrepeat; - int dist = 0; - - return dist; -} - int getBaseChanceModifier(int baseChance) { - return ((gGameOptions.nDifficulty > 0) ? baseChance - (0x0300 * gGameOptions.nDifficulty) : baseChance); + return ((gGameOptions.nDifficulty > 0) ? baseChance - (0x0500 * gGameOptions.nDifficulty) : baseChance); } int getRecoilChance(spritetype* pSprite) { - int mass = getSpriteMassBySize(pSprite); - int cumulDmg = 0; int baseChance = getBaseChanceModifier(0x8000); - if (pSprite->extra >= 0) { - XSPRITE pXSprite = xsprite[pSprite->extra]; - baseChance += (pXSprite.burnTime / 2); - cumulDmg = pXSprite.data3; - if (dudeIsMelee(&pXSprite)) - baseChance = 0x700; - } - - baseChance += cumulDmg; + XSPRITE* pXSprite = &xsprite[pSprite->extra]; int mass = getSpriteMassBySize(pSprite); + int baseChance = (!dudeIsMelee(pXSprite) ? 0x8000 : 0x5000); + baseChance = getBaseChanceModifier(baseChance) + pXSprite->data3; + int chance = ((baseChance / mass) << 7); return chance; - } int getDodgeChance(spritetype* pSprite) { - int mass = getSpriteMassBySize(pSprite); int baseChance = getBaseChanceModifier(0x4000); + int mass = getSpriteMassBySize(pSprite); int baseChance = getBaseChanceModifier(0x6000); if (pSprite->extra >= 0) { - XSPRITE pXSprite = xsprite[pSprite->extra]; - baseChance += pXSprite.burnTime; - if (dudeIsMelee(&pXSprite)) - baseChance = 0x400; + XSPRITE* pXSprite = &xsprite[pSprite->extra]; + baseChance += pXSprite->burnTime; + if (dudeIsMelee(pXSprite)) + baseChance = 0x1000; } int chance = ((baseChance / mass) << 7); @@ -1172,12 +1322,16 @@ void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT event) actPostSprite(pSprite->xvel, kStatFree); return; } - + int nTarget = pXSprite->target; - if (nTarget >= 0 && nTarget < kMaxSprites) { + if (spriRangeIsFine(nTarget)) { spritetype* pTarget = &sprite[nTarget]; - if (pTarget->statnum == kStatDude && !(pTarget->flags & 32) && pTarget->extra > 0 && pTarget->extra < kMaxXSprites && !pXSprite->stateTimer) - { + if (pTarget->statnum == kStatDude && !(pTarget->flags & 32) && pTarget->extra > 0 && pTarget->extra < kMaxXSprites && !pXSprite->stateTimer) { + + if (IsPlayerSprite(pTarget)) { + PLAYER* pPlayer = &gPlayer[pTarget->type - kDudePlayer1]; + if (powerupCheck(pPlayer, kPwUpShadowCloak) > 0) return; + } int top, bottom; GetSpriteExtents(pSprite, &top, &bottom); int nType = pTarget->type - kDudeBase; @@ -1186,8 +1340,7 @@ void dudeLeechOperate(spritetype* pSprite, XSPRITE* pXSprite, EVENT event) int x = pTarget->x; int y = pTarget->y; int z = pTarget->z; int nDist = approxDist(x - pSprite->x, y - pSprite->y); - if (nDist != 0 && cansee(pSprite->x, pSprite->y, top, pSprite->sectnum, x, y, z, pTarget->sectnum)) - { + if (nDist != 0 && cansee(pSprite->x, pSprite->y, top, pSprite->sectnum, x, y, z, pTarget->sectnum)) { int t = divscale(nDist, 0x1aaaaa, 12); x += (xvel[nTarget] * t) >> 12; y += (yvel[nTarget] * t) >> 12; @@ -1255,11 +1408,20 @@ void updateTargetOfLeech(spritetype* pSprite) { consoleSysMsg("pSprite->extra >= 0 && pSprite->extra < kMaxXSprites"); return; } - + + spritetype* pLeech = leechIsDropped(pSprite); if (pLeech == NULL || pLeech->extra < 0) gGenDudeExtra[pSprite->index].nLifeLeech = -1; - else if (xsprite[pSprite->extra].target != xsprite[pLeech->extra].target) - xsprite[pLeech->extra].target = xsprite[pSprite->extra].target; + else if (xsprite[pSprite->extra].target != xsprite[pLeech->extra].target) { + XSPRITE* pXDude = &xsprite[pSprite->extra]; XSPRITE* pXLeech = &xsprite[pLeech->extra]; + if (pXDude->target < 0 && spriRangeIsFine(pXLeech->target)) { + aiSetTarget(pXDude, pXLeech->target); + if (inIdle(pXDude->aiState)) + aiActivateDude(pSprite, pXDude); + } else { + pXLeech->target = pXDude->target; + } + } } void updateTargetOfSlaves(spritetype* pSprite) { @@ -1301,123 +1463,223 @@ void updateTargetOfSlaves(spritetype* pSprite) { } bool inDodge(AISTATE* aiState) { - return (aiState == &GDXGenDudeDodgeDmgW || aiState == &GDXGenDudeDodgeDmgL || aiState == &GDXGenDudeDodgeDmgD); + return (aiState == &genDudeDodgeShortW || aiState == &genDudeDodgeShortL || aiState == &genDudeDodgeShortD); } bool inIdle(AISTATE* aiState) { - return (aiState == &GDXGenDudeIdleW || aiState == &GDXGenDudeIdleL); + return (aiState == &genDudeIdleW || aiState == &genDudeIdleL); } -int getSeqStartId(XSPRITE* pXSprite) { - int seqStartId = dudeInfo[sprite[pXSprite->reference].type - kDudeBase].seqStartID; - // Store seqStartId in data2 field - if (pXSprite->data2 > 0) { - seqStartId = pXSprite->data2; - // check for full set of animations - for (int i = seqStartId; i <= seqStartId + 24; i++) { - - // exceptions - switch (i - seqStartId) { - case 3: // burning dude - case 4: // electrocution - case 8: // attack u/d - case 11: // reserved - case 12: // reserved - case 13: // move u - case 14: // move d - case 16: // burning death 2 - case 17: // idle w - case 18: // transformation in another dude - case 19: // reserved - case 20: // reserved - case 21: // reserved - case 22: // reserved - case 23: // reserved - case 24: // reserved - continue; - } - - if (!gSysRes.Lookup(i, "SEQ")) { - pXSprite->data2 = dudeInfo[sprite[pXSprite->reference].type - kDudeBase].seqStartID; - viewSetSystemMessage("No SEQ animation id %d found for custom dude #%d!", i, sprite[pXSprite->reference].index); - viewSetSystemMessage("SEQ base id: %d", pXSprite->data2); - return pXSprite->data2; - } - - } - - } else { - pXSprite->data2 = seqStartId; - } - - return seqStartId; +bool inAttack(AISTATE* aiState) { + return (aiState == &genDudeFireL || aiState == &genDudeFireW + || aiState == &genDudeFireD || aiState == &genDudeThrow || aiState == &genDudeThrow2 || aiState == &genDudePunch); } -void genDudePrepare(spritetype* pSprite, int propId) { +short inSearch(AISTATE* aiState) { + if (aiState->stateType == kAiStateSearch) return 1; + return 0; +} + +short inRecoil(AISTATE* aiState) { + if (aiState == &genDudeRecoilL || aiState == &genDudeRecoilTesla) return 1; + else if (aiState == &genDudeRecoilD) return 2; + else if (aiState == &genDudeRecoilW) return 3; + else return 0; +} + +short inDuck(AISTATE* aiState) { + if (aiState == &genDudeFireD) return 1; + else if (aiState == &genDudeChaseD) return 2; + else if (aiState == &genDudeChaseNoWalkD) return 3; + else if (aiState == &genDudeRecoilD) return 4; + else if (aiState == &genDudeDodgeShortD) return 5; + return 0; +} + + +bool canSwim(spritetype* pSprite) { + return gGenDudeExtra[pSprite->index].canSwim; +} + +bool canDuck(spritetype* pSprite) { + return gGenDudeExtra[pSprite->index].canDuck; +} + +bool canWalk(spritetype* pSprite) { + return gGenDudeExtra[pSprite->index].canWalk; +} + + +int genDudeSeqStartId(XSPRITE* pXSprite) { + if (genDudePrepare(&sprite[pXSprite->reference], kGenDudePropertyStates)) return pXSprite->data2; + else return kGenDudeDefaultSeq; +} + +bool genDudePrepare(spritetype* pSprite, int propId) { if (!(pSprite->index >= 0 && pSprite->index < kMaxSprites)) { consoleSysMsg("pSprite->index >= 0 && pSprite->index < kMaxSprites"); - return; + return false; } else if (!(pSprite->extra >= 0 && pSprite->extra < kMaxXSprites)) { consoleSysMsg("pSprite->extra >= 0 && pSprite->extra < kMaxXSprites"); - return; + return false; } else if (pSprite->type != kDudeModernCustom) { consoleSysMsg("pSprite->type != kDudeModernCustom"); - return; + return false; + } else if (propId < kGenDudePropertyAll || propId >= kGenDudePropertyMax) { + viewSetSystemMessage("Unknown custom dude #%d property (%d)", pSprite->index, propId); + return false; } - XSPRITE* pXSprite = &xsprite[pSprite->extra]; GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; + XSPRITE* pXSprite = &xsprite[pSprite->extra]; + GENDUDEEXTRA* pExtra = &gGenDudeExtra[pSprite->index]; pExtra->updReq[propId] = false; + switch (propId) { case kGenDudePropertyAll: - pExtra->updReq[propId] = false; - case kGenDudePropertyWeapon: - //viewSetSystemMessage("PROPERTY: WEAPONS"); + case kGenDudePropertyInitVals: + pExtra->frontSpeed = getGenDudeMoveSpeed(pSprite, 0, true, false); + pExtra->initVals[0] = pSprite->xrepeat; + pExtra->initVals[1] = pSprite->yrepeat; + pExtra->initVals[2] = pSprite->clipdist; + if (propId) break; + case kGenDudePropertyWeapon: { pExtra->curWeapon = pXSprite->data1; switch (pXSprite->data1) { - case 19: - pExtra->curWeapon = 2; - break; - case 310: - pExtra->curWeapon = kMissileArcGargoyle; - break; - case kThingDroppedLifeLeech: - pExtra->curWeapon = kModernThingEnemyLifeLeech; - break; + case 19: pExtra->curWeapon = 2; break; + case 310: pExtra->curWeapon = kMissileArcGargoyle; break; + case kThingDroppedLifeLeech: pExtra->curWeapon = kModernThingEnemyLifeLeech; break; } - pExtra->updReq[propId] = false; + + pExtra->canAttack = false; + if (pExtra->curWeapon > 0 && gSysRes.Lookup(pXSprite->data2 + kGenDudeSeqAttackNormalL, "SEQ")) + pExtra->canAttack = true; + + pExtra->isMelee = false; + if (pExtra->curWeapon >= kTrapExploder && pExtra->curWeapon < (kTrapExploder + kExplodeMax) - 1) pExtra->isMelee = true; + else if (pExtra->curWeapon >= 0 && pExtra->curWeapon < kVectorMax) { + if (gVectorData[pExtra->curWeapon].maxDist > 0 && gVectorData[pExtra->curWeapon].maxDist <= kGenDudeMaxMeleeDist) + pExtra->isMelee = true; + } + if (propId) break; - case kGenDudePropertyDamage: - //viewSetSystemMessage("PROPERTY: DAMAGE SCALE"); + } + case kGenDudePropertyDmgScale: scaleDamage(pXSprite); - pExtra->updReq[propId] = false; if (propId) break; case kGenDudePropertyMass: { - //viewSetSystemMessage("PROPERTY: MASS"); - // to ensure mass get's updated, let's clear all cache SPRITEMASS* pMass = &gSpriteMass[pSprite->index]; pMass->seqId = pMass->picnum = pMass->xrepeat = pMass->yrepeat = pMass->clipdist = 0; pMass->mass = pMass->airVel = pMass->fraction = 0; getSpriteMassBySize(pSprite); - pExtra->updReq[propId] = false; if (propId) break; } case kGenDudePropertyAttack: - //viewSetSystemMessage("PROPERTY: ATTACK"); pExtra->fireDist = getRangeAttackDist(pSprite, 1200, 45000); - pExtra->throwDist = gGenDudeExtra[pSprite->index].fireDist; // temp + pExtra->throwDist = pExtra->fireDist; // temp pExtra->baseDispersion = getDispersionModifier(pSprite, 200, 3500); - pExtra->updReq[propId] = false; if (propId) break; - case kGenDudePropertyStates: - //viewSetSystemMessage("PROPERTY: STATES"); - pExtra->frontSpeed = getGenDudeMoveSpeed(pSprite, 0, true, false); + case kGenDudePropertyStates: { + pExtra->canFly = false; - pExtra->canDuck = (gSysRes.Lookup(pXSprite->data2 + 8, "SEQ") && gSysRes.Lookup(pXSprite->data2 + 14, "SEQ")); - pExtra->canSwim = (gSysRes.Lookup(pXSprite->data2 + 8, "SEQ") && gSysRes.Lookup(pXSprite->data2 + 13, "SEQ") - && gSysRes.Lookup(pXSprite->data2 + 17, "SEQ")); - pExtra->updReq[propId] = false; + + // check the animation + int seqStartId = dudeInfo[pSprite->type - kDudeBase].seqStartID; + if (pXSprite->data2 <= 0) seqStartId = pXSprite->data2 = dudeInfo[pSprite->type - kDudeBase].seqStartID; + else seqStartId = pXSprite->data2; + + for (int i = seqStartId; i < seqStartId + kGenDudeSeqMax; i++) { + switch (i - seqStartId) { + case kGenDudeSeqIdleL: + case kGenDudeSeqDeathDefault: + if (!gSysRes.Lookup(i, "SEQ")) { + pXSprite->data2 = dudeInfo[pSprite->type - kDudeBase].seqStartID; + viewSetSystemMessage("No SEQ animation id %d found for custom dude #%d!", i, pSprite->index); + viewSetSystemMessage("SEQ base id: %d", seqStartId); + } + break; + case kGenDudeSeqDeathExplode: + if (gSysRes.Lookup(i, "SEQ")) pExtra->availDeaths[kDmgExplode] = 1; + else pExtra->availDeaths[kDmgExplode] = 0; + break; + case kGenDudeSeqAttackNormalL: + pExtra->canAttack = (gSysRes.Lookup(i, "SEQ") && pExtra->curWeapon > 0); + break; + case kGenDudeSeqBurning: + pExtra->canBurn = gSysRes.Lookup(i, "SEQ"); + break; + case kGenDudeSeqElectocuted: + pExtra->canElectrocute = gSysRes.Lookup(i, "SEQ"); + break; + case kGenDudeSeqRecoil: + pExtra->canRecoil = gSysRes.Lookup(i, "SEQ"); + break; + case kGenDudeSeqMoveL: { + bool oldStatus = pExtra->canWalk; + pExtra->canWalk = gSysRes.Lookup(i, "SEQ"); + if (oldStatus != pExtra->canWalk) { + if (!spriRangeIsFine(pXSprite->target)) { + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeIdleW); + else aiGenDudeNewState(pSprite, &genDudeIdleL); + } else if (pExtra->canWalk) { + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseW); + else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseD); + else aiGenDudeNewState(pSprite, &genDudeChaseL); + } else { + if (spriteIsUnderwater(pSprite, false)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkW); + else if (inDuck(pXSprite->aiState)) aiGenDudeNewState(pSprite, &genDudeChaseNoWalkD); + else aiGenDudeNewState(pSprite, &genDudeChaseNoWalkL); + } + } + break; + } + case kGenDudeSeqAttackPunch: { + pExtra->forcePunch = true; // required for those who don't have fire trigger in punch seq and for default animation + Seq* pSeq = NULL; DICTNODE* hSeq = gSysRes.Lookup(i, "SEQ"); + if (hSeq != NULL) { + pSeq = (Seq*)gSysRes.Load(hSeq); + for (int i = 0; i < pSeq->nFrames; i++) { + if (!pSeq->frames[i].at5_5) continue; + pExtra->forcePunch = false; + break; + } + } + break; + } + case kGenDudeSeqAttackNormalDW: + pExtra->canDuck = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 14, "SEQ")); + pExtra->canSwim = (gSysRes.Lookup(i, "SEQ") && gSysRes.Lookup(seqStartId + 13, "SEQ") + && gSysRes.Lookup(seqStartId + 17, "SEQ")); + break; + case kGenDudeSeqDeathBurn1: { + bool seq15 = gSysRes.Lookup(i, "SEQ"); bool seq16 = gSysRes.Lookup(seqStartId + 16, "SEQ"); + if (seq15 && seq16) pExtra->availDeaths[kDmgBurn] = 3; + else if (seq16) pExtra->availDeaths[kDmgBurn] = 2; + else if (seq15) pExtra->availDeaths[kDmgBurn] = 1; + else pExtra->availDeaths[kDmgBurn] = 0; + break; + } + case kGenDudeSeqMoveW: + case kGenDudeSeqMoveD: + case kGenDudeSeqDeathBurn2: + case kGenDudeSeqIdleW: + continue; + case kGenDudeSeqReserved3: + case kGenDudeSeqReserved4: + case kGenDudeSeqReserved5: + case kGenDudeSeqReserved6: + case kGenDudeSeqReserved7: + case kGenDudeSeqReserved8: + /*if (gSysRes.Lookup(i, "SEQ")) { + viewSetSystemMessage("Found reserved SEQ animation (%d) for custom dude #%d!", i, pSprite->index); + viewSetSystemMessage("Using reserved animation is not recommended."); + viewSetSystemMessage("SEQ base id: %d", seqStartId); + }*/ + break; + } + } if (propId) break; + } case kGenDudePropertyLeech: //viewSetSystemMessage("PROPERTY: LEECH"); pExtra->nLifeLeech = -1; @@ -1429,7 +1691,6 @@ void genDudePrepare(spritetype* pSprite, int propId) { } } } - pExtra->updReq[propId] = false; if (propId) break; case kGenDudePropertySlaves: //viewSetSystemMessage("PROPERTY: SLAVES"); @@ -1445,39 +1706,28 @@ void genDudePrepare(spritetype* pSprite, int propId) { if (pExtra->slaveCount > gGameOptions.nDifficulty) break; } - pExtra->updReq[propId] = false; if (propId) break; - case kGenDudePropertyMelee: { - //viewSetSystemMessage("PROPERTY: MELEE"); - short curWeapon = pExtra->curWeapon; - pExtra->isMelee = false; int meleeDist = 2048; - if (curWeapon >= kTrapExploder && curWeapon < (kTrapExploder + kExplodeMax) - 1) { - pExtra->isMelee = true; - } else if (curWeapon >= 0 && curWeapon < kVectorMax) { - if (gVectorData[curWeapon].maxDist > 0 && gVectorData[curWeapon].maxDist <= meleeDist) - pExtra->isMelee = true; + case kGenDudePropertySpriteSize: { + if (seqGetStatus(3, pSprite->extra) == -1) + seqSpawn(pXSprite->data2 + pXSprite->aiState->seqId, 3, pSprite->extra, -1); + + // make sure dudes aren't in the floor or ceiling + int zTop, zBot; GetSpriteExtents(pSprite, &zTop, &zBot); + if (!(sector[pSprite->sectnum].ceilingstat & 0x0001)) + pSprite->z += ClipLow(sector[pSprite->sectnum].ceilingz - zTop, 0); + if (!(sector[pSprite->sectnum].floorstat & 0x0001)) + pSprite->z += ClipHigh(sector[pSprite->sectnum].floorz - zBot, 0); + + int curSumm = pSprite->xrepeat + pSprite->yrepeat; int defSumm = pExtra->initVals[0] + pExtra->initVals[1]; + if (curSumm < defSumm) pSprite->clipdist = ClipLow(curSumm >> 1, 4); + else if (curSumm > defSumm) pSprite->clipdist = ClipHigh(curSumm >> 1, 255); + else pSprite->clipdist = pExtra->initVals[2]; + + if (propId) break; } - pExtra->updReq[propId] = false; } - break; - default: - viewSetSystemMessage("Unknown custom dude #%d property (%d)", pSprite->index, propId); - break; - } -} -bool canSwim(spritetype* pSprite) { - return gGenDudeExtra[pSprite->index].canSwim; + return true; } -bool canDuck(spritetype* pSprite) { - return gGenDudeExtra[pSprite->index].canDuck; -} - -bool canWalk(spritetype* pSprite) { - return gGenDudeExtra[pSprite->index].canWalk; -} - -////////// - END_BLD_NS diff --git a/source/blood/src/aiunicult.h b/source/blood/src/aiunicult.h index 1cfa1a113..04395f43d 100644 --- a/source/blood/src/aiunicult.h +++ b/source/blood/src/aiunicult.h @@ -26,9 +26,40 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "eventq.h" BEGIN_BLD_NS - -#define kDefaultAnimationBase 11520 +#define kGenDudeDefaultSeq 11520 #define kGenDudeMaxSlaves 7 +#define kGenDudeTransformStatus -222 +#define kGenDudeUpdTimeRate 10 +#define kGenDudeMaxMeleeDist 2048 + +enum { +kGenDudeSeqIdleL = 0, +kGenDudeSeqDeathDefault = 1, +kGenDudeSeqDeathExplode = 2, +kGenDudeSeqBurning = 3, +kGenDudeSeqElectocuted = 4, +kGenDudeSeqRecoil = 5, +kGenDudeSeqAttackNormalL = 6, +kGenDudeSeqAttackThrow = 7, +kGenDudeSeqAttackNormalDW = 8, +kGenDudeSeqMoveL = 9, +kGenDudeSeqAttackPunch = 10, +kGenDudeSeqReserved1 = 11, +kGenDudeSeqReserved2 = 12, +kGenDudeSeqMoveW = 13, +kGenDudeSeqMoveD = 14, +kGenDudeSeqDeathBurn1 = 15, +kGenDudeSeqDeathBurn2 = 16, +kGenDudeSeqIdleW = 17, +kGenDudeSeqTransform = 18, +kGenDudeSeqReserved3 = 19, +kGenDudeSeqReserved4 = 20, +kGenDudeSeqReserved5 = 21, +kGenDudeSeqReserved6 = 22, +kGenDudeSeqReserved7 = 23, +kGenDudeSeqReserved8 = 24, +kGenDudeSeqMax , +}; enum { kGenDudeSndTargetSpot = 0, @@ -48,44 +79,47 @@ kGenDudeSndMax , enum { kGenDudePropertyAll = 0, kGenDudePropertyWeapon = 1, -kGenDudePropertyDamage = 2, +kGenDudePropertyDmgScale = 2, kGenDudePropertyMass = 3, kGenDudePropertyAttack = 4, kGenDudePropertyStates = 5, kGenDudePropertyLeech = 6, kGenDudePropertySlaves = 7, -kGenDudePropertyMelee = 8, -kGenDudePropertyClipdist = 9, +kGenDudePropertySpriteSize = 8, +kGenDudePropertyInitVals = 9, kGenDudePropertyMax , }; - -extern AISTATE GDXGenDudeIdleL; -extern AISTATE GDXGenDudeIdleW; -extern AISTATE GDXGenDudeSearchL; -extern AISTATE GDXGenDudeSearchW; -extern AISTATE GDXGenDudeGotoL; -extern AISTATE GDXGenDudeGotoW; -extern AISTATE GDXGenDudeDodgeL; -extern AISTATE GDXGenDudeDodgeD; -extern AISTATE GDXGenDudeDodgeW; -extern AISTATE GDXGenDudeDodgeDmgL; -extern AISTATE GDXGenDudeDodgeDmgD; -extern AISTATE GDXGenDudeDodgeDmgW; -extern AISTATE GDXGenDudeChaseL; -extern AISTATE GDXGenDudeChaseD; -extern AISTATE GDXGenDudeChaseW; -extern AISTATE GDXGenDudeFireL; -extern AISTATE GDXGenDudeFireD; -extern AISTATE GDXGenDudeFireW; -extern AISTATE GDXGenDudeRecoilL; -extern AISTATE GDXGenDudeRecoilD; -extern AISTATE GDXGenDudeRecoilW; -extern AISTATE GDXGenDudeThrow; -extern AISTATE GDXGenDudeThrow2; -extern AISTATE GDXGenDudePunch; -extern AISTATE GDXGenDudeRTesla; -extern AISTATE GDXGenDudeTransform; +extern AISTATE genDudeIdleL; +extern AISTATE genDudeIdleW; +extern AISTATE genDudeSearchL; +extern AISTATE genDudeSearchW; +extern AISTATE genDudeGotoL; +extern AISTATE genDudeGotoW; +extern AISTATE genDudeDodgeL; +extern AISTATE genDudeDodgeD; +extern AISTATE genDudeDodgeW; +extern AISTATE genDudeDodgeShortL; +extern AISTATE genDudeDodgeShortD; +extern AISTATE genDudeDodgeShortW; +extern AISTATE genDudeChaseL; +extern AISTATE genDudeChaseD; +extern AISTATE genDudeChaseW; +extern AISTATE genDudeFireL; +extern AISTATE genDudeFireD; +extern AISTATE genDudeFireW; +extern AISTATE genDudeRecoilL; +extern AISTATE genDudeRecoilD; +extern AISTATE genDudeRecoilW; +extern AISTATE genDudeThrow; +extern AISTATE genDudeThrow2; +extern AISTATE genDudePunch; +extern AISTATE genDudeRecoilTesla; +extern AISTATE genDudeSearchNoWalkL; +extern AISTATE genDudeSearchNoWalkW; +extern AISTATE genDudeChaseNoWalkL; +extern AISTATE genDudeChaseNoWalkD; +extern AISTATE genDudeChaseNoWalkW; struct GENDUDESND { @@ -93,6 +127,7 @@ struct GENDUDESND int randomRange; int sndIdOffset; // relative to data3 bool aiPlaySound; // false = sfxStart3DSound(); + bool interruptable; }; extern GENDUDESND gCustomDudeSnd[]; @@ -105,29 +140,41 @@ struct GENDUDEEXTRA { unsigned short curWeapon; // data1 duplicate to avoid potential problems when changing data dynamically unsigned short baseDispersion; signed short nLifeLeech; // spritenum of dropped dude's leech - short dmgControl[kDamageMax]; // depends of current weapon, drop armor item and sprite yrepeat - short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon short slaveCount; + short slave[kGenDudeMaxSlaves]; // index of the ones dude is summon + short dmgControl[kDamageMax]; // depends of current weapon, drop armor item, sprite yrepeat and surface type + short availDeaths[kDamageMax]; // list of seqs with deaths for each damage type + short initVals[3]; // xrepeat, yrepeat, clipdist + bool forcePunch; // indicate if there is no fire trigger in punch state seq bool updReq[kGenDudePropertyMax]; // update requests + bool sndPlaying; // indicate if sound of AISTATE currently playing bool isMelee; + bool canBurn; // can turn in Burning dude or not + bool canElectrocute; + bool canAttack; + bool canRecoil; bool canWalk; bool canDuck; bool canSwim; bool canFly; - }; extern GENDUDEEXTRA gGenDudeExtra[]; +inline GENDUDEEXTRA* genDudeExtra(spritetype* pSprite) { + return &gGenDudeExtra[pSprite->index]; +} + XSPRITE* getNextIncarnation(XSPRITE* pXSprite); void killDudeLeech(spritetype* pLeech); void removeLeech(spritetype* pLeech, bool delSprite = true); void removeDudeStuff(spritetype* pSprite); spritetype* leechIsDropped(spritetype* pSprite); -bool spriteIsUnderwater(spritetype* pSprite, bool oldWay); -bool sfxPlayGDXGenDudeSound(spritetype* pSprite, int mode); +bool spriteIsUnderwater(spritetype* pSprite, bool oldWay = false); +bool playGenDudeSound(spritetype* pSprite, int mode, bool forceInterrupt = false); void aiGenDudeMoveForward(spritetype* pSprite, XSPRITE* pXSprite); void aiGenDudeChooseDirection(spritetype* pSprite, XSPRITE* pXSprite, int a3, int aXvel = -1, int aYvel = -1); +void aiGenDudeNewState(spritetype* pSprite, AISTATE* pAIState); int getGenDudeMoveSpeed(spritetype* pSprite, int which, bool mul, bool shift); bool TargetNearThing(spritetype* pSprite, int thingType); int checkAttackState(spritetype* pSprite, XSPRITE* pXSprite); @@ -143,12 +190,16 @@ bool canDuck(spritetype* pSprite); bool canWalk(spritetype* pSprite); bool inDodge(AISTATE* aiState); bool inIdle(AISTATE* aiState); -int getSeqStartId(XSPRITE* pXSprite); -int getSeeDist(spritetype* pSprite, int startDist, int minDist, int maxDist); +bool inAttack(AISTATE* aiState); +short inRecoil(AISTATE* aiState); +short inSearch(AISTATE* aiState); +short inDuck(AISTATE* aiState); +int genDudeSeqStartId(XSPRITE* pXSprite); int getRangeAttackDist(spritetype* pSprite, int minDist = 1200, int maxDist = 80000); int getDispersionModifier(spritetype* pSprite, int minDisp, int maxDisp); void scaleDamage(XSPRITE* pXSprite); -void genDudePrepare(spritetype* pSprite, int propId = kGenDudePropertyAll); +bool genDudePrepare(spritetype* pSprite, int propId = kGenDudePropertyAll); void genDudeUpdate(spritetype* pSprite); +void genDudeProcess(spritetype* pSprite, XSPRITE* pXSprite); END_BLD_NS diff --git a/source/blood/src/blood.cpp b/source/blood/src/blood.cpp index be0f0327b..e97287208 100644 --- a/source/blood/src/blood.cpp +++ b/source/blood/src/blood.cpp @@ -608,6 +608,7 @@ void StartLevel(GAMEOPTIONS *gameOptions) case kModernObjDataAccumulator: case kModernEffectSpawner: case kModernWindGenerator: + case kModernPlayerControl: pSprite->type = kSpriteDecoration; break; case kItemModernMapLevel: diff --git a/source/blood/src/callback.cpp b/source/blood/src/callback.cpp index 16397feb2..1357ab7b7 100644 --- a/source/blood/src/callback.cpp +++ b/source/blood/src/callback.cpp @@ -45,6 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "trig.h" #include "triggers.h" #include "view.h" +#include "aiunicult.h" BEGIN_BLD_NS @@ -763,6 +764,12 @@ void makeMissileBlocking(int nSprite) // 23 sprite[nSprite].cstat |= CSTAT_SPRITE_BLOCK; } +void genDudeUpdateCallback(int nSprite) // 24 +{ + if (spriRangeIsFine(nSprite)) + genDudeUpdate(&sprite[nSprite]); +} + void(*gCallback[kCallbackMax])(int) = { fxFlameLick, @@ -789,6 +796,7 @@ void(*gCallback[kCallbackMax])(int) = DropVoodoo, // unused UniMissileBurst, makeMissileBlocking, + genDudeUpdateCallback, }; END_BLD_NS diff --git a/source/blood/src/callback.h b/source/blood/src/callback.h index d01f95fd8..ef98a19cb 100644 --- a/source/blood/src/callback.h +++ b/source/blood/src/callback.h @@ -51,6 +51,7 @@ enum CALLBACK_ID { kCallbackDropVoodoo = 21, // unused kCallbackMissileBurst = 22, // by NoOne kCallbackMissileSpriteBlock = 23, // by NoOne + kCallbackGenDudeUpdate = 24, // by NoOne kCallbackMax, }; diff --git a/source/blood/src/common_game.h b/source/blood/src/common_game.h index 60d93d6c8..e12eeb48f 100644 --- a/source/blood/src/common_game.h +++ b/source/blood/src/common_game.h @@ -436,6 +436,17 @@ enum { kSectorMax = 620, }; +// ai state types +enum { +kAiStateOther = -1, +kAiStateIdle = 0, +kAiStateGenIdle = 1, +kAiStateMove = 2, +kAiStateSearch = 3, +kAiStateChase = 4, +kAiStateRecoil = 5, +kAiStateAttack = 6, +}; // sprite attributes #define kHitagAutoAim 0x0008 @@ -472,16 +483,6 @@ enum { #define kSecCFloorShade 0x8000 -// ai state types -#define kAiStateOther -1 -#define kAiStateIdle 0 -#define kAiStateGenIdle 1 -#define kAiStateMove 2 -#define kAiStateSearch 3 -#define kAiStateChase 4 -#define kAiStateRecoil 5 - - #define kAng5 28 #define kAng15 85 #define kAng30 170 diff --git a/source/blood/src/db.h b/source/blood/src/db.h index b799342dd..d3aae502d 100644 --- a/source/blood/src/db.h +++ b/source/blood/src/db.h @@ -32,7 +32,7 @@ BEGIN_BLD_NS #define kMaxSuperXSprites 128 // by NoOne: functions to quckly check range of specifical arrays -inline bool xsprRangeIsFine(int nXindex) { +inline bool xspriRangeIsFine(int nXindex) { return (nXindex >= 0 && nXindex < kMaxXSprites); } @@ -44,6 +44,10 @@ inline bool xwallRangeIsFine(int nXindex) { return (nXindex >= 0 && nXindex < kMaxXWalls); } +inline bool xspriIsFine(int nIndex) { + return (nIndex >= 0 && nIndex < kMaxSprites && !(sprite[nIndex].flags & 32) && sprite[nIndex].statnum != kStatFree); +} + extern bool gModernMap; #pragma pack(push, 1) diff --git a/source/blood/src/dude.cpp b/source/blood/src/dude.cpp index 192a95d26..31e6d6f98 100644 --- a/source/blood/src/dude.cpp +++ b/source/blood/src/dude.cpp @@ -1544,7 +1544,7 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] = 0, 0 }, - //254 - kGDXUniversalCultist + //254 - kDudeModernCustom { 11520, // start sequence ID 85, // start health @@ -1570,12 +1570,12 @@ DUDEINFO dudeInfo[kDudeMax-kDudeBase] = 256, // angSpeed // 0, 7, -1, 18, // nGibType - 128, 128, 128, 128, 128, 128, 128, + 128, 150, 128, 256, 128, 128, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, - //255 - kGDXGenDudeBurning + //255 - kDudeModernCustomBurning { 4096, // start sequence ID 25, // start health diff --git a/source/blood/src/endgame.cpp b/source/blood/src/endgame.cpp index c69e0dd69..d453362e6 100644 --- a/source/blood/src/endgame.cpp +++ b/source/blood/src/endgame.cpp @@ -158,45 +158,6 @@ void CKillMgr::sub_2641C(void) } } -/* -void CKillMgr::AddKill(spritetype *pSprite) { - if (pSprite->statnum == kStatDude) { - switch (pSprite->type) { - case kDudeBat: - case kDudeRat: - case kDudeBurningInnocent: - case kDudeInnocent: - return; - } - - at4++; - } -} - -void CKillMgr::sub_2641C(void) -{ - at0 = 0; - for (int nSprite = headspritestat[kStatDude]; nSprite >= 0; nSprite = nextspritestat[nSprite]) { - - spritetype *pSprite = &sprite[nSprite]; - if (IsDudeSprite(pSprite)) { - if (pSprite->statnum == kStatDude) { - switch (pSprite->type) { - case kDudeBat: - case kDudeRat: - case kDudeBurningInnocent: - case kDudeInnocent: - return; - } - - at0++; - } - } - - } -} -*/ - void CKillMgr::Draw(void) { char pBuffer[40]; diff --git a/source/blood/src/eventq.cpp b/source/blood/src/eventq.cpp index d09183f8b..9ea7d78ba 100644 --- a/source/blood/src/eventq.cpp +++ b/source/blood/src/eventq.cpp @@ -427,11 +427,12 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command, short causedBy) break; } - //by NoOne: allow to send commands on player sprites + if (gModernMap) { + // allow to send commands on player sprites PLAYER* pPlayer = NULL; - if (rxId >= kChannelPlayer0 && rxId <= kChannelPlayer7) { + if (playerRXRngIsFine(rxId)) { if ((pPlayer = getPlayerById((kChannelPlayer0 - kChannelPlayer7) + kMaxPlayers)) != NULL) trMessageSprite(pPlayer->nSprite, event); } else if (rxId == kChannelAllPlayers) { @@ -439,6 +440,9 @@ void evSend(int nIndex, int nType, int rxId, COMMAND_ID command, short causedBy) if ((pPlayer = getPlayerById(i)) != NULL) trMessageSprite(pPlayer->nSprite, event); } + // send command on sprite which create the event sequence + } else if (rxId == kChannelEventCauser && spriRangeIsFine(event.causedBy)) { + trMessageSprite(event.causedBy, event); } } diff --git a/source/blood/src/eventq.h b/source/blood/src/eventq.h index 34fe642ab..279a055e9 100644 --- a/source/blood/src/eventq.h +++ b/source/blood/src/eventq.h @@ -40,9 +40,8 @@ kChannelLevelStartCoop, kChannelLevelStartTeamsOnly, kChannelPlayerDeathTeamA = 15, kChannelPlayerDeathTeamB, - -// by NoOne: RX channels of players to send commands on ///////////////////////////// +// channels of players to send commands on kChannelPlayer0 = 30, kChannelPlayer1, kChannelPlayer2, @@ -52,10 +51,11 @@ kChannelPlayer5, kChannelPlayer6, kChannelPlayer7, kChannelAllPlayers = kChannelPlayer0 + kMaxPlayers, +// channel of event causer +kChannelEventCauser = 50, +// map requires modern features to work properly +kChannelMapModernize = 60, ///////////////////////////// - -kChannelMapModernize = 60, // map requires modern features to work properly - kChannelTeamAFlagCaptured = 80, kChannelTeamBFlagCaptured, kChannelRemoteBomb0 = 90, @@ -79,44 +79,44 @@ extern RXBUCKET rxBucket[]; extern unsigned short bucketHead[]; enum COMMAND_ID { - kCmdOff = 0, - kCmdOn = 1, - kCmdState = 2, - kCmdToggle = 3, - kCmdNotState = 4, - kCmdLink = 5, - kCmdLock = 6, - kCmdUnlock = 7, - kCmdToggleLock = 8, - kCmdStopOff = 9, - kCmdStopOn = 10, - kCmdStopNext = 11, - kCmdCounterSector = 12, - kCmdCallback = 20, - kCmdRepeat = 21, +kCmdOff = 0, +kCmdOn = 1, +kCmdState = 2, +kCmdToggle = 3, +kCmdNotState = 4, +kCmdLink = 5, +kCmdLock = 6, +kCmdUnlock = 7, +kCmdToggleLock = 8, +kCmdStopOff = 9, +kCmdStopOn = 10, +kCmdStopNext = 11, +kCmdCounterSector = 12, +kCmdCallback = 20, +kCmdRepeat = 21, - kCmdSpritePush = 30, - kCmdSpriteImpact = 31, - kCmdSpritePickup = 32, - kCmdSpriteTouch = 33, - kCmdSpriteSight = 34, - kCmdSpriteProximity = 35, - kCmdSpriteExplode = 36, +kCmdSpritePush = 30, +kCmdSpriteImpact = 31, +kCmdSpritePickup = 32, +kCmdSpriteTouch = 33, +kCmdSpriteSight = 34, +kCmdSpriteProximity = 35, +kCmdSpriteExplode = 36, - kCmdSectorPush = 40, - kCmdSectorImpact = 41, - kCmdSectorEnter = 42, - kCmdSectorExit = 43, +kCmdSectorPush = 40, +kCmdSectorImpact = 41, +kCmdSectorEnter = 42, +kCmdSectorExit = 43, - kCmdWallPush = 50, - kCmdWallImpact = 51, - kCmdWallTouch = 52, +kCmdWallPush = 50, +kCmdWallImpact = 51, +kCmdWallTouch = 52, - kCmdModernUse = 53, // used by most of modern types - kCmdNumberic = 64, // 64: 0, 65: 1 and so on up to 255 - kCmdModernFeaturesEnable = 100, // must be in object with kChannelMapModernize RX / TX - kCmdModernFeaturesDisable = 200, // must be in object with kChannelMapModernize RX / TX - kCmdNumbericMax = 255, +kCmdModernUse = 53, // used by most of modern types +kCmdNumberic = 64, // 64: 0, 65: 1 and so on up to 255 +kCmdModernFeaturesEnable = 100, // must be in object with kChannelMapModernize RX / TX +kCmdModernFeaturesDisable = 200, // must be in object with kChannelMapModernize RX / TX +kCmdNumbericMax = 255, }; inline bool playerRXRngIsFine(int rx) { diff --git a/source/blood/src/levels.cpp b/source/blood/src/levels.cpp index c1ad24fae..55a1819d2 100644 --- a/source/blood/src/levels.cpp +++ b/source/blood/src/levels.cpp @@ -357,7 +357,7 @@ void levelEndLevel(int arg) } } -// By NoOne: this function can be called via sending numbered command to TX kGDXChannelEndLevel +// By NoOne: this function can be called via sending numbered command to TX kChannelModernEndLevelCustom // This allows to set custom next level instead of taking it from INI file. void levelEndLevelCustom(int nLevel) { diff --git a/source/blood/src/player.cpp b/source/blood/src/player.cpp index 570ecb558..8512ee832 100644 --- a/source/blood/src/player.cpp +++ b/source/blood/src/player.cpp @@ -483,23 +483,45 @@ QAV* qavSceneLoad(int qavId) { return pQav; } + + void qavSceneDraw(PLAYER* pPlayer, int a2, int a3, int a4, int a5) { if (pPlayer == NULL || pPlayer->sceneQav == -1) return; QAVSCENE* pQavScene = &gPlayerCtrl[pPlayer->nPlayer].qavScene; + spritetype* pSprite = &sprite[pQavScene->index]; + if (pQavScene->qavResrc != NULL) { QAV* pQAV = pQavScene->qavResrc; int v4 = (pPlayer->weaponTimer == 0) ? (int)totalclock % pQAV->at10 : pQAV->at10 - pPlayer->weaponTimer; - - pQAV->x = a3; pQAV->y = a4; int flags = 2; - int nInv = powerupCheck(pPlayer, kPwUpShadowCloak); + + int flags = 2; int nInv = powerupCheck(pPlayer, kPwUpShadowCloak); if (nInv >= 120 * 8 || (nInv != 0 && ((int)totalclock & 32))) { - a2 = -128; - flags |= 1; + a2 = -128; flags |= 1; + } + + // draw as weapon + if (!(pSprite->flags & kModernTypeFlag1)) { + + pQAV->x = a3; pQAV->y = a4; + pQAV->Draw(v4, flags, a2, a5); + + // draw fullscreen (currently 4:3 only) + } else { + + int wx1 = windowxy1.x, wy1 = windowxy1.y, wx2 = windowxy2.x, wy2 = windowxy2.y; + + windowxy2.x = xdim - 1; windowxy2.y = ydim - 1; + windowxy1.x = windowxy1.y = 0; + + pQAV->Draw(v4, flags, a2, a5); + + windowxy1.x = wx1; windowxy1.y = wy1; + windowxy2.x = wx2; windowxy2.y = wy2; + } - pQAV->Draw(v4, flags, a2, a5); } } diff --git a/source/blood/src/player.h b/source/blood/src/player.h index 7bf385759..c1cbe9413 100644 --- a/source/blood/src/player.h +++ b/source/blood/src/player.h @@ -64,7 +64,7 @@ struct PLAYER { DUDEINFO *pDudeInfo; GINPUT input; //short input; // INPUT - //char at10; // forward + //char moveFunc; // forward //short at11; // turn //char hearDist; // strafe //int bobV; // buttonFlags @@ -216,11 +216,15 @@ struct POWERUPINFO { int maxTime; }; + +#define kQavSceneStackSize 16 // by NoOne: this one stores qavs anims that can be played by trigger struct QAVSCENE { short index = -1; // index of sprite which triggered qav scene QAV* qavResrc = NULL; short causedBy = -1; + + // TO-DO: Stack of animations which allows to pop and push (restoring previous animation instead of weapon once current animation is played) }; // by NoOne: this one for controlling the player using triggers (movement speed, jumps and other stuff) diff --git a/source/blood/src/seq.h b/source/blood/src/seq.h index cbb799147..8b7661415 100644 --- a/source/blood/src/seq.h +++ b/source/blood/src/seq.h @@ -56,7 +56,7 @@ struct Seq { short at8; short ata; int atc; - SEQFRAME frames[1]; // at10 + SEQFRAME frames[1]; void Preload(void); void Precache(void); }; diff --git a/source/blood/src/sfx.cpp b/source/blood/src/sfx.cpp index a904b79cf..538fc16eb 100644 --- a/source/blood/src/sfx.cpp +++ b/source/blood/src/sfx.cpp @@ -42,28 +42,6 @@ POINT2D earL, earR, earL0, earR0; // Ear position VECTOR2D earVL, earVR; // Ear velocity ? int lPhase, rPhase, lVol, rVol, lPitch, rPitch; -struct BONKLE -{ - int at0; - int at4; - DICTNODE *at8; - int atc; - spritetype *at10; - int at14; - int at18; - int at1c; - POINT3D at20; - POINT3D at2c; - //int at20; - //int at24; - //int at28; - //int at2c; - //int at30; - //int at34; - int at38; - int at3c; -}; - BONKLE Bonkle[256]; BONKLE *BonkleCache[256]; diff --git a/source/blood/src/sfx.h b/source/blood/src/sfx.h index 98665faf5..4bc8f1abd 100644 --- a/source/blood/src/sfx.h +++ b/source/blood/src/sfx.h @@ -25,6 +25,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. BEGIN_BLD_NS +struct BONKLE +{ + int at0; + int at4; + DICTNODE* at8; + int atc; + spritetype* at10; + int at14; + int at18; + int at1c; + POINT3D at20; + POINT3D at2c; + //int at20; + //int at24; + //int at28; + //int at2c; + //int at30; + //int at34; + int at38; + int at3c; +}; + +extern BONKLE Bonkle[256]; +extern BONKLE* BonkleCache[256]; + void sfxInit(void); void sfxTerm(void); void sfxPlay3DSound(int x, int y, int z, int soundId, int nSector); diff --git a/source/blood/src/triggers.cpp b/source/blood/src/triggers.cpp index b52a78347..f1c310bff 100644 --- a/source/blood/src/triggers.cpp +++ b/source/blood/src/triggers.cpp @@ -863,29 +863,30 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) } return; case kModernPlayerControl: // WIP - PLAYER* pPlayer = NULL; int nPlayer = pXSprite->data1; + PLAYER* pPlayer = NULL; int nPlayer = pXSprite->data1; int oldCmd = -1; if (pXSprite->data1 == 0 && spriRangeIsFine(event.causedBy)) nPlayer = sprite[event.causedBy].type; - - if ((pPlayer = getPlayerById(nPlayer)) == NULL || pPlayer->pXSprite->health <= 0) - return; + + if ((pPlayer = getPlayerById(nPlayer)) == NULL || pPlayer->pXSprite->health <= 0) return; + else if (pXSprite->command < kCmdNumberic + 3 && pXSprite->command > kCmdNumberic + 4 + && !modernTypeSetSpriteState(nSprite, pXSprite, pXSprite->state ^ 1, event.causedBy)) return; TRPLAYERCTRL* pCtrl = pCtrl = &gPlayerCtrl[pPlayer->nPlayer]; if (event.cmd >= kCmdNumberic) { switch (event.cmd) { case kCmdNumberic + 3:// start playing qav scene - viewSetSystemMessage("START QAV %d, %d", pXSprite->rxID, pXSprite->txID); if (pCtrl->qavScene.index != nSprite || pXSprite->Interrutable) trPlayerCtrlStartScene(pXSprite, pPlayer, event.causedBy); - break; + return; case kCmdNumberic + 4: // stop playing qav scene - viewSetSystemMessage("STOP QAV", gPlayerCtrl[pPlayer->nPlayer].qavScene.index); - if (pCtrl->qavScene.index == nSprite) + if (pCtrl->qavScene.index == nSprite || event.type != 3 || sprite[event.index].type != kModernPlayerControl) trPlayerCtrlStopScene(pXSprite, pPlayer); + return; + default: + oldCmd = pXSprite->command; + pXSprite->command = event.cmd; // convert event command to current sprite command break; } - - return; } /// !!! COMMANDS OF THE CURRENT SPRITE, NOT OF THE EVENT !!! /// @@ -923,7 +924,8 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) gPosture[i][a].frontAccel = gPosture[i][a].sideAccel = gPosture[i][a].backAccel = ClipRange(mulscale8(defSpeed, speed), 0, 65535); } } - viewSetSystemMessage("MOVEMENT: %d %d %d", pXSprite->rxID,pSprite->index, gPosture[0][0].frontAccel); + + //viewSetSystemMessage("MOVEMENT: %d %d %d", pXSprite->rxID,pSprite->index, gPosture[0][0].frontAccel); } // player jump height (for all players ATM) @@ -941,7 +943,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) } } } - viewSetSystemMessage("JUMPING: %d", gPosture[0][0].normalJumpZ); + //viewSetSystemMessage("JUMPING: %d", gPosture[0][0].normalJumpZ); } break; @@ -950,7 +952,7 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) if (pXSprite->data3 < 0) break; switch (pXSprite->data2) { case 1: // tilting - pPlayer->tiltEffect = pXSprite->data3; + pPlayer->tiltEffect = ClipRange(pXSprite->data3, 0, 220); break; case 2: // pain pPlayer->painEffect = pXSprite->data3; @@ -987,27 +989,25 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) case kCmdNumberic + 5: // 69 // set player sprite and look angles - if (pXSprite->data2 == 0) { + if (pXSprite->data4 == 0) { // look angle - if (valueIsBetween(pXSprite->data3, -128, 128)) { + if (valueIsBetween(pXSprite->data2, -128, 128)) { CONSTEXPR int upAngle = 289; CONSTEXPR int downAngle = -347; CONSTEXPR double lookStepUp = 4.0 * upAngle / 60.0; CONSTEXPR double lookStepDown = -4.0 * downAngle / 60.0; - int look = pXSprite->data3 << 5; + int look = pXSprite->data2 << 5; if (look > 0) pPlayer->q16look = fix16_min(mulscale8(F16(lookStepUp), look), F16(upAngle)); else if (look < 0) pPlayer->q16look = -fix16_max(mulscale8(F16(lookStepDown), abs(look)), F16(downAngle)); else pPlayer->q16look = 0; } // angle - if ((pSprite->flags & kModernTypeFlag1) && valueIsBetween(pXSprite->data4, 0, kAng180)) - pPlayer->pSprite->ang = pXSprite->data4; - else if (pXSprite->data4 == 1) - pPlayer->pSprite->ang = pSprite->ang; - - + // TO-DO: if tx > 0, take a look on TX ID sprite + if (pXSprite->data3 == 1) pPlayer->pSprite->ang = pXSprite->data3; + else if (valueIsBetween(pXSprite->data3, 0, kAng180)) + pPlayer->pSprite->ang = pXSprite->data3; } //viewSetSystemMessage("ANGLE: %d, SLOPE: %d", pPlayer->pSprite->ang, pPlayer->q16look); break; @@ -1017,22 +1017,28 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) switch (pXSprite->data2) { // erase all case 0: - // erase all weapons except pitchfork + // erase weapons case 1: - WeaponLower(pPlayer); - - for (int i = 0; i < 14; i++) { - pPlayer->hasWeapon[i] = false; - // also erase ammo - if (i < 12 && pXSprite->data3 == 1) - pPlayer->ammoCount[i] = 0; - } + // erase all + if (pXSprite->data3 <= 0) { + WeaponLower(pPlayer); - pPlayer->hasWeapon[1] = true; - pPlayer->curWeapon = 0; - pPlayer->nextWeapon = 1; - - WeaponRaise(pPlayer); + for (int i = 0; i < 14; i++) { + pPlayer->hasWeapon[i] = false; + // also erase ammo + if (i < 12) pPlayer->ammoCount[i] = 0; + } + + pPlayer->hasWeapon[1] = true; + pPlayer->curWeapon = 0; + pPlayer->nextWeapon = 1; + + WeaponRaise(pPlayer); + + // erase just specified + } else { + + } if (pXSprite->data2) break; // erase all armor case 2: @@ -1065,11 +1071,11 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) if (pXSprite->data2 == 1) { pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pWeaponData->count, gAmmoInfo[nAmmoType].max); } else { - pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pXSprite->data3, gAmmoInfo[nAmmoType].max); + pPlayer->ammoCount[nAmmoType] = ClipHigh(pPlayer->ammoCount[nAmmoType] + pXSprite->data4, gAmmoInfo[nAmmoType].max); break; } - pPlayer->hasWeapon[pXSprite->data2] = true; + pPlayer->hasWeapon[pXSprite->data3] = true; if (pXSprite->data4 == 0) { // switch on it if (pPlayer->sceneQav >= 0) { @@ -1085,7 +1091,19 @@ void OperateSprite(int nSprite, XSPRITE *pXSprite, EVENT event) break; } break; + case kCmdNumberic + 8: // 72 + // use inventory item + if (pXSprite->data2 > 0 && pXSprite->data2 <= 5) { + packUseItem(pPlayer, pXSprite->data2 - 1); + + // force remove after use + if (pXSprite->data4 == 1) + pPlayer->packSlots[0].curAmount = pPlayer->packSlots[0].curAmount = 0; + + } + break; } + if (oldCmd > -1) pXSprite->command = oldCmd; return; } } @@ -1548,11 +1566,7 @@ void useObjResizer(XSPRITE* pXSource, short objType, int objIndex) { break; // for sprites case 3: - - /*PLAYER* pPlayer = NULL; - if (playerRXRngIsFine(pXSource->txID) && (pPlayer = getPlayerById((kChannelPlayer0 - kChannelPlayer7) + kMaxPlayers)) != NULL) - objIndex = pPlayer->nSprite;*/ - + // resize by seq scaling if (sprite[pXSource->reference].flags & kModernTypeFlag1) { if (valueIsBetween(pXSource->data1, -255, 32767)) { @@ -1563,27 +1577,28 @@ void useObjResizer(XSPRITE* pXSource, short objType, int objIndex) { // request properties update for custom dude switch (sprite[objIndex].type) { - case kDudeModernCustom: - case kDudeModernCustomBurning: - gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyDamage] = true; - break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + gGenDudeExtra[objIndex].updReq[kGenDudePropertySpriteSize] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyDmgScale] = true; + evPost(objIndex, 3, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate, -1); + break; } } // resize by repeats } else { - + if (valueIsBetween(pXSource->data1, -1, 32767)) sprite[objIndex].xrepeat = ClipRange(pXSource->data1, 0, 255); - + if (valueIsBetween(pXSource->data2, -1, 32767)) sprite[objIndex].yrepeat = ClipRange(pXSource->data2, 0, 255); } - if (valueIsBetween(pXSource->data3, -1, 32767)) sprite[objIndex].xoffset = ClipRange(pXSource->data3, 0, 255); @@ -1876,7 +1891,12 @@ void useTeleportTarget(XSPRITE* pXSource, spritetype* pSprite) { if (pXSector != NULL && pXSector->Underwater) xsprite[pSprite->extra].medium = kMediumWater; else xsprite[pSprite->extra].medium = kMediumNormal; - if (pXSource->data2 == 1) pSprite->ang = pSource->ang; + if (pXSource->data2 == 1) { + pSprite->ang = pSource->ang; + if (IsDudeSprite(pSprite) && xspriRangeIsFine(pSprite->index)) + xsprite[pSprite->extra].goalAng = pSprite->ang; + } + if (pXSource->data3 == 1) xvel[pSprite->xvel] = yvel[pSprite->xvel] = zvel[pSprite->xvel] = 0; @@ -2006,11 +2026,21 @@ void useSectorWindGen(XSPRITE* pXSource, sectortype* pSector) { } } + + void useSpriteDamager(XSPRITE* pXSource, spritetype* pSprite) { - if (pSprite != NULL) { - int dmgType = (pXSource->data2 == 7) ? Random(6) : ClipRange(pXSource->data2, 0, 6); + + spritetype* pSource = &sprite[pXSource->reference]; + if (pSprite != NULL && xspriIsFine(pSprite->index)) { int dmg = (pXSource->data3 == 0) ? 65535 : ClipRange(pXSource->data3, 1, 65535); - actDamageSprite(pSprite->index, pSprite, (DAMAGE_TYPE)dmgType, dmg); + int dmgType = ClipRange(pXSource->data2, 0, 6); + + if (pXSource->data2 == -1 && IsDudeSprite(pSprite)) { + xsprite[pSprite->extra].health = ClipLow(xsprite[pSprite->extra].health - dmg, 0); + if (xsprite[pSprite->extra].health == 0) + actKillDude(pSource->index, pSprite, (DAMAGE_TYPE)0, 65535); + } + else actDamageSprite(pSource->index, pSprite, (DAMAGE_TYPE)dmgType, dmg); } } @@ -4206,42 +4236,59 @@ int getDataFieldOfObject(int objType, int objIndex, int dataIndex) { bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, int causedBy) { switch (objType) { - case 3: + case 3: { + + XSPRITE* pXSprite = &xsprite[sprite[objIndex].extra]; + + // exceptions + if (IsDudeSprite(&sprite[objIndex]) && pXSprite->health <= 0) return true; + /*switch (sprite[objIndex].type) { + case kThingBloodBits: + case kThingBloodChunks: + case kThingZombieHead: + case kThingObjectGib: + case kThingObjectExplode: + if (pXSprite->data1 > 0 || pXSprite->data2 > 0 || pXSprite->data3 > 0 || pXSprite->data4 > 0) return true; + break; + }*/ + switch (dataIndex) { case 1: xsprite[sprite[objIndex].extra].data1 = value; switch (sprite[objIndex].type) { - case kSwitchCombo: - if (value == xsprite[sprite[objIndex].extra].data2) SetSpriteState(objIndex, &xsprite[sprite[objIndex].extra], 1, causedBy); - else SetSpriteState(objIndex, &xsprite[sprite[objIndex].extra], 0, causedBy); - break; - case kDudeModernCustom: - case kDudeModernCustomBurning: - gGenDudeExtra[objIndex].updReq[kGenDudePropertyWeapon] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyMelee] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyDamage] = true; - break; + case kSwitchCombo: + if (value == xsprite[sprite[objIndex].extra].data2) SetSpriteState(objIndex, &xsprite[sprite[objIndex].extra], 1, causedBy); + else SetSpriteState(objIndex, &xsprite[sprite[objIndex].extra], 0, causedBy); + break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + gGenDudeExtra[objIndex].updReq[kGenDudePropertyWeapon] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyDmgScale] = true; + evPost(objIndex, 3, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate, causedBy); + break; } return true; case 2: xsprite[sprite[objIndex].extra].data2 = value; switch (sprite[objIndex].type) { - case kDudeModernCustom: - case kDudeModernCustomBurning: - gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyDamage] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyStates] = true; - gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true; - break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + gGenDudeExtra[objIndex].updReq[kGenDudePropertySpriteSize] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyMass] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyDmgScale] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyStates] = true; + gGenDudeExtra[objIndex].updReq[kGenDudePropertyAttack] = true; + evPost(objIndex, 3, kGenDudeUpdTimeRate, kCallbackGenDudeUpdate, causedBy); + break; } return true; case 3: xsprite[sprite[objIndex].extra].data3 = value; switch (sprite[objIndex].type) { - case kDudeModernCustom: - case kDudeModernCustomBurning: - xsprite[sprite[objIndex].extra].sysData1 = value; - break; + case kDudeModernCustom: + case kDudeModernCustomBurning: + xsprite[sprite[objIndex].extra].sysData1 = value; + break; } return true; case 4: @@ -4250,6 +4297,7 @@ bool setDataValueOfObject(int objType, int objIndex, int dataIndex, int value, i default: return false; } + } case 0: xsector[sector[objIndex].extra].data = value; return true; From 41194f99f9a38c5e9343fd7feedde1f11267180a Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:02 +0000 Subject: [PATCH 04/22] SW: Fix playing track 0 when entering the sound settings git-svn-id: https://svn.eduke32.com/eduke32@8294 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/menus.cpp --- source/sw/src/menus.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/source/sw/src/menus.cpp b/source/sw/src/menus.cpp index aee245b8a..51bd08a72 100644 --- a/source/sw/src/menus.cpp +++ b/source/sw/src/menus.cpp @@ -2893,11 +2893,8 @@ MNU_JoystickCheck(MenuItem *item) static SWBOOL MNU_TryMusicInit(void) { - if (PlaySong(0, RedBookSong[Level], TRUE, FALSE)) - { if (currentmenu->cursor == 0) MNU_MusicCheck(¤tmenu->items[currentmenu->cursor+1]); - } return TRUE; } From 92a699b7eb303f310f688a6adae5341613008f5f Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:06 +0000 Subject: [PATCH 05/22] SW: Fix enough OOBs to get in-game git-svn-id: https://svn.eduke32.com/eduke32@8295 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/_functio.h # source/sw/src/config.cpp # source/sw/src/sector.cpp --- source/sw/src/sector.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source/sw/src/sector.cpp b/source/sw/src/sector.cpp index 0f0e5a5a8..c8535df7f 100644 --- a/source/sw/src/sector.cpp +++ b/source/sw/src/sector.cpp @@ -197,8 +197,9 @@ WallSetup(void) wall_num = wall[wall_num].point2) { SET(wall[wall_num].extra, WALLFX_LOOP_DONT_SPIN); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_LOOP_DONT_SPIN); + auto const nextwall = wall[wall_num].nextwall; + if ((unsigned)nextwall < MAXSECTORS) + SET(wall[nextwall].extra, WALLFX_LOOP_DONT_SPIN); } break; From 46d485590195aaccd8c6c3b305a1a3f8f3cb4b4f Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:10 +0000 Subject: [PATCH 06/22] Fix the ifcrc token: 0 is a valid CRC32 result! git-svn-id: https://svn.eduke32.com/eduke32@8296 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/build/src/defs.cpp --- source/build/src/defs.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/source/build/src/defs.cpp b/source/build/src/defs.cpp index 85f759bc2..0d0577e4f 100644 --- a/source/build/src/defs.cpp +++ b/source/build/src/defs.cpp @@ -650,7 +650,8 @@ static int32_t defsparser(scriptfile *script) int32_t havexoffset = 0, haveyoffset = 0, haveextra = 0; int32_t xoffset = 0, yoffset = 0; int32_t istexture = 0; - int32_t tilecrc = 0, origcrc = 0; + int32_t tilecrc = 0; + uint8_t have_ifcrc = 0; int32_t extra = 0; static const tokenlist tilefromtexturetokens[] = @@ -695,6 +696,7 @@ static int32_t defsparser(scriptfile *script) break; case T_IFCRC: scriptfile_getsymbol(script, &tilecrc); + have_ifcrc = 1; break; case T_TEXHITSCAN: flags |= PICANM_TEXHITSCAN_BIT; @@ -721,9 +723,9 @@ static int32_t defsparser(scriptfile *script) break; } - if (tilecrc) + if (have_ifcrc) { - origcrc = tileCRC(tile); + int32_t origcrc = tileCRC(tile); if (origcrc != tilecrc) { //initprintf("CRC of tile %d doesn't match! CRC: %d, Expected: %d\n", tile, origcrc, tilecrc); From 2fc49b3489abc7ad6364b430d88d687ca3933c41 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:19 +0000 Subject: [PATCH 07/22] SW: Fix mouse aiming git-svn-id: https://svn.eduke32.com/eduke32@8298 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/config.cpp # source/sw/src/game.cpp --- source/sw/src/game.cpp | 89 ++++++++++++++++++---------------------- source/sw/src/game.h | 1 - source/sw/src/player.cpp | 3 +- source/sw/src/save.cpp | 2 + source/sw/src/weapon.cpp | 4 +- 5 files changed, 44 insertions(+), 55 deletions(-) diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index 7ae7c0378..862601fcd 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -3911,7 +3911,6 @@ void GetHelpInput(PLAYERp pp) } short MirrorDelay; -int MouseYAxisMode = -1; void getinput(SW_PACKET *loc) { @@ -3930,16 +3929,11 @@ void getinput(SW_PACKET *loc) #define MAXVEL ((NORMALKEYMOVE*2)+10) #define MAXSVEL ((NORMALKEYMOVE*2)+10) #define MAXANGVEL 100 +#define MAXAIMVEL 128 #define SET_LOC_KEY(loc, sync_num, key_test) SET(loc, ((!!(key_test)) << (sync_num))) - ControlInfo info; - int32_t running; - int32_t turnamount; static int32_t turnheldtime; - int32_t keymove; int32_t momx, momy; - int aimvel; - int mouseaxis; extern SWBOOL MenuButtonAutoRun; extern SWBOOL MenuButtonAutoAim; @@ -3951,7 +3945,6 @@ void getinput(SW_PACKET *loc) // reset all syncbits loc->bits = 0; - svel = vel = angvel = aimvel = 0; // MAKE SURE THIS WILL GET SET SET_LOC_KEY(loc->bits, SK_QUIT_GAME, MultiPlayQuitFlag); @@ -3978,7 +3971,9 @@ void getinput(SW_PACKET *loc) } } + int const aimMode = TEST(pp->Flags, PF_MOUSE_AIMING_ON); + ControlInfo info; CONTROL_GetInput(&info); if (in_mousedeadzone) @@ -4065,36 +4060,10 @@ void getinput(SW_PACKET *loc) SET_LOC_KEY(loc->bits, SK_SPACE_BAR, ((!!inputState.GetKeyStatus(KEYSC_SPACE)) | buttonMap.ButtonDown(gamefunc_Open))); - running = false;// G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); - - int const keyMove = running ? (NORMALKEYMOVE << 1) : NORMALKEYMOVE; - constexpr int const analogExtent = 32767; // KEEPINSYNC sdlayer.cpp - constexpr int const analogTurnAmount = (NORMALTURN << 1); - - if (buttonMap.ButtonDown(gamefunc_Strafe) && !pp->sop) - { - static int strafeyaw; - - svel = -(info.mousex + strafeyaw) >> 3; - strafeyaw = (info.mousex + strafeyaw) % 8; - - svel -= info.dyaw * keyMove / analogExtent; - } - else - { - angvel = fix16_div(fix16_from_int(info.mousex), F16(32)); - angvel += fix16_from_int(info.dyaw) / analogExtent * (analogTurnAmount << 1); - - angvel >>= 15; - } - - aimvel = fix16_div(fix16_from_int(info.mousey), F16(64)); - - if (!in_mouseflip) // SW's mouse is inverted by default. - aimvel = -aimvel; - - aimvel -= fix16_from_int(info.dpitch) / analogExtent * analogTurnAmount; - aimvel >>= 15; + int const running = BUTTON(gamefunc_Run) || TEST(pp->Flags, PF_LOCK_RUN); // G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); + int32_t turnamount; + int32_t keymove; + constexpr int const analogExtent = 32767; // KEEPINSYNC sdlayer.cpp svel -= info.dx * keyMove / analogExtent; vel -= info.dz * keyMove / analogExtent; @@ -4118,6 +4087,34 @@ void getinput(SW_PACKET *loc) keymove = NORMALKEYMOVE; } + info.dz = (info.dz * move_scale)>>8; + info.dyaw = (info.dyaw * turn_scale)>>8; + + int32_t svel = 0, vel = 0, angvel = 0, aimvel = 0; + + if (buttonMap.ButtonDown(gamefunc_Strafe) && !pp->sop) + { + svel = -info.mousex; + svel -= info.dyaw * keymove / analogExtent; + } + else + { + angvel = info.mousex / 32; + angvel += info.dyaw * (turnamount << 1) / analogExtent; + } + + if (aimMode) + aimvel = -info.mousey / 64; + else + vel = -(info.mousey >> 6); + + if (!in_mouseflip) + aimvel = -aimvel; + + aimvel -= info.dpitch * turnamount / analogExtent; + svel -= info.dx * keymove / analogExtent; + vel -= info.dz * keymove / analogExtent; + if (buttonMap.ButtonDown(gamefunc_Strafe) && !pp->sop) { if (buttonMap.ButtonDown(gamefunc_Turn_Left)) @@ -4170,19 +4167,11 @@ void getinput(SW_PACKET *loc) if (buttonMap.ButtonDown(gamefunc_Move_Backward)) vel += -keymove; + vel = clamp(vel, -MAXVEL, MAXVEL); + svel = clamp(svel, -MAXSVEL, MAXSVEL); - if (vel < -MAXVEL) - vel = -MAXVEL; - if (vel > MAXVEL) - vel = MAXVEL; - if (svel < -MAXSVEL) - svel = -MAXSVEL; - if (svel > MAXSVEL) - svel = MAXSVEL; - if (angvel < -MAXANGVEL) - angvel = -MAXANGVEL; - if (angvel > MAXANGVEL) - angvel = MAXANGVEL; + angvel = clamp(angvel, -MAXANGVEL, MAXANGVEL); + aimvel = clamp(aimvel, -MAXAIMVEL, MAXAIMVEL); momx = mulscale9(vel, sintable[NORM_ANGLE(newpp->pang + 512)]); momy = mulscale9(vel, sintable[NORM_ANGLE(newpp->pang)]); diff --git a/source/sw/src/game.h b/source/sw/src/game.h index 91bc55d55..111ac1878 100644 --- a/source/sw/src/game.h +++ b/source/sw/src/game.h @@ -2251,7 +2251,6 @@ extern char keys[]; extern short screenpeek; extern int dimensionmode, zoom; -extern int vel,svel,angvel; #define STAT_DAMAGE_LIST_SIZE 20 extern int16_t StatDamageList[STAT_DAMAGE_LIST_SIZE]; diff --git a/source/sw/src/player.cpp b/source/sw/src/player.cpp index cebf9ffd6..1e037f54b 100644 --- a/source/sw/src/player.cpp +++ b/source/sw/src/player.cpp @@ -134,7 +134,6 @@ extern SWBOOL FinishedLevel; char PlayerGravity = PLAYER_JUMP_GRAV; #endif -int vel, svel, angvel; extern SWBOOL DebugOperate; //unsigned char synctics, lastsynctics; @@ -3116,7 +3115,7 @@ DriveCrush(PLAYERp pp, int *x, int *y) if (sp->z < sop->crush_z) continue; - vel = FindDistance2D(pp->xvect>>8, pp->yvect>>8); + int32_t const vel = FindDistance2D(pp->xvect>>8, pp->yvect>>8); if (vel < 9000) { DoActorBeginSlide(i, getangle(pp->xvect, pp->yvect), vel/8, 5); diff --git a/source/sw/src/save.cpp b/source/sw/src/save.cpp index ceaf7d78b..7aafcf519 100644 --- a/source/sw/src/save.cpp +++ b/source/sw/src/save.cpp @@ -493,6 +493,7 @@ int SaveGame(short save_num) MWRITE(Track[i].TrackPoint, Track[i].NumPoints * sizeof(TRACK_POINT),1,fil); } + int32_t svel = 0, vel = 0, angvel = 0; MWRITE(&vel,sizeof(vel),1,fil); MWRITE(&svel,sizeof(svel),1,fil); MWRITE(&angvel,sizeof(angvel),1,fil); @@ -1013,6 +1014,7 @@ int LoadGame(short save_num) } } + int32_t svel, vel, angvel; MREAD(&vel,sizeof(vel),1,fil); MREAD(&svel,sizeof(svel),1,fil); MREAD(&angvel,sizeof(angvel),1,fil); diff --git a/source/sw/src/weapon.cpp b/source/sw/src/weapon.cpp index 379a2ca53..94dee2d19 100644 --- a/source/sw/src/weapon.cpp +++ b/source/sw/src/weapon.cpp @@ -9251,7 +9251,7 @@ DoVulcanBoulder(int16_t Weapon) u->ret = move_missile(Weapon, u->xchange, u->ychange, u->zchange, u->ceiling_dist, u->floor_dist, CLIPMASK_MISSILE, MISSILEMOVETICS); - vel = ksqrt(SQ(u->xchange) + SQ(u->ychange)); + int32_t const vel = ksqrt(SQ(u->xchange) + SQ(u->ychange)); if (vel < 30) { @@ -11268,7 +11268,7 @@ SpawnNuclearSecondaryExp(int16_t Weapon, short ang) RESET(exp->cstat, CSTAT_SPRITE_BLOCK | CSTAT_SPRITE_BLOCK_HITSCAN); //ang = RANDOM_P2(2048); - vel = (2048+128) + RANDOM_RANGE(2048); + int32_t const vel = (2048+128) + RANDOM_RANGE(2048); eu->xchange = MOVEx(vel, ang); eu->ychange = MOVEy(vel, ang); eu->Radius = 200; // was NUKE_RADIUS From fd3ec5682714cde7d38f30fff80f0db294697678 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:23 +0000 Subject: [PATCH 08/22] SW: Fix OOB access when viewing a mirror git-svn-id: https://svn.eduke32.com/eduke32@8299 1a8010ca-5511-0410-912e-c29ae57300e0 --- source/sw/src/jsector.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/sw/src/jsector.cpp b/source/sw/src/jsector.cpp index 8509d3ee0..97f4464f1 100644 --- a/source/sw/src/jsector.cpp +++ b/source/sw/src/jsector.cpp @@ -578,7 +578,7 @@ JS_DrawMirrors(PLAYERp pp, int tx, int ty, int tz, short tpang, int tphoriz) { for (cnt = MAXMIRRORS - 1; cnt >= 0; cnt--) //if (TEST_GOTPIC(cnt + MIRRORLABEL) || TEST_GOTPIC(cnt + CAMSPRITE)) - if (TEST_GOTPIC(cnt + MIRRORLABEL) || TEST_GOTPIC(mirror[cnt].campic)) + if (TEST_GOTPIC(cnt + MIRRORLABEL) || ((unsigned)mirror[cnt].campic < MAXTILES && TEST_GOTPIC(mirror[cnt].campic))) { bIsWallMirror = FALSE; if (TEST_GOTPIC(cnt + MIRRORLABEL)) @@ -587,7 +587,7 @@ JS_DrawMirrors(PLAYERp pp, int tx, int ty, int tz, short tpang, int tphoriz) RESET_GOTPIC(cnt + MIRRORLABEL); } //else if (TEST_GOTPIC(cnt + CAMSPRITE)) - else if (TEST_GOTPIC(mirror[cnt].campic)) + else if ((unsigned)mirror[cnt].campic < MAXTILES && TEST_GOTPIC(mirror[cnt].campic)) { //RESET_GOTPIC(cnt + CAMSPRITE); RESET_GOTPIC(mirror[cnt].campic); From 31f8cb4def39aa3eb200a2c88c8f469c58c468d9 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:26 +0000 Subject: [PATCH 09/22] SW: Fix an assertion failure in palette changing code git-svn-id: https://svn.eduke32.com/eduke32@8300 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/build/src/palette.cpp --- source/build/src/palette.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/build/src/palette.cpp b/source/build/src/palette.cpp index 16fedf317..bc0c09090 100644 --- a/source/build/src/palette.cpp +++ b/source/build/src/palette.cpp @@ -747,7 +747,7 @@ void videoSetPalette(char dabrightness, uint8_t dapalid, uint8_t flags) int32_t palsumdidchange; // uint32_t lastbright = curbrightness; - Bassert((flags & 4) == 0); + // Bassert((flags&4)==0); // What is so bad about this flag? if (/*(unsigned)dapalid >= MAXBASEPALS ||*/ basepaltable[dapalid] == NULL) dapalid = 0; From 383ecda2b20a62f83f0ccac6d7e1b77ad464e6a3 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:33 +0000 Subject: [PATCH 10/22] SW: Avoid an OOB in GetUpperLowerSector git-svn-id: https://svn.eduke32.com/eduke32@8302 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/brooms.cpp --- source/sw/src/rooms.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/sw/src/rooms.cpp b/source/sw/src/rooms.cpp index 420d3a565..90e07d57e 100644 --- a/source/sw/src/rooms.cpp +++ b/source/sw/src/rooms.cpp @@ -830,9 +830,10 @@ GetUpperLowerSector(short match, int x, int y, short *upper, short *lower) if (!found) continue; - sectorlist[sln] = i; if (sln < (int)SIZ(GlobStackSect)) GlobStackSect[sln] = i; + if (sln < (int)SIZ(sectorlist)) + sectorlist[sln] = i; sln++; } } From a51e91d4e9217f1625b562b83a4a4df169446872 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:38 +0000 Subject: [PATCH 11/22] SW: Fix keyboard input git-svn-id: https://svn.eduke32.com/eduke32@8303 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/duke3d/src/config.cpp # source/duke3d/src/menus.cpp # source/mact/include/control.h # source/mact/src/control.cpp # source/sw/src/config.cpp # source/sw/src/menus.cpp --- source/duke3d/src/menus.cpp | 5 +++-- source/sw/src/menus.cpp | 10 ++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/source/duke3d/src/menus.cpp b/source/duke3d/src/menus.cpp index 785b1b465..4701f1ba1 100644 --- a/source/duke3d/src/menus.cpp +++ b/source/duke3d/src/menus.cpp @@ -698,7 +698,7 @@ static MenuEntry_t *MEL_DISPLAYSETUP_GL[] = { -static char const *MenuKeyNone = " -"; +static char const MenuKeyNone[] = " -"; static char const *MEOSN_Keys[NUMKEYS]; static MenuCustom2Col_t MEO_KEYBOARDSETUPFUNCS_TEMPLATE = { 0, &MF_Minifont, NUMKEYS, 54<<16, 0 }; @@ -1565,8 +1565,9 @@ void Menu_Init(void) } MEOS_Gamefuncs.numOptions = k; - for (i = 0; i < NUMKEYS; ++i) + for (i = 1; i < NUMKEYS-1; ++i) MEOSN_Keys[i] = KB_ScanCodeToString(i); + MEOSN_Keys[0] = MenuKeyNone; MEOSN_Keys[NUMKEYS-1] = MenuKeyNone; diff --git a/source/sw/src/menus.cpp b/source/sw/src/menus.cpp index 51bd08a72..060f315a8 100644 --- a/source/sw/src/menus.cpp +++ b/source/sw/src/menus.cpp @@ -683,12 +683,6 @@ SWBOOL MNU_KeySetupCustom(UserCall call, MenuItem *item) { inputState.ClearKeyStatus(inputState.GetLastScanCode()); - //KeyboardKeys[currentkey][currentcol] = KB_GetLastScanCode(); -#if 0 // [JM] Re-do this shit !CHECKME! - CONTROL_MapKey(currentkey, - KeyboardKeys[currentkey][0], - KeyboardKeys[currentkey][1]); -#endif currentmode = 0; } @@ -811,12 +805,12 @@ SWBOOL MNU_KeySetupCustom(UserCall call, MenuItem *item) MNU_DrawSmallString(OPT_XS, j, ds, (i==currentkey) ? 0 : 12, 16); p = keyGetName(KeyboardKeys[i][0]); - if (!p || KeyboardKeys[i][0]==0xff) p = " -"; + if (!p || !KeyboardKeys[i][0] || KeyboardKeys[i][0]==0xff) p = " -"; MNU_DrawSmallString(OPT_XSIDE, j, p, (i==currentkey) ? -5 : 12, (i==currentkey && currentcol==0) ? 14 : 16); p = keyGetName(KeyboardKeys[i][1]); - if (!p || KeyboardKeys[i][1]==0xff) p = " -"; + if (!p || !KeyboardKeys[i][1] || KeyboardKeys[i][1]==0xff) p = " -"; MNU_DrawSmallString(OPT_XSIDE + 4*14, j, p, (i==currentkey) ? -5 : 12, (i==currentkey && currentcol==1) ? 14 : 16); #endif From 9dde07ced9ce86da64fffd9c4cafeaff3ba0b834 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:49 +0000 Subject: [PATCH 12/22] SW: Copy the sln==1 GetUpperLowerSector case from the editor to the game This avoids upper and lower remaining unmodified. Sector 469 in Seppuku Station causes it! git-svn-id: https://svn.eduke32.com/eduke32@8306 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/brooms.cpp --- source/sw/src/rooms.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/source/sw/src/rooms.cpp b/source/sw/src/rooms.cpp index 90e07d57e..99e812ba6 100644 --- a/source/sw/src/rooms.cpp +++ b/source/sw/src/rooms.cpp @@ -846,10 +846,17 @@ GetUpperLowerSector(short match, int x, int y, short *upper, short *lower) *lower = -1; return; } - else + // Map rooms have NOT been dragged on top of each other + else if (sln == 1) + { + *lower = sectorlist[0]; + *upper = sectorlist[0]; + return; + } + // Map rooms HAVE been dragged on top of each other // inside will somtimes find that you are in two different sectors if the x,y // is exactly on a sector line. - if (sln > 2) + else if (sln > 2) { //DSPRINTF(ds, "TOO MANY SECTORS FOUND: x=%d, y=%d, match=%d, num sectors %d, %d, %d, %d, %d, %d", x, y, match, sln, sectorlist[0], sectorlist[1], sectorlist[2], sectorlist[3], sectorlist[4]); MONO_PRINT(ds); From 83cfcb65a83294ecde6486a2202f9ee0b08504e8 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:52 +0000 Subject: [PATCH 13/22] SW: Update the port credits Still far from perfect. git-svn-id: https://svn.eduke32.com/eduke32@8307 1a8010ca-5511-0410-912e-c29ae57300e0 --- source/sw/src/menus.cpp | 55 +++++++++++++++++++---------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/source/sw/src/menus.cpp b/source/sw/src/menus.cpp index 060f315a8..f5a82838d 100644 --- a/source/sw/src/menus.cpp +++ b/source/sw/src/menus.cpp @@ -1270,7 +1270,7 @@ MNU_OrderCustom(UserCall call, MenuItem *item) //5261, //5262 - 5114 // JBF: for my credits + 5120 // 5114 // JBF: for my credits }; static short SWOrderScreen[] = { @@ -1282,7 +1282,7 @@ MNU_OrderCustom(UserCall call, MenuItem *item) 5118, 4979, - 5114 // JBF: for my credits + 5120 // 5114 // JBF: for my credits }; short *OrderScreen, OrderScreenSiz; @@ -1410,7 +1410,8 @@ MNU_OrderCustom(UserCall call, MenuItem *item) on_screen = 0; // CTW MODIFICATION END - rotatesprite(0,0,RS_SCALE,0,OrderScreen[on_screen],0,0, + int const shade = on_screen == OrderScreenSiz-1 ? 8 : 0; + rotatesprite(0,0,RS_SCALE,0,OrderScreen[on_screen], shade, 0, (ROTATE_SPRITE_CORNER|ROTATE_SPRITE_SCREEN_CLIP|ROTATE_SPRITE_NON_MASK|ROTATE_SPRITE_IGNORE_START_MOST), 0, 0, xdim-1, ydim-1); @@ -1421,38 +1422,31 @@ MNU_OrderCustom(UserCall call, MenuItem *item) static const char *jtitle = "^Port Credits"; static const char *jtext[] = { - "*GAME AND ENGINE PORT", + "*Developers", + " Richard \"TerminX\" Gobeille", + " Evan \"Hendricks266\" Ramos", + " Alex \"pogokeen\" Dawson", + "*Retired developers", + " Pierre-Loup \"Plagman\" Griffais", + " Philipp \"Helixhorned\" Kutin", + "*Special thanks to", " Jonathon \"JonoF\" Fowler", - "-", - "*\"POLYMOST\" 3D RENDERER", - "*NETWORKING, OTHER CODE", + "*Uses BUILD Engine technology by", " Ken \"Awesoken\" Silverman", + "*Additional thanks to", + " Alexey \"Nuke.YKT\" Skrybykin", + " Jordon \"Striker\" Moss", + " Par \"Parkar\" Karlsson", // "Pär \"Parkar\" Karlsson", + " Ben \"ProAsm\" Smit", + " NY00123", "-", - " Visit http://www.jonof.id.au/jfsw for the", - " source code, latest news, and updates of this port." + " Visit eduke32.com for news and updates" }; +#if 0 static const char *scroller[] = { - "This program is free software; you can redistribute it", - "and/or modify it under the terms of the GNU General", - "Public License as published by the Free Software", - "Foundation; either version 2 of the License, or (at your", - "option) any later version.", - "", - "This program is distributed in the hope that it will be", - "useful but WITHOUT ANY WARRANTY; without even the implied", - "warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR", - "PURPOSE. See the GNU General Public License (GPL.TXT) for", - "more details.", - "", - "", - "", - "", "Thanks to these people for their input and contributions:", "", - "Richard \"TerminX\" Gobeille,", - "Par \"Parkar\" Karlsson", // "Pär \"Parkar\" Karlsson", - "Ben \"ProAsm\" Smit", "", "and all those who submitted bug reports and ", "supported the project financially!", @@ -1464,9 +1458,9 @@ MNU_OrderCustom(UserCall call, MenuItem *item) "", "" }; - const int numscrollerlines = SIZ(scroller); +#endif short dimx, dimy; - int ycur = 54; + int ycur = 20; unsigned ji; dimy = 0; MNU_MeasureString(jtitle, &dimx, &dimy); @@ -1496,6 +1490,8 @@ MNU_OrderCustom(UserCall call, MenuItem *item) } } +#if 0 + const int numscrollerlines = SIZ(scroller); int m,i; for (m=0, i=((int32_t) totalclock/104)%numscrollerlines; m<4; m++,i++) { @@ -1505,6 +1501,7 @@ MNU_OrderCustom(UserCall call, MenuItem *item) MNU_MeasureSmallString(scroller[i], &dimx, &dimy); MNU_DrawSmallString(160-(dimx>>1), 154+(m*7), scroller[i], 0, 8); } +#endif } //inputState.ClearKeysDown(); From 7fb425aebbd8cef1c7e30db7ce2d74c40319d79b Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:24:56 +0000 Subject: [PATCH 14/22] SW: Fix non-debug builds on Windows git-svn-id: https://svn.eduke32.com/eduke32@8308 1a8010ca-5511-0410-912e-c29ae57300e0 --- source/sw/src/game.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index 862601fcd..01e47553b 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -105,6 +105,10 @@ signed char MNU_InputString(char*, short); SWBOOL IsCommand(const char* str); SWBOOL MNU_StartNetGame(void); +#ifdef _WIN32 +# include "winbits.h" +#endif + const char* AppProperName = "VoidSW"; const char* AppTechnicalName = "voidsw"; From 1a0b363ded02d0017b199ab64d34ba4dad7f87d5 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:25:00 +0000 Subject: [PATCH 15/22] SW: Allow the Run key to Walk when AutoRun is enabled git-svn-id: https://svn.eduke32.com/eduke32@8309 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/game.cpp # source/sw/src/player.cpp --- source/sw/src/game.cpp | 2 +- source/sw/src/player.cpp | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index 01e47553b..a017305d8 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -4064,7 +4064,7 @@ void getinput(SW_PACKET *loc) SET_LOC_KEY(loc->bits, SK_SPACE_BAR, ((!!inputState.GetKeyStatus(KEYSC_SPACE)) | buttonMap.ButtonDown(gamefunc_Open))); - int const running = BUTTON(gamefunc_Run) || TEST(pp->Flags, PF_LOCK_RUN); // G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); + int const running = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); int32_t turnamount; int32_t keymove; constexpr int const analogExtent = 32767; // KEEPINSYNC sdlayer.cpp diff --git a/source/sw/src/player.cpp b/source/sw/src/player.cpp index 1e037f54b..80723dc15 100644 --- a/source/sw/src/player.cpp +++ b/source/sw/src/player.cpp @@ -2404,7 +2404,6 @@ MoveScrollMode2D(PLAYERp pp) #define MAXANGVEL 100 ControlInfo scrl_input; - int32_t running; int32_t keymove; int32_t momx, momy; static int mfvel=0, mfsvel=0; @@ -2435,19 +2434,19 @@ MoveScrollMode2D(PLAYERp pp) Follow_posy = pp->posy; } - running = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); - if (buttonMap.ButtonDown(gamefunc_Strafe)) mfsvel -= scrl_input.dyaw>>2; mfsvel -= scrl_input.dx>>2; mfvel = -scrl_input.dz>>2; +#if 0 + int const running = !!BUTTON(gamefunc_Run) ^ !!TEST(pp->Flags, PF_LOCK_RUN); if (running) { - //keymove = NORMALKEYMOVE << 1; - keymove = NORMALKEYMOVE; + keymove = NORMALKEYMOVE << 1; } else +#endif { keymove = NORMALKEYMOVE; } From f411b72783435e161eef3a11faa2524238012d6b Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:25:03 +0000 Subject: [PATCH 16/22] SW: Fix widescreen flickering in end of level screen git-svn-id: https://svn.eduke32.com/eduke32@8310 1a8010ca-5511-0410-912e-c29ae57300e0 --- source/sw/src/game.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index a017305d8..2c0ee37fe 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -2308,6 +2308,9 @@ void BonusScreen(PLAYERp pp) } gStateControl(&State, &Tics); + + videoClearViewableArea(0L); + rotatesprite(0, 0, RS_SCALE, 0, 5120, 0, 0, TITLE_ROT_FLAGS, 0, 0, xdim - 1, ydim - 1); if (UserMapName[0]) From 510e73736001069817529c60c049577a3a1cded6 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:25:08 +0000 Subject: [PATCH 17/22] SW: Fix "MV_GetVoice(): bad handle" log spam git-svn-id: https://svn.eduke32.com/eduke32@8311 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/draw.cpp # source/sw/src/menus.cpp --- source/audiolib/include/fx_man.h | 1 + source/sw/src/menus.cpp | 20 +++++++++--------- source/sw/src/miscactr.cpp | 32 ++++++++++++++-------------- source/sw/src/panel.cpp | 6 +++++- source/sw/src/player.cpp | 10 +++++---- source/sw/src/ripper2.cpp | 4 ++-- source/sw/src/sounds.cpp | 36 +++++++++++++++++++++----------- source/sw/src/zilla.cpp | 2 +- 8 files changed, 65 insertions(+), 46 deletions(-) diff --git a/source/audiolib/include/fx_man.h b/source/audiolib/include/fx_man.h index 513e3a5c3..ea0f6e428 100644 --- a/source/audiolib/include/fx_man.h +++ b/source/audiolib/include/fx_man.h @@ -109,6 +109,7 @@ static FORCE_INLINE int FX_Pan3D(int handle, int angle, int distance) return FX_CheckMVErr(MV_Pan3D(handle, angle, distance)); } static FORCE_INLINE int FX_SoundActive(int handle) { return MV_VoicePlaying(handle); } +static FORCE_INLINE int FX_SoundValidAndActive(int handle) { return handle > 0 && MV_VoicePlaying(handle); } static FORCE_INLINE int FX_SoundsPlaying(void) { return MV_VoicesPlaying(); } static FORCE_INLINE int FX_StopSound(int handle) { return FX_CheckMVErr(MV_Kill(handle)); } static FORCE_INLINE int FX_StopAllSounds(void) { return FX_CheckMVErr(MV_KillAllVoices()); } diff --git a/source/sw/src/menus.cpp b/source/sw/src/menus.cpp index f5a82838d..0144da70d 100644 --- a/source/sw/src/menus.cpp +++ b/source/sw/src/menus.cpp @@ -1311,9 +1311,9 @@ MNU_OrderCustom(UserCall call, MenuItem *item) { DidOrderSound = TRUE; choose_snd = STD_RANDOM_RANGE(1000); - if (choose_snd > 500 && !FX_SoundActive(wanghandle)) + if (choose_snd > 500 && !FX_SoundValidAndActive(wanghandle)) wanghandle = PlaySound(DIGI_WANGORDER1, &zero, &zero, &zero, v3df_dontpan); - else if (!FX_SoundActive(wanghandle)) + else if (!FX_SoundValidAndActive(wanghandle)) wanghandle = PlaySound(DIGI_WANGORDER2, &zero, &zero, &zero, v3df_dontpan); } @@ -3761,11 +3761,11 @@ static void MNU_DownLevel(MenuGroup * group) static void MNU_UpLevel(void) { int zero = 0; - static int handle1=0; + static int handle1; // if run out of menus then EXIT if (!menuarrayptr) { - if(!FX_SoundActive(handle1)) + if (!FX_SoundValidAndActive(handle1)) handle1 = PlaySound(DIGI_STARCLINK,&zero,&zero,&zero,v3df_dontpan); ExitMenus(); return; @@ -4106,7 +4106,7 @@ void MNU_DoMenu( CTLType type, PLAYERp pp ) SWBOOL resetitem; unsigned char key; int zero = 0; - static int handle2 = 0; + static int handle2; static int limitmove=0; static SWBOOL select_held=FALSE; @@ -4140,7 +4140,7 @@ void MNU_DoMenu( CTLType type, PLAYERp pp ) { static int handle5=0; I_GeneralTriggerClear(); - if (!FX_SoundActive(handle5)) + if (!FX_SoundValidAndActive(handle5)) handle5 = PlaySound(DIGI_SWORDSWOOSH,&zero,&zero,&zero,v3df_dontpan); inputState.ClearKeysDown(); MNU_DoItem(); @@ -4163,16 +4163,16 @@ void MNU_DoMenu( CTLType type, PLAYERp pp ) else if (I_ReturnTrigger()) { I_ReturnTriggerClear(); - static int handle3=0; - if (!FX_SoundActive(handle3)) + static int handle3; + if (!FX_SoundValidAndActive(handle3)) handle3 = PlaySound(DIGI_SWORDSWOOSH,&zero,&zero,&zero,v3df_dontpan); MNU_UpLevel(); resetitem = TRUE; } else if (MNU_DoHotkey()) { - static int handle4=0; - if (!FX_SoundActive(handle4)) + static int handle4; + if (!FX_SoundValidAndActive(handle4)) handle4 = PlaySound(DIGI_STAR,&zero,&zero,&zero,v3df_dontpan); resetitem = TRUE; } diff --git a/source/sw/src/miscactr.cpp b/source/sw/src/miscactr.cpp index 9c1001308..ab0d0369b 100644 --- a/source/sw/src/miscactr.cpp +++ b/source/sw/src/miscactr.cpp @@ -173,7 +173,7 @@ int DoToiletGirl(short SpriteNum) choose_snd = RANDOM_P2(1024<<4)>>4; - if (!FX_SoundActive(handle)) + if (!FX_SoundValidAndActive(handle)) { if (choose_snd > 750) handle = PlaySound(DIGI_TOILETGIRLFART1,&sp->x,&sp->y,&sp->z,v3df_dontpan); @@ -188,7 +188,7 @@ int DoToiletGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { if (RANDOM_RANGE(1000<<8)>>8 > 500) madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan); @@ -235,7 +235,7 @@ int NullToiletGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { if (RANDOM_RANGE(1000<<8)>>8 > 500) madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan); @@ -416,7 +416,7 @@ int DoWashGirl(short SpriteNum) { static int handle; - if (!FX_SoundActive(handle)) + if (!FX_SoundValidAndActive(handle)) { if (RANDOM_P2(1024<<4)>>4 > 500) handle = PlaySound(DIGI_ANIMESING1,&sp->x,&sp->y,&sp->z,v3df_dontpan); @@ -446,7 +446,7 @@ int DoWashGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { if (RANDOM_RANGE(1000<<8)>>8 > 500) madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan); @@ -490,7 +490,7 @@ int NullWashGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { if (RANDOM_RANGE(1000<<8)>>8 > 500) madhandle = PlaySound(DIGI_ANIMEMAD1,&sp->x,&sp->y,&sp->z,v3df_dontpan); @@ -1305,7 +1305,7 @@ int DoCarGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); @@ -1360,7 +1360,7 @@ int NullCarGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); @@ -1532,7 +1532,7 @@ int DoMechanicGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); @@ -1587,7 +1587,7 @@ int NullMechanicGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); @@ -1760,7 +1760,7 @@ int DoSailorGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); @@ -1820,7 +1820,7 @@ int NullSailorGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); @@ -1968,7 +1968,7 @@ int DoPruneGirl(short SpriteNum) USERp u = User[SpriteNum]; SPRITEp sp = User[SpriteNum]->SpriteP; short rnd_range = 0; - static int madhandle=0,coyhandle=0; + static int madhandle, coyhandle; SWBOOL ICanSee = FALSE; DoActorPickClosePlayer(SpriteNum); @@ -1978,7 +1978,7 @@ int DoPruneGirl(short SpriteNum) { if ((u->WaitTics -= ACTORMOVETICS) <= 0 && ICanSee) { - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = STD_RANDOM_RANGE(1000); @@ -1998,7 +1998,7 @@ int DoPruneGirl(short SpriteNum) } else { - if (!FX_SoundActive(coyhandle)) + if (!FX_SoundValidAndActive(coyhandle)) { short choose; choose = STD_RANDOM_RANGE(1000); @@ -2049,7 +2049,7 @@ int NullPruneGirl(short SpriteNum) { static int madhandle; - if (!FX_SoundActive(madhandle)) + if (!FX_SoundValidAndActive(madhandle)) { short choose; choose = RANDOM_RANGE(1000); diff --git a/source/sw/src/panel.cpp b/source/sw/src/panel.cpp index e1f98170a..823147ce3 100644 --- a/source/sw/src/panel.cpp +++ b/source/sw/src/panel.cpp @@ -997,7 +997,11 @@ int WeaponOperate(PLAYERp pp) if (pp->WpnRocketType != 2 || pp->CurWpn != pp->Wpn[WPN_MICRO]) { pp->InitingNuke = FALSE; - FX_StopSound(pp->nukevochandle); + if (pp->nukevochandle > 0) + { + FX_StopSound(pp->nukevochandle); + pp->nukevochandle = 0; + } } return 0; diff --git a/source/sw/src/player.cpp b/source/sw/src/player.cpp index 80723dc15..79a4f332a 100644 --- a/source/sw/src/player.cpp +++ b/source/sw/src/player.cpp @@ -3736,7 +3736,7 @@ DoPlayerFall(PLAYERp pp) PlaySound(DIGI_HITGROUND, &pp->posx, &pp->posy, &pp->posz, v3df_follow|v3df_dontpan); } - if (handle && FX_SoundActive(handle)) + if (FX_SoundValidAndActive(handle)) { // My sound code will detect the sound has stopped and clean up // for you. @@ -5166,9 +5166,10 @@ DoPlayerStopDiveNoWarp(PLAYERp pp) if (!NoMeters) SetRedrawScreen(pp); - if (pp->TalkVocHandle && FX_SoundActive(pp->TalkVocHandle)) + if (FX_SoundValidAndActive(pp->TalkVocHandle)) { FX_StopSound(pp->TalkVocHandle); + pp->TalkVocHandle = 0; pp->PlayerTalking = FALSE; } @@ -5201,9 +5202,10 @@ DoPlayerStopDive(PLAYERp pp) if (!NoMeters) SetRedrawScreen(pp); - if (pp->TalkVocHandle && FX_SoundActive(pp->TalkVocHandle)) + if (FX_SoundValidAndActive(pp->TalkVocHandle)) { FX_StopSound(pp->TalkVocHandle); + pp->TalkVocHandle = 0; pp->PlayerTalking = FALSE; } @@ -6503,7 +6505,7 @@ DoPlayerBeginDie(PLAYERp pp) // Override any previous talking, death scream has precedance if (pp->PlayerTalking) { - if (FX_SoundActive(pp->TalkVocHandle)) + if (FX_SoundValidAndActive(pp->TalkVocHandle)) FX_StopSound(pp->TalkVocHandle); pp->PlayerTalking = FALSE; pp->TalkVocnum = -1; diff --git a/source/sw/src/ripper2.cpp b/source/sw/src/ripper2.cpp index a6991323f..e8a961a16 100644 --- a/source/sw/src/ripper2.cpp +++ b/source/sw/src/ripper2.cpp @@ -1246,11 +1246,11 @@ int DoRipper2StandHeart(short SpriteNum) { SPRITEp sp = &sprite[SpriteNum]; USERp u = User[SpriteNum]; - static int riphearthandle=0; + static int riphearthandle; NullRipper2(SpriteNum); - if (!FX_SoundActive(riphearthandle)) + if (!FX_SoundValidAndActive(riphearthandle)) riphearthandle = PlaySound(DIGI_RIPPER2HEARTOUT,&sp->x,&sp->y,&sp->z,v3df_none); if ((u->WaitTics -= ACTORMOVETICS) <= 0) diff --git a/source/sw/src/sounds.cpp b/source/sw/src/sounds.cpp index 1142c2016..284d30b77 100644 --- a/source/sw/src/sounds.cpp +++ b/source/sw/src/sounds.cpp @@ -527,9 +527,10 @@ StopSong(void) if (DemoMode) return; - if (SongType == SongTypeWave && SongVoice >= 0) + if (SongType == SongTypeWave && SongVoice > 0) { FX_StopSound(SongVoice); + SongVoice = 0; } else if (SongType == SongTypeMIDI) { @@ -553,7 +554,7 @@ PauseSong(SWBOOL pauseon) { if (!MusicEnabled()) return; - if (SongType == SongTypeWave && SongVoice >= 0) + if (SongType == SongTypeWave && SongVoice > 0) { FX_PauseVoice(SongVoice, pauseon); } @@ -1313,9 +1314,10 @@ DeleteNoSoundOwner(short spritenum) // Make sure to stop active // sounds - if (FX_SoundActive(vp->handle)) + if (FX_SoundValidAndActive(vp->handle)) { FX_StopSound(vp->handle); + vp->handle = 0; } #if 0 @@ -1372,9 +1374,10 @@ void DeleteNoFollowSoundOwner(short spritenum) // If the follow flag is set, compare the x and y addresses. if ((vp->flags & v3df_follow) && vp->x == &sp->x && vp->y == &sp->y) { - if (FX_SoundActive(vp->handle)) + if (FX_SoundValidAndActive(vp->handle)) { FX_StopSound(vp->handle); + vp->handle = 0; } #if 0 @@ -1529,7 +1532,7 @@ DoTimedSound(VOC3D_INFOp p) if (p->tics >= p->maxtics) { - if (!FX_SoundActive(p->handle)) + if (!FX_SoundValidAndActive(p->handle)) { // Check for special case ambient sounds p->num = RandomizeAmbientSpecials(p->num); @@ -1549,7 +1552,7 @@ DoTimedSound(VOC3D_INFOp p) p->deleted = TRUE; // Mark old sound for deletion } } - } // !FX_SoundActive + } p->tics = 0; //while (p->tics >= p->maxtics) // Really stupid thing to do! @@ -1577,8 +1580,11 @@ StopAmbientSound(void) if (p->flags & v3df_kill) { - if (FX_SoundActive(p->handle)) + if (FX_SoundValidAndActive(p->handle)) + { FX_StopSound(p->handle); // Make sure to stop active sounds + p->handle = 0; + } p->deleted = TRUE; } @@ -1668,8 +1674,11 @@ DoUpdateSounds3D(void) // Is the sound slated for death? Kill it, otherwise play it. if (p->flags & v3df_kill) { - if (FX_SoundActive(p->handle)) + if (FX_SoundValidAndActive(p->handle)) + { FX_StopSound(p->handle); // Make sure to stop active sounds + p->handle = 0; + } //DSPRINTF(ds,"%d had v3df_kill.\n",p->num); //MONO_PRINT(ds); @@ -1677,7 +1686,7 @@ DoUpdateSounds3D(void) } else { - if (!FX_SoundActive(p->handle) && !looping) + if (!FX_SoundValidAndActive(p->handle) && !looping) { if (p->flags & v3df_intermit) { @@ -1691,7 +1700,7 @@ DoUpdateSounds3D(void) p->deleted = TRUE; } } - else if (FX_SoundActive(p->handle)) + else if (FX_SoundValidAndActive(p->handle)) { if (p->flags & v3df_follow) { @@ -1732,6 +1741,7 @@ DoUpdateSounds3D(void) if (dist >= 255 && p->vp->voc_distance == DIST_NORMAL) { FX_StopSound(p->handle); // Make sure to stop active + p->handle = 0; // sounds } else @@ -1770,7 +1780,7 @@ DoUpdateSounds3D(void) } } } - else if (!FX_SoundActive(p->handle) && looping) + else if (!FX_SoundValidAndActive(p->handle) && looping) { if (p->flags & v3df_follow) { @@ -1898,7 +1908,9 @@ Terminate3DSounds(void) while (vp) { - FX_StopSound(vp->handle); // Make sure to stop active sounds + if (vp->handle > 0) + FX_StopSound(vp->handle); // Make sure to stop active sounds + vp->handle = 0; vp->deleted = TRUE; vp = vp->next; } diff --git a/source/sw/src/zilla.cpp b/source/sw/src/zilla.cpp index 3045b3187..70a557c4b 100644 --- a/source/sw/src/zilla.cpp +++ b/source/sw/src/zilla.cpp @@ -725,7 +725,7 @@ int DoZillaMove(short SpriteNum) //DoActorSlide(SpriteNum); // Random Zilla taunts - if (!FX_SoundActive(handle)) + if (!FX_SoundValidAndActive(handle)) { choose = STD_RANDOM_RANGE(1000); if (choose > 990) From 348ccdfd5bbbd492b7e306cb0f450ac83f88004e Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Tue, 26 Nov 2019 08:25:13 +0000 Subject: [PATCH 18/22] Templatize the branchless negation method used for GV_FLAG_NEGATIVE git-svn-id: https://svn.eduke32.com/eduke32@8312 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/build/include/compat.h --- source/build/include/compat.h | 11 +++++++++-- source/duke3d/src/gamevars.cpp | 3 +-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/source/build/include/compat.h b/source/build/include/compat.h index 54b49d33c..2bcbbf5a3 100644 --- a/source/build/include/compat.h +++ b/source/build/include/compat.h @@ -1067,6 +1067,13 @@ FORCE_INLINE CONSTEXPR DivResult divrhs(T lhs) { return divide(lhs, (T)base); } + +template +static FORCE_INLINE CONSTEXPR_CXX14 enable_if_t::value, T> NEGATE_ON_CONDITION(T value, T2 condition) +{ + T const invert = !!condition; + return (value ^ -invert) + invert; +} #endif template @@ -1081,11 +1088,11 @@ CONSTEXPR size_t logbasenegative(T n) return n > static_cast(-(native_t)base) ? 1 : 1 + logbase(n / static_cast(-(native_t)base)); } +#endif + #define isPow2OrZero(v) (((v) & ((v) - 1)) == 0) #define isPow2(v) (isPow2OrZero(v) && (v)) -#endif - ////////// Bitfield manipulation ////////// #if 0 diff --git a/source/duke3d/src/gamevars.cpp b/source/duke3d/src/gamevars.cpp index 7bbda3cd6..1b4a5deb0 100644 --- a/source/duke3d/src/gamevars.cpp +++ b/source/duke3d/src/gamevars.cpp @@ -760,7 +760,6 @@ static FORCE_INLINE int __fastcall getvar__(int const gameVar, int const spriteN int returnValue = 0; int const varFlags = var.flags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK); - int const invertResult = !!(gameVar & GV_FLAG_NEGATIVE); if (!varFlags) returnValue = var.global; else if (varFlags == GAMEVAR_PERACTOR) @@ -775,7 +774,7 @@ static FORCE_INLINE int __fastcall getvar__(int const gameVar, int const spriteN case GAMEVAR_Q16PTR: returnValue = fix16_to_int(*(fix16_t *)var.global); break; } - return (returnValue ^ -invertResult) + invertResult; + return NEGATE_ON_CONDITION(returnValue, gameVar & GV_FLAG_NEGATIVE); } } From abdd807e7fdfbc5978b7de4e9a9d26df852377e7 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Tue, 26 Nov 2019 19:10:24 +0100 Subject: [PATCH 19/22] - fixed merge errors. --- source/rr/src/screens.cpp | 1 - source/sw/src/border.cpp | 3 --- source/sw/src/game.cpp | 14 ++------------ 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/source/rr/src/screens.cpp b/source/rr/src/screens.cpp index 87bbf83ba..1cb208e5e 100644 --- a/source/rr/src/screens.cpp +++ b/source/rr/src/screens.cpp @@ -753,7 +753,6 @@ FString GameInterface::statFPS() GameStats GameInterface::getStats() { - GameStats stats; DukePlayer_t* p = g_player[myconnectindex].ps; return { p->actors_killed, p->max_actors_killed, p->secret_rooms, p->max_secret_rooms, p->player_par / REALGAMETICSPERSEC }; } diff --git a/source/sw/src/border.cpp b/source/sw/src/border.cpp index 5f042d291..33398e44b 100644 --- a/source/sw/src/border.cpp +++ b/source/sw/src/border.cpp @@ -24,9 +24,6 @@ Prepared for public release: 03/28/2005 - Charlie Wiederhold, 3D Realms */ //------------------------------------------------------------------------- #include "ns.h" -// Added improved crosshair accuracy -// Added UsingMenus for fragbar -// #include "build.h" diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index 2c0ee37fe..fde75d0b1 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -105,13 +105,6 @@ signed char MNU_InputString(char*, short); SWBOOL IsCommand(const char* str); SWBOOL MNU_StartNetGame(void); -#ifdef _WIN32 -# include "winbits.h" -#endif - -const char* AppProperName = "VoidSW"; -const char* AppTechnicalName = "voidsw"; - #if DEBUG #define BETA 0 @@ -4072,9 +4065,6 @@ void getinput(SW_PACKET *loc) int32_t keymove; constexpr int const analogExtent = 32767; // KEEPINSYNC sdlayer.cpp - svel -= info.dx * keyMove / analogExtent; - vel -= info.dz * keyMove / analogExtent; - if (running) { if (pp->sop_control) @@ -4110,12 +4100,12 @@ void getinput(SW_PACKET *loc) angvel += info.dyaw * (turnamount << 1) / analogExtent; } - if (aimMode) + if (true)//aimMode) aimvel = -info.mousey / 64; else vel = -(info.mousey >> 6); - if (!in_mouseflip) + if (in_mouseflip) aimvel = -aimvel; aimvel -= info.dpitch * turnamount / analogExtent; From 7698f73b55735fce9296e4f10ec1985186cd498a Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Wed, 27 Nov 2019 07:33:04 +0000 Subject: [PATCH 20/22] Fix tautological comparison in savegame.cpp git-svn-id: https://svn.eduke32.com/eduke32@8314 1a8010ca-5511-0410-912e-c29ae57300e0 --- source/duke3d/src/savegame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/duke3d/src/savegame.cpp b/source/duke3d/src/savegame.cpp index 9bbbb4008..1c195fd00 100644 --- a/source/duke3d/src/savegame.cpp +++ b/source/duke3d/src/savegame.cpp @@ -466,7 +466,7 @@ int32_t G_LoadPlayer(savebrief_t & sv) if (currentboardfilename[0]) { // only setup art if map differs from previous - if (!previousboardfilename[0] || previousboardfilename != currentboardfilename) + if (!previousboardfilename[0] || Bstrcmp(previousboardfilename, currentboardfilename)) artSetupMapArt(currentboardfilename); Bstrcpy(previousboardfilename, currentboardfilename); append_ext_UNSAFE(currentboardfilename, ".mhk"); From ece20928a0632d1bfbf9739d15c6ba1c0f828d76 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Wed, 27 Nov 2019 07:33:08 +0000 Subject: [PATCH 21/22] Fix buffer overflow in getclosestcol_lim Patch from Nuke.YKT. git-svn-id: https://svn.eduke32.com/eduke32@8315 1a8010ca-5511-0410-912e-c29ae57300e0 --- source/build/src/colmatch.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/build/src/colmatch.cpp b/source/build/src/colmatch.cpp index 4ccdaf895..d6c40feeb 100644 --- a/source/build/src/colmatch.cpp +++ b/source/build/src/colmatch.cpp @@ -92,7 +92,7 @@ int32_t getclosestcol_lim(int32_t const r, int32_t const g, int32_t const b, int int mindist = -1; - int const k = (numclosestcolresults > COLRESULTSIZ) ? (COLRESULTSIZ-4) : (numclosestcolresults-4); + int const k = (numclosestcolresults > COLRESULTSIZ) ? COLRESULTSIZ : numclosestcolresults; if (!numclosestcolresults) goto skip; @@ -101,7 +101,7 @@ int32_t getclosestcol_lim(int32_t const r, int32_t const g, int32_t const b, int int i; - for (i = 0; i < k+4; i+=4) + for (i = 0; i <= k-4; i+=4) { if (col == (getclosestcol_results[i] & 0x00ffffff)) { mindist = i; break; } if (col == (getclosestcol_results[i+1] & 0x00ffffff)) { mindist = i+1; break; } From 0a70c5e55f642cd5d4df7d6f1f63c511f0502923 Mon Sep 17 00:00:00 2001 From: hendricks266 Date: Wed, 27 Nov 2019 07:33:34 +0000 Subject: [PATCH 22/22] SW: Sanitize all uses of wall.nextwall to prevent OOBs git-svn-id: https://svn.eduke32.com/eduke32@8322 1a8010ca-5511-0410-912e-c29ae57300e0 # Conflicts: # source/sw/src/jnstub.cpp # source/sw/src/sector.cpp --- source/sw/src/copysect.cpp | 29 +++--- source/sw/src/draw.cpp | 3 +- source/sw/src/game.cpp | 4 +- source/sw/src/game.h | 3 - source/sw/src/light.cpp | 16 ++-- source/sw/src/rooms.cpp | 2 +- source/sw/src/rotator.cpp | 16 +++- source/sw/src/sector.cpp | 188 ++++++++----------------------------- source/sw/src/slidor.cpp | 49 +++++----- source/sw/src/sprite.cpp | 13 ++- source/sw/src/track.cpp | 8 +- source/sw/src/weapon.cpp | 2 +- 12 files changed, 124 insertions(+), 209 deletions(-) diff --git a/source/sw/src/copysect.cpp b/source/sw/src/copysect.cpp index 9f04672f1..39ff71fec 100644 --- a/source/sw/src/copysect.cpp +++ b/source/sw/src/copysect.cpp @@ -63,20 +63,23 @@ void CopySectorWalls(short dest_sectnum, short src_sectnum) wall[dest_wall_num].lotag = wall[src_wall_num].lotag; wall[dest_wall_num].extra = wall[src_wall_num].extra; - if (wall[dest_wall_num].nextwall >= 0 && wall[src_wall_num].nextwall >= 0) + uint16_t const dest_nextwall = wall[dest_wall_num].nextwall; + uint16_t const src_nextwall = wall[src_wall_num].nextwall; + + if (dest_nextwall < MAXWALLS && src_nextwall < MAXWALLS) { - wall[wall[dest_wall_num].nextwall].picnum = wall[wall[src_wall_num].nextwall].picnum; - wall[wall[dest_wall_num].nextwall].xrepeat = wall[wall[src_wall_num].nextwall].xrepeat; - wall[wall[dest_wall_num].nextwall].yrepeat = wall[wall[src_wall_num].nextwall].yrepeat; - wall[wall[dest_wall_num].nextwall].overpicnum = wall[wall[src_wall_num].nextwall].overpicnum; - wall[wall[dest_wall_num].nextwall].pal = wall[wall[src_wall_num].nextwall].pal; - wall[wall[dest_wall_num].nextwall].cstat = wall[wall[src_wall_num].nextwall].cstat; - wall[wall[dest_wall_num].nextwall].shade = wall[wall[src_wall_num].nextwall].shade; - wall[wall[dest_wall_num].nextwall].xpanning = wall[wall[src_wall_num].nextwall].xpanning; - wall[wall[dest_wall_num].nextwall].ypanning = wall[wall[src_wall_num].nextwall].ypanning; - wall[wall[dest_wall_num].nextwall].hitag = wall[wall[src_wall_num].nextwall].hitag; - wall[wall[dest_wall_num].nextwall].lotag = wall[wall[src_wall_num].nextwall].lotag; - wall[wall[dest_wall_num].nextwall].extra = wall[wall[src_wall_num].nextwall].extra; + wall[dest_nextwall].picnum = wall[src_nextwall].picnum; + wall[dest_nextwall].xrepeat = wall[src_nextwall].xrepeat; + wall[dest_nextwall].yrepeat = wall[src_nextwall].yrepeat; + wall[dest_nextwall].overpicnum = wall[src_nextwall].overpicnum; + wall[dest_nextwall].pal = wall[src_nextwall].pal; + wall[dest_nextwall].cstat = wall[src_nextwall].cstat; + wall[dest_nextwall].shade = wall[src_nextwall].shade; + wall[dest_nextwall].xpanning = wall[src_nextwall].xpanning; + wall[dest_nextwall].ypanning = wall[src_nextwall].ypanning; + wall[dest_nextwall].hitag = wall[src_nextwall].hitag; + wall[dest_nextwall].lotag = wall[src_nextwall].lotag; + wall[dest_nextwall].extra = wall[src_nextwall].extra; } dest_wall_num = wall[dest_wall_num].point2; diff --git a/source/sw/src/draw.cpp b/source/sw/src/draw.cpp index de415fbf7..9d138852b 100644 --- a/source/sw/src/draw.cpp +++ b/source/sw/src/draw.cpp @@ -2413,7 +2413,8 @@ drawscreen(PLAYERp pp) i = wal->nextsector; if (i < 0) continue; if (wal->cstat&0x0071) continue; - if (wall[wal->nextwall].cstat&0x0071) continue; + uint16_t const nextwall = wal->nextwall; + if (nextwall < MAXWALLS && wall[nextwall].cstat&0x0071) continue; if (sector[i].lotag == 32767) continue; if (sector[i].ceilingz >= sector[i].floorz) continue; show2dsector[i>>3] |= (1<<(i&7)); diff --git a/source/sw/src/game.cpp b/source/sw/src/game.cpp index fde75d0b1..437d5eadf 100644 --- a/source/sw/src/game.cpp +++ b/source/sw/src/game.cpp @@ -4442,7 +4442,7 @@ void drawoverheadmap(int cposx, int cposy, int czoom, short cang) for (j = startwall, wal = &wall[startwall]; j <= endwall; j++, wal++) { k = wal->nextwall; - if (k < 0) + if ((unsigned)k >= MAXWALLS) continue; if ((show2dwall[j >> 3] & (1 << (j & 7))) == 0) @@ -4695,7 +4695,7 @@ SHOWSPRITE: for (j = startwall, wal = &wall[startwall]; j <= endwall; j++, wal++) { - if (wal->nextwall >= 0) + if ((uint16_t)wal->nextwall < MAXWALLS) continue; if ((show2dwall[j >> 3] & (1 << (j & 7))) == 0) diff --git a/source/sw/src/game.h b/source/sw/src/game.h index 111ac1878..ecdb085c5 100644 --- a/source/sw/src/game.h +++ b/source/sw/src/game.h @@ -360,9 +360,6 @@ extern char MessageOutputString[256]; #define SET_SPRITE_TAG13(sp,val) (*((short*)&sprite[sp].xoffset)) = B_LITTLE16(val) #define SET_SPRITE_TAG14(sp,val) (*((short*)&sprite[sp].xrepeat)) = B_LITTLE16(val) -// this will get you the other wall moved by dragpoint -#define DRAG_WALL(w) (wall[wall[(w)].nextwall].point2) - // OVER and UNDER water macros #define SpriteInDiveArea(sp) (TEST(sector[(sp)->sectnum].extra, SECTFX_DIVE_AREA) ? TRUE : FALSE) #define SpriteInUnderwaterArea(sp) (TEST(sector[(sp)->sectnum].extra, SECTFX_UNDERWATER|SECTFX_UNDERWATER2) ? TRUE : FALSE) diff --git a/source/sw/src/light.cpp b/source/sw/src/light.cpp index b7c0c530b..c9778faf5 100644 --- a/source/sw/src/light.cpp +++ b/source/sw/src/light.cpp @@ -93,13 +93,17 @@ void SectorLightShade(SPRITEp sp, short intensity) wall[w].pal = sp->pal; wallcount++; - if (TEST(sp->extra, SPRX_BOOL5) && wall[w].nextwall >= 0) + if (TEST(sp->extra, SPRX_BOOL5)) { - base_shade = wall_shade[wallcount]; - wall[wall[w].nextwall].shade = base_shade + intensity; - if (!TEST_BOOL6(sp)) - wall[wall[w].nextwall].pal = sp->pal; - wallcount++; + uint16_t const nextwall = wall[w].nextwall; + if (nextwall < MAXWALLS) + { + base_shade = wall_shade[wallcount]; + wall[nextwall].shade = base_shade + intensity; + if (!TEST_BOOL6(sp)) + wall[nextwall].pal = sp->pal; + wallcount++; + } } } } diff --git a/source/sw/src/rooms.cpp b/source/sw/src/rooms.cpp index 99e812ba6..92a258c6f 100644 --- a/source/sw/src/rooms.cpp +++ b/source/sw/src/rooms.cpp @@ -126,7 +126,7 @@ void SetWallWarpHitscan(short sectnum) // Travel all the way around loop setting wall bits do { - if (wall[wall_num].nextwall >= 0) + if ((uint16_t)wall[wall_num].nextwall < MAXWALLS) SET(wall[wall_num].cstat, CSTAT_WALL_WARP_HITSCAN); wall_num = wall[wall_num].point2; } diff --git a/source/sw/src/rotator.cpp b/source/sw/src/rotator.cpp index c187faa5c..97cd46f1d 100644 --- a/source/sw/src/rotator.cpp +++ b/source/sw/src/rotator.cpp @@ -280,8 +280,12 @@ void DoRotatorSetInterp(short SpriteNum) setinterpolation(&wall[w].x); setinterpolation(&wall[w].y); - setinterpolation(&wall[DRAG_WALL(w)].x); - setinterpolation(&wall[DRAG_WALL(w)].y); + uint16_t const nextwall = wall[w].nextwall; + if (nextwall < MAXWALLS) + { + setinterpolation(&wall[wall[nextwall].point2].x); + setinterpolation(&wall[wall[nextwall].point2].y); + } } } @@ -299,8 +303,12 @@ void DoRotatorStopInterp(short SpriteNum) stopinterpolation(&wall[w].x); stopinterpolation(&wall[w].y); - stopinterpolation(&wall[DRAG_WALL(w)].x); - stopinterpolation(&wall[DRAG_WALL(w)].y); + uint16_t const nextwall = wall[w].nextwall; + if (nextwall < MAXWALLS) + { + stopinterpolation(&wall[wall[nextwall].point2].x); + stopinterpolation(&wall[wall[nextwall].point2].y); + } } } diff --git a/source/sw/src/sector.cpp b/source/sw/src/sector.cpp index c8535df7f..93611bec3 100644 --- a/source/sw/src/sector.cpp +++ b/source/sw/src/sector.cpp @@ -107,8 +107,12 @@ void SetSectorWallBits(short sectnum, int bit_mask, SWBOOL set_sectwall, SWBOOL if (set_sectwall) SET(wall[wall_num].extra, bit_mask); - if (set_nextwall && wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, bit_mask); + if (set_nextwall) + { + uint16_t const nextwall = wall[wall_num].nextwall; + if (nextwall < MAXWALLS) + SET(wall[nextwall].extra, bit_mask); + } wall_num = wall[wall_num].point2; } @@ -143,6 +147,28 @@ void WallSetupDontMove(void) } } +static void WallSetupLoop(WALLp wp, int16_t lotag, int16_t extra) +{ + // set first wall + { + SET(wp->extra, extra); + uint16_t const nextwall = wp->nextwall; + if (nextwall < MAXWALLS) + SET(wall[nextwall].extra, extra); + } + + // Travel all the way around loop setting wall bits + for (uint16_t wall_num = wp->point2; + wall[wall_num].lotag != lotag; + wall_num = wall[wall_num].point2) + { + SET(wall[wall_num].extra, extra); + uint16_t const nextwall = wall[wall_num].nextwall; + if (nextwall < MAXWALLS) + SET(wall[nextwall].extra, extra); + } +} + void WallSetup(void) { @@ -181,112 +207,33 @@ WallSetup(void) { case TAG_WALL_LOOP_DONT_SPIN: { - short wall_num, start_wall; - - // set first wall - SET(wp->extra, WALLFX_LOOP_DONT_SPIN); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_LOOP_DONT_SPIN); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_DONT_SPIN; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_LOOP_DONT_SPIN); - auto const nextwall = wall[wall_num].nextwall; - if ((unsigned)nextwall < MAXSECTORS) - SET(wall[nextwall].extra, WALLFX_LOOP_DONT_SPIN); - } - + WallSetupLoop(wp, TAG_WALL_LOOP_DONT_SPIN, WALLFX_LOOP_DONT_SPIN); break; } case TAG_WALL_LOOP_DONT_SCALE: { - short wall_num, start_wall; - - // set first wall - SET(wp->extra, WALLFX_DONT_SCALE); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_DONT_SCALE); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_DONT_SCALE; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_DONT_SCALE); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_DONT_SCALE); - } - + WallSetupLoop(wp, TAG_WALL_LOOP_DONT_SCALE, WALLFX_DONT_SCALE); wp->lotag = 0; - break; } case TAG_WALL_LOOP_OUTER_SECONDARY: { - short wall_num, start_wall; - - // make sure its a red wall - ASSERT(wp->nextwall >= 0); - - // set first wall - SET(wp->extra, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_OUTER_SECONDARY; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY); - } + // make sure it's a red wall + ASSERT((uint16_t)wp->nextwall < MAXWALLS); + WallSetupLoop(wp, TAG_WALL_LOOP_OUTER_SECONDARY, WALLFX_LOOP_OUTER|WALLFX_LOOP_OUTER_SECONDARY); break; } case TAG_WALL_LOOP_OUTER: { - short wall_num, start_wall; - - // make sure its a red wall - ASSERT(wp->nextwall >= 0); - - // set first wall - SET(wp->extra, WALLFX_LOOP_OUTER); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_LOOP_OUTER); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_OUTER; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_LOOP_OUTER); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_LOOP_OUTER); - } + // make sure it's a red wall + ASSERT((uint16_t)wp->nextwall < MAXWALLS); + WallSetupLoop(wp, TAG_WALL_LOOP_OUTER, WALLFX_LOOP_OUTER); wp->lotag = 0; - break; } @@ -299,76 +246,19 @@ WallSetup(void) case TAG_WALL_LOOP_SPIN_2X: { - short wall_num, start_wall; - - // set first wall - SET(wp->extra, WALLFX_LOOP_SPIN_2X); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_LOOP_SPIN_2X); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_SPIN_2X; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_LOOP_SPIN_2X); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_LOOP_SPIN_2X); - } - + WallSetupLoop(wp, TAG_WALL_LOOP_SPIN_2X, WALLFX_LOOP_SPIN_2X); break; } case TAG_WALL_LOOP_SPIN_4X: { - short wall_num, start_wall; - - // set first wall - SET(wp->extra, WALLFX_LOOP_SPIN_4X); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_LOOP_SPIN_4X); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_SPIN_4X; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_LOOP_SPIN_4X); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_LOOP_SPIN_4X); - } - + WallSetupLoop(wp, TAG_WALL_LOOP_SPIN_4X, WALLFX_LOOP_SPIN_4X); break; } case TAG_WALL_LOOP_REVERSE_SPIN: { - short wall_num, start_wall; - - // set first wall - SET(wp->extra, WALLFX_LOOP_REVERSE_SPIN); - if (wp->nextwall >= 0) - SET(wall[wp->nextwall].extra, WALLFX_LOOP_REVERSE_SPIN); - - // move the the next wall - start_wall = wp->point2; - - // Travel all the way around loop setting wall bits - for (wall_num = start_wall; - wall[wall_num].lotag != TAG_WALL_LOOP_REVERSE_SPIN; - wall_num = wall[wall_num].point2) - { - SET(wall[wall_num].extra, WALLFX_LOOP_REVERSE_SPIN); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].extra, WALLFX_LOOP_REVERSE_SPIN); - } - + WallSetupLoop(wp, TAG_WALL_LOOP_REVERSE_SPIN, WALLFX_LOOP_REVERSE_SPIN); break; } diff --git a/source/sw/src/slidor.cpp b/source/sw/src/slidor.cpp index 61c247ac4..697513cab 100644 --- a/source/sw/src/slidor.cpp +++ b/source/sw/src/slidor.cpp @@ -273,13 +273,14 @@ void DoSlidorInterp(short SpriteNum, INTERP_FUNCp interp_func) switch (wall[w].lotag) { case TAG_WALL_SLIDOR_LEFT: - + { // prev wall pw = w - 1; if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + uint16_t const nextwall = wall[w].nextwall; + if (nextwall >= MAXWALLS) { // white wall - move 4 points interp_func(&wall[w].x); @@ -291,21 +292,23 @@ void DoSlidorInterp(short SpriteNum, INTERP_FUNCp interp_func) { // red wall - move 2 points interp_func(&wall[w].x); - interp_func(&wall[DRAG_WALL(w)].x); + interp_func(&wall[wall[nextwall].point2].x); interp_func(&wall[wall[w].point2].x); - interp_func(&wall[DRAG_WALL(wall[w].point2)].x); + interp_func(&wall[wall[wall[wall[w].point2].nextwall].point2].x); } break; + } case TAG_WALL_SLIDOR_RIGHT: - + { // prev wall pw = w - 1; if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + uint16_t const nextwall = wall[w].nextwall; + if (nextwall >= MAXWALLS) { // white wall - move 4 points interp_func(&wall[w].x); @@ -317,21 +320,23 @@ void DoSlidorInterp(short SpriteNum, INTERP_FUNCp interp_func) { // red wall - move 2 points interp_func(&wall[w].x); - interp_func(&wall[DRAG_WALL(w)].x); + interp_func(&wall[wall[nextwall].point2].x); interp_func(&wall[wall[w].point2].x); - interp_func(&wall[DRAG_WALL(wall[w].point2)].x); + interp_func(&wall[wall[wall[wall[w].point2].nextwall].point2].x); } break; + } case TAG_WALL_SLIDOR_UP: - + { // prev wall pw = w - 1; if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + uint16_t const nextwall = wall[w].nextwall; + if (nextwall >= MAXWALLS) { interp_func(&wall[w].y); interp_func(&wall[pw].y); @@ -341,21 +346,23 @@ void DoSlidorInterp(short SpriteNum, INTERP_FUNCp interp_func) else { interp_func(&wall[w].y); - interp_func(&wall[DRAG_WALL(w)].y); + interp_func(&wall[wall[nextwall].point2].y); interp_func(&wall[wall[w].point2].y); - interp_func(&wall[DRAG_WALL(wall[w].point2)].y); + interp_func(&wall[wall[wall[wall[w].point2].nextwall].point2].y); } break; + } case TAG_WALL_SLIDOR_DOWN: - + { // prev wall pw = w - 1; if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + uint16_t const nextwall = wall[w].nextwall; + if (nextwall >= MAXWALLS) { interp_func(&wall[w].y); interp_func(&wall[pw].y); @@ -365,14 +372,14 @@ void DoSlidorInterp(short SpriteNum, INTERP_FUNCp interp_func) else { interp_func(&wall[w].y); - interp_func(&wall[DRAG_WALL(w)].y); + interp_func(&wall[wall[nextwall].point2].y); interp_func(&wall[wall[w].point2].y); - interp_func(&wall[DRAG_WALL(wall[w].point2)].y); + interp_func(&wall[wall[wall[wall[w].point2].nextwall].point2].y); } - break; } + } w = wall[w].point2; } @@ -397,7 +404,7 @@ int DoSlidorMoveWalls(short SpriteNum, int amt) if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + if ((uint16_t)wall[w].nextwall >= MAXWALLS) { // white wall - move 4 points wall[w].x -= amt; @@ -421,7 +428,7 @@ int DoSlidorMoveWalls(short SpriteNum, int amt) if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + if ((uint16_t)wall[w].nextwall >= MAXWALLS) { // white wall - move 4 points wall[w].x += amt; @@ -445,7 +452,7 @@ int DoSlidorMoveWalls(short SpriteNum, int amt) if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + if ((uint16_t)wall[w].nextwall >= MAXWALLS) { wall[w].y -= amt; wall[pw].y -= amt; @@ -467,7 +474,7 @@ int DoSlidorMoveWalls(short SpriteNum, int amt) if (w < startwall) pw = endwall; - if (wall[w].nextwall < 0) + if ((uint16_t)wall[w].nextwall >= MAXWALLS) { wall[w].y += amt; wall[pw].y += amt; diff --git a/source/sw/src/sprite.cpp b/source/sw/src/sprite.cpp index c3fb96ab2..3a7940bdf 100644 --- a/source/sw/src/sprite.cpp +++ b/source/sw/src/sprite.cpp @@ -2616,7 +2616,8 @@ SpriteSetup(void) wallcount++; if (TEST_BOOL5(sp)) { - if (wall[w].nextwall >= 0) + uint16_t const nextwall = wall[w].nextwall; + if (nextwall < MAXWALLS) { wall_shade[wallcount] = wall[wall[w].nextwall].shade; wallcount++; @@ -2672,7 +2673,8 @@ SpriteSetup(void) wallcount++; if (TEST_BOOL5(sp)) { - if (wall[w].nextwall >= 0) + uint16_t const nextwall = wall[w].nextwall; + if (nextwall < MAXWALLS) { wall_shade[wallcount] = wall[wall[w].nextwall].shade; wallcount++; @@ -2955,7 +2957,7 @@ SpriteSetup(void) do { // DO NOT TAG WHITE WALLS! - if (wall[wall_num].nextwall >= 0) + if ((uint16_t)wall[wall_num].nextwall < MAXWALLS) { SET(wall[wall_num].cstat, CSTAT_WALL_WARP_HITSCAN); } @@ -3070,8 +3072,9 @@ SpriteSetup(void) do { SET(wall[wall_num].cstat, CSTAT_WALL_BLOCK_ACTOR); - if (wall[wall_num].nextwall >= 0) - SET(wall[wall[wall_num].nextwall].cstat, CSTAT_WALL_BLOCK_ACTOR); + uint16_t const nextwall = wall[wall_num].nextwall; + if (nextwall < MAXWALLS) + SET(wall[nextwall].cstat, CSTAT_WALL_BLOCK_ACTOR); wall_num = wall[wall_num].point2; } while (wall_num != start_wall); diff --git a/source/sw/src/track.cpp b/source/sw/src/track.cpp index dab981945..a3a147f32 100644 --- a/source/sw/src/track.cpp +++ b/source/sw/src/track.cpp @@ -872,8 +872,9 @@ SectorObjectSetupBounds(SECTOR_OBJECTp sop) // each wall has this set - for collision detection SET(wall[k].extra, WALLFX_SECTOR_OBJECT|WALLFX_DONT_STICK); - if (wall[k].nextwall >= 0) - SET(wall[wall[k].nextwall].extra, WALLFX_SECTOR_OBJECT|WALLFX_DONT_STICK); + uint16_t const nextwall = wall[k].nextwall; + if (nextwall < MAXWALLS) + SET(wall[nextwall].extra, WALLFX_SECTOR_OBJECT|WALLFX_DONT_STICK); } } @@ -2117,7 +2118,8 @@ DetectSectorObjectByWall(WALLp wph) // if outer wall check the NEXTWALL also if (TEST(wp->extra, WALLFX_LOOP_OUTER)) { - if (wph == &wall[wp->nextwall]) + uint16_t const nextwall = wp->nextwall; + if (nextwall < MAXWALLS && wph == &wall[nextwall]) return sop; } diff --git a/source/sw/src/weapon.cpp b/source/sw/src/weapon.cpp index 94dee2d19..e92139b8a 100644 --- a/source/sw/src/weapon.cpp +++ b/source/sw/src/weapon.cpp @@ -20654,7 +20654,7 @@ SWBOOL TestDontStick(short SpriteNum, short hit_sect, short hit_wall, int hit_z) return TRUE; // if blocking red wallo - if (TEST(wp->cstat, CSTAT_WALL_BLOCK) && wp->nextwall >= 0) + if (TEST(wp->cstat, CSTAT_WALL_BLOCK) && (uint16_t)wp->nextwall < MAXWALLS) return TRUE; return FALSE;