diff --git a/source/games/sw/src/coolie.cpp b/source/games/sw/src/coolie.cpp index d6a7743f3..8eac328ce 100644 --- a/source/games/sw/src/coolie.cpp +++ b/source/games/sw/src/coolie.cpp @@ -562,7 +562,7 @@ int SpawnCoolg(short SpriteNum) { // Don't do a ghost every time - if (RANDOM_RANGE(1000) > 700) + if (RANDOM_RANGE(1000) > 700 || Skill < MinEnemySkill - 1) { return(0); } diff --git a/source/games/sw/src/game.h b/source/games/sw/src/game.h index 697655440..8c515e487 100644 --- a/source/games/sw/src/game.h +++ b/source/games/sw/src/game.h @@ -2095,6 +2095,7 @@ extern USERSAVE puser[MAX_SW_PLAYERS_REG]; extern double smoothratio; extern int MoveSkip4, MoveSkip2, MoveSkip8; +extern int MinEnemySkill; #define MASTER_SWITCHING 1 diff --git a/source/games/sw/src/girlninj.cpp b/source/games/sw/src/girlninj.cpp index 582e96f56..59ab2d1e2 100644 --- a/source/games/sw/src/girlninj.cpp +++ b/source/games/sw/src/girlninj.cpp @@ -728,7 +728,7 @@ SetupGirlNinja(short SpriteNum) else { u = SpawnUser(SpriteNum, GIRLNINJA_RUN_R0, s_GirlNinjaRun[0]); - u->Health = 100; + u->Health = (Skill < MinEnemySkill - 1) ? 50 : 100; } u->StateEnd = s_GirlNinjaDie; diff --git a/source/games/sw/src/ninja.cpp b/source/games/sw/src/ninja.cpp index 892f50774..e637fe6ee 100644 --- a/source/games/sw/src/ninja.cpp +++ b/source/games/sw/src/ninja.cpp @@ -1832,6 +1832,10 @@ SetupNinja(short SpriteNum) ANIMATOR DoActorDecide; short pic = sp->picnum; + // Fake some skill settings in case the lower skills are empty. + int RedNinjaHealth = MinEnemySkill <= Skill ? HEALTH_RED_NINJA : HEALTH_NINJA; + if (Skill < MinEnemySkill - 1) sp->pal = 0; + if (TEST(sp->cstat, CSTAT_SPRITE_RESTORE)) { u = User[SpriteNum].Data(); @@ -1853,7 +1857,7 @@ SetupNinja(short SpriteNum) u->Attrib = &InvisibleNinjaAttrib; EnemyDefaults(SpriteNum, &NinjaGreenActionSet, &NinjaPersonality); if (!TEST(sp->cstat, CSTAT_SPRITE_RESTORE)) - u->Health = HEALTH_RED_NINJA; + u->Health = RedNinjaHealth; SET(sp->cstat, CSTAT_SPRITE_TRANSLUCENT); sp->shade = 127; sp->pal = u->spal = PALETTE_PLAYER5; @@ -1881,7 +1885,7 @@ SetupNinja(short SpriteNum) u->Attrib = &NinjaAttrib; EnemyDefaults(SpriteNum, &NinjaRedActionSet, &NinjaPersonality); if (!TEST(sp->cstat, CSTAT_SPRITE_RESTORE)) - u->Health = HEALTH_RED_NINJA; + u->Health = RedNinjaHealth; sp->pal = u->spal = PALETTE_PLAYER3; if (pic == NINJA_CRAWL_R0) { @@ -1906,7 +1910,7 @@ SetupNinja(short SpriteNum) u->Attrib = &NinjaAttrib; EnemyDefaults(SpriteNum, &NinjaSeekerActionSet, &NinjaPersonality); if (!TEST(sp->cstat, CSTAT_SPRITE_RESTORE)) - u->Health = HEALTH_RED_NINJA; + u->Health = RedNinjaHealth; sp->pal = u->spal = PAL_XLAT_LT_TAN; u->Attrib = &NinjaAttrib; } @@ -1915,7 +1919,7 @@ SetupNinja(short SpriteNum) u->Attrib = &NinjaAttrib; EnemyDefaults(SpriteNum, &NinjaGrenadeActionSet, &NinjaPersonality); if (!TEST(sp->cstat, CSTAT_SPRITE_RESTORE)) - u->Health = HEALTH_RED_NINJA; + u->Health = RedNinjaHealth; sp->pal = u->spal = PAL_XLAT_LT_GREY; u->Attrib = &NinjaAttrib; } diff --git a/source/games/sw/src/save.cpp b/source/games/sw/src/save.cpp index efe2be333..a8a17a524 100644 --- a/source/games/sw/src/save.cpp +++ b/source/games/sw/src/save.cpp @@ -1270,6 +1270,7 @@ void GameInterface::SerializeGameState(FSerializer& arc) .Array("bosswasseen", bosswasseen, 3) .Array("BossSpriteNum", BossSpriteNum, 3); arc.Array("tracks", Track, countof(Track)) + ("minenemyskill", MinEnemySkill) ; postSerializePanelSprites(arc); arc.EndObject(); diff --git a/source/games/sw/src/sprite.cpp b/source/games/sw/src/sprite.cpp index bc6a1ec1b..eb7810072 100644 --- a/source/games/sw/src/sprite.cpp +++ b/source/games/sw/src/sprite.cpp @@ -92,6 +92,7 @@ void InitWeaponUzi(PLAYERp); bool FAF_Sector(short sectnum); int MoveSkip4, MoveSkip2, MoveSkip8; +int MinEnemySkill; extern STATE s_CarryFlag[]; extern STATE s_CarryFlagNoDet[]; @@ -1049,7 +1050,8 @@ ActorTestSpawn(SPRITEp sp) } // Skill ranges from -1 (No Monsters) to 3 - if (TEST(sp->extra, SPRX_SKILL) > Skill) + int spawnskill = TEST(sp->extra, SPRX_SKILL); + if (spawnskill > MinEnemySkill || (MinEnemySkill == 0 && spawnskill > Skill)) { // JBF: hack to fix Wanton Destruction's missing Sumos, Serpents, and Zilla on Skill < 2 @@ -1091,23 +1093,44 @@ ActorTestSpawn(SPRITEp sp) } -void PreCacheRipper(void); -void PreCacheRipper2(void); -void PreCacheCoolie(void); -void PreCacheSerpent(void); -void PreCacheGuardian(void); -void PreCacheNinja(void); -void PreCacheSumo(void); -void PreCacheEel(void); -void PreCacheToiletGirl(void); -void PreCacheWashGirl(void); -void PreCacheTrash(void); -void PreCacheBunny(void); -void PreCacheSkel(void); -void PreCacheHornet(void); -void PreCacheSkull(void); -void PreCacheBetty(void); -void PreCachePachinko(void); +int EnemyCheckSkill() +{ + StatIterator it(STAT_DEFAULT); + int maxskill = INT_MAX; + int SpriteNum; + while ((SpriteNum = it.NextIndex()) >= 0) + { + auto sp = &sprite[SpriteNum]; + + switch (sp->picnum) + { + case COOLIE_RUN_R0: + case NINJA_RUN_R0: + case NINJA_CRAWL_R0: + case GORO_RUN_R0: + case 1441: + case COOLG_RUN_R0: + case EEL_RUN_R0: + case SUMO_RUN_R0: + case ZILLA_RUN_R0: + case RIPPER_RUN_R0: + case RIPPER2_RUN_R0: + case SERP_RUN_R0: + case LAVA_RUN_R0: + case SKEL_RUN_R0: + case HORNET_RUN_R0: + case SKULL_R0: + case BETTY_R0: + case GIRLNINJA_RUN_R0: + { + int myskill = sp->extra & SPRX_SKILL; + if (myskill < maxskill) maxskill = myskill; + } + } + } + if (maxskill < 0 || maxskill == INT_MAX) maxskill = 0; + return maxskill; +} bool ActorSpawn(SPRITEp sp) @@ -1789,6 +1812,8 @@ SpriteSetup(void) short i, num; int cz,fz; + MinEnemySkill = EnemyCheckSkill(); + // special case for player PicAnimOff(PLAYER_NINJA_RUN_R0); @@ -1808,6 +1833,8 @@ SpriteSetup(void) // Call my little sprite setup routine first JS_SpriteSetup(); + int minEnemySkill = EnemyCheckSkill(); + StatIterator it(STAT_DEFAULT); while ((SpriteNum = it.NextIndex()) >= 0) {