diff --git a/src/entity.cpp b/src/entity.cpp index 2a764de9a..6b0625aeb 100644 --- a/src/entity.cpp +++ b/src/entity.cpp @@ -2528,6 +2528,24 @@ void Entity::modHP(int amount) { Compendium_t::Events_t::eventUpdateCodex(skill[2], Compendium_t::CPDM_HP_LOST_RUN, "hp", oldHP - entitystats->HP); Compendium_t::Events_t::eventUpdateCodex(skill[2], Compendium_t::CPDM_HP_LOST_TOTAL, "hp", oldHP - entitystats->HP); + + if ( gameplayCustomManager.inUse() && gameplayCustomManager.doTraumaDamage ) // damage maxHP based on settings + { + double damage = oldHP - entitystats->HP; + double percent = ( (double)gameplayCustomManager.traumaDamagePercent / 100.0 ); + double traumaDmg = percent * damage; + int oldMaxHP = entitystats->MAXHP; + + if (traumaDmg < 1.0) + { + traumaDmg = 0.0; // don't allow player to take unfair trauma damage + } + + entitystats->MAXHP -= traumaDmg; + entitystats->MAXHP = std::min(oldMaxHP, std::max( gameplayCustomManager.traumaDamageHPLimit, entitystats->MAXHP ) ); + entitystats->HP = std::min(entitystats->HP, entitystats->MAXHP); + // prevent maxHP from dropping below minimum, don't increase maxHP by mistake, don't allow HP to exceed maxHP + } } } } @@ -3141,13 +3159,29 @@ void Entity::handleEffects(Stat* myStats) static ConsoleVariable cvar_lvlup_ally_sfx("/lvlup_ally_sfx", 520); // increase MAXHP/MAXMP - myStats->MAXHP += HP_MOD; + if ( gameplayCustomManager.inUse() && behavior == &actPlayer ) + { + myStats->MAXHP += gameplayCustomManager.playerLevelupHP; + } + else + { + myStats->MAXHP += HP_MOD; + } modHP(getHPRestoreOnLevelUp()); myStats->HP = std::min(myStats->HP, myStats->MAXHP); if ( !(behavior == &actMonster && monsterAllySummonRank != 0) ) { - myStats->MP += MP_MOD; - myStats->MAXMP += MP_MOD; + if ( gameplayCustomManager.inUse() && behavior == &actPlayer) + { + myStats->MP += gameplayCustomManager.playerLevelupMP; + myStats->MAXMP += gameplayCustomManager.playerLevelupMP; + } + else + { + myStats->MP += MP_MOD; + myStats->MAXMP += MP_MOD; + } + if ( behavior == &actPlayer && myStats->playerRace == RACE_INSECTOID && myStats->stat_appearance == 0 ) { myStats->MAXMP = std::min(100, myStats->MAXMP); @@ -5453,7 +5487,10 @@ real_t Entity::getACEffectiveness(Entity* my, Stat* myStats, bool isPlayer, Enti if ( myStats->defending ) { - return 1.0; + if ( !gameplayCustomManager.inUse() || my->behavior != &actPlayer ) + { + return 1.0; + } } int blessings = 0; @@ -5496,6 +5533,26 @@ real_t Entity::getACEffectiveness(Entity* my, Stat* myStats, bool isPlayer, Enti blessings += cursedItemIsBuff ? abs(myStats->amulet->beatitude) : myStats->amulet->beatitude; } outNumBlessings = blessings; + + if ( gameplayCustomManager.inUse() && my->behavior == &actPlayer ) + { + double playerACEffPassive = gameplayCustomManager.playerACEpassive / 100.0; + double playerACEffActive = gameplayCustomManager.playerACEactive / 100.0; + double ACEtoCalculate = 0.0; + + if ( myStats->defending ) + { + ACEtoCalculate = playerACEffActive; + } + else + { + ACEtoCalculate = playerACEffPassive; + } + ACEtoCalculate = std::max(0.0, std::min(1.0, ACEtoCalculate)); + + double blessingModifier = gameplayCustomManager.playerACEbless / 100.0; + return std::max(0.0, std::min(1.0, ACEtoCalculate + blessingModifier * blessings)); + } return std::max(0.0, std::min(1.0, .75 + 0.025 * blessings)); } @@ -5836,6 +5893,10 @@ Sint32 statGetSTR(Stat* entitystats, Entity* my) break; } } + if ( gameplayCustomManager.inUse() && my && my->behavior == &actPlayer ) + { + STR *= gameplayCustomManager.playerMultiplierSTR; + } return STR; } @@ -6084,6 +6145,10 @@ Sint32 statGetDEX(Stat* entitystats, Entity* my) { DEX += 8; } + if ( gameplayCustomManager.inUse() && my && my->behavior == &actPlayer ) + { + DEX *= gameplayCustomManager.playerMultiplierDEX; + } return DEX; } @@ -6191,6 +6256,10 @@ Sint32 statGetCON(Stat* entitystats, Entity* my) percentHP = 100 - percentHP; CON += percentHP / 10; } + if ( gameplayCustomManager.inUse() && my && my->behavior == &actPlayer ) + { + CON *= gameplayCustomManager.playerMultiplierCON; + } return CON; } @@ -6298,6 +6367,10 @@ Sint32 statGetINT(Stat* entitystats, Entity* my) { INT -= std::max(8, static_cast(INT * 0.25)); } + if ( gameplayCustomManager.inUse() && my && my->behavior == &actPlayer ) + { + INT *= gameplayCustomManager.playerMultiplierINT; + } return INT; } @@ -6464,6 +6537,10 @@ Sint32 statGetPER(Stat* entitystats, Entity* my) { PER -= std::max(5, PER / 2); } + if ( gameplayCustomManager.inUse() && my && my->behavior == &actPlayer ) + { + PER *= gameplayCustomManager.playerMultiplierPER; + } return PER; } @@ -6555,6 +6632,10 @@ Sint32 statGetCHR(Stat* entitystats, Entity* my) { CHR += std::max(4, static_cast(CHR * .25)); } + if ( gameplayCustomManager.inUse() && my && my->behavior == &actPlayer ) + { + CHR *= gameplayCustomManager.playerMultiplierCHR; + } return CHR; } @@ -12964,6 +13045,14 @@ void Entity::awardXP(Entity* src, bool share, bool root) if ( gameplayCustomManager.inUse() ) { xpGain = (gameplayCustomManager.globalXPPercent / 100.f) * xpGain; + + if ( gameplayCustomManager.doConditionalXPModifier ) + { + if ( destStats->LVL - srcStats->LVL >= gameplayCustomManager.conditionalXPModLvlThreshold ) // check if level difference exceeds level threshold + { + xpGain = (gameplayCustomManager.conditionalXPModPercent / 100.f) * xpGain; + } + } } else if ( gameModeManager.currentSession.challengeRun.isActive() && gameModeManager.currentSession.challengeRun.globalXPPercent != 100 ) @@ -22822,6 +22911,7 @@ int getEntityHungerInterval(int player, Entity* my, Stat* myStats, EntityHungerI { bool isInsectoidPlayer = false; bool isAutomatonPlayer = false; + bool isSkeletonPlayer = false; if ( player >= 0 ) { if ( stats[player]->type == AUTOMATON ) @@ -22832,6 +22922,10 @@ int getEntityHungerInterval(int player, Entity* my, Stat* myStats, EntityHungerI { isInsectoidPlayer = true; } + else if ( stats[player]->type == SKELETON ) + { + isSkeletonPlayer = true; + } } else if ( my && my->behavior == &actPlayer && myStats ) { @@ -22843,6 +22937,10 @@ int getEntityHungerInterval(int player, Entity* my, Stat* myStats, EntityHungerI { isInsectoidPlayer = true; } + else if ( myStats->type == SKELETON ) + { + isSkeletonPlayer = true; + } } else if ( myStats ) { @@ -22858,6 +22956,10 @@ int getEntityHungerInterval(int player, Entity* my, Stat* myStats, EntityHungerI { isInsectoidPlayer = true; } + else if ( myStats->type == SKELETON ) + { + isSkeletonPlayer = true; + } break; } } @@ -22883,6 +22985,20 @@ int getEntityHungerInterval(int player, Entity* my, Stat* myStats, EntityHungerI return 1000; } } + else if ( isSkeletonPlayer ) + { + switch ( hungerInterval ) + { + case HUNGER_INTERVAL_OVERSATIATED: + return 5000; // unreachable + case HUNGER_INTERVAL_HUNGRY: + return -1; //unreachable + case HUNGER_INTERVAL_WEAK: + return -1; //unreachable + case HUNGER_INTERVAL_STARVING: + return -1; //unreachable + } + } switch ( hungerInterval ) { @@ -23113,6 +23229,11 @@ int Entity::getHPRestoreOnLevelUp() { int hpMod = HP_MOD; + if ( gameplayCustomManager.inUse() && behavior == &actPlayer ) + { + hpMod = gameplayCustomManager.playerLevelupHP; + } + if ( Stat* myStats = getStats() ) { if ( myStats->helmet && myStats->helmet->type == HAT_CROWN ) diff --git a/src/mod_tools.hpp b/src/mod_tools.hpp index bd95e51b9..3907bba11 100644 --- a/src/mod_tools.hpp +++ b/src/mod_tools.hpp @@ -1855,6 +1855,24 @@ class GameplayCustomManager bool minimapShareProgress = false; int playerWeightPercent = 100; double playerSpeedMax = 12.5; + int playerACEpassive = 75; + int playerACEactive = 100; + double playerACEbless = 2.5; + bool doConditionalXPModifier = false; + int conditionalXPModLvlThreshold = 0; + int conditionalXPModPercent = 100; + double playerMultiplierSTR = 1.0; + double playerMultiplierDEX = 1.0; + double playerMultiplierCON = 1.0; + double playerMultiplierINT = 1.0; + double playerMultiplierPER = 1.0; + double playerMultiplierCHR = 1.0; + int playerLevelupHP = 5; + int playerLevelupMP = 5; + bool doTraumaDamage = false; + int traumaDamagePercent = 0; + int traumaDamageHPLimit = 25; + int zapBrigadeSpawnPercent = 20; inline bool inUse() { return usingCustomManager; }; void resetValues() { @@ -1865,6 +1883,24 @@ class GameplayCustomManager minimapShareProgress = false; playerWeightPercent = 100; playerSpeedMax = 12.5; + playerACEpassive = 75; + playerACEactive = 100; + playerACEbless = 2.5; + doConditionalXPModifier = false; + conditionalXPModLvlThreshold = 0; + conditionalXPModPercent = 100; + playerMultiplierSTR = 1.0; + playerMultiplierDEX = 1.0; + playerMultiplierCON = 1.0; + playerMultiplierINT = 1.0; + playerMultiplierPER = 1.0; + playerMultiplierCHR = 1.0; + playerLevelupHP = 5; + playerLevelupMP = 5; + doTraumaDamage = false; + traumaDamagePercent = 0; + traumaDamageHPLimit = 25; + zapBrigadeSpawnPercent = 20; minotaurForceEnableFloors.first.clear(); minotaurForceEnableFloors.second.clear(); @@ -1933,6 +1969,30 @@ class GameplayCustomManager CustomHelpers::addMemberToRoot(d, "player_speed_weight_impact_percent", rapidjson::Value(playerWeightPercent)); CustomHelpers::addMemberToRoot(d, "player_speed_max", rapidjson::Value(playerSpeedMax)); + CustomHelpers::addMemberToRoot(d, "player_AC_eff_passive_percent", rapidjson::Value(playerACEpassive)); + CustomHelpers::addMemberToRoot(d, "player_AC_eff_block_percent", rapidjson::Value(playerACEactive)); + CustomHelpers::addMemberToRoot(d, "player_AC_eff_blessing_percent", rapidjson::Value(playerACEbless)); + + CustomHelpers::addMemberToRoot(d, "enable_conditional_xp_modifier", rapidjson::Value(doConditionalXPModifier)); + CustomHelpers::addMemberToRoot(d, "conditional_mod_lvl_difference_threshold", rapidjson::Value(conditionalXPModLvlThreshold)); + CustomHelpers::addMemberToRoot(d, "conditional_xp_modifier_percent", rapidjson::Value(conditionalXPModPercent)); + + CustomHelpers::addMemberToRoot(d, "player_STR_multiplier", rapidjson::Value(playerMultiplierSTR)); + CustomHelpers::addMemberToRoot(d, "player_DEX_multiplier", rapidjson::Value(playerMultiplierDEX)); + CustomHelpers::addMemberToRoot(d, "player_CON_multiplier", rapidjson::Value(playerMultiplierCON)); + CustomHelpers::addMemberToRoot(d, "player_INT_multiplier", rapidjson::Value(playerMultiplierINT)); + CustomHelpers::addMemberToRoot(d, "player_PER_multiplier", rapidjson::Value(playerMultiplierPER)); + CustomHelpers::addMemberToRoot(d, "player_CHR_multiplier", rapidjson::Value(playerMultiplierCHR)); + + CustomHelpers::addMemberToRoot(d, "player_levelup_HP", rapidjson::Value(playerLevelupHP)); + CustomHelpers::addMemberToRoot(d, "player_levelup_MP", rapidjson::Value(playerLevelupMP)); + + CustomHelpers::addMemberToRoot(d, "enable_player_trauma_damage", rapidjson::Value(doTraumaDamage)); + CustomHelpers::addMemberToRoot(d, "trauma_damage_percent", rapidjson::Value(traumaDamagePercent)); + CustomHelpers::addMemberToRoot(d, "trauma_damage_hp_floor", rapidjson::Value(traumaDamageHPLimit)); + + CustomHelpers::addMemberToRoot(d,"zap_brigade_spawnrate_percent", rapidjson::Value(zapBrigadeSpawnPercent)); + rapidjson::Value obj(rapidjson::kObjectType); rapidjson::Value arr(rapidjson::kArrayType); CustomHelpers::addMemberToRoot(d, "minotaur_force_disable_on_floors", obj); @@ -2126,6 +2186,96 @@ class GameplayCustomManager playerSpeedMax = itr->value.GetDouble(); return true; } + else if ( name.compare("player_AC_eff_passive_percent") == 0 ) + { + playerACEpassive = itr->value.GetInt(); + return true; + } + else if ( name.compare("player_AC_eff_block_percent") == 0 ) + { + playerACEactive = itr->value.GetInt(); + return true; + } + else if ( name.compare("player_AC_eff_blessing_percent") == 0 ) + { + playerACEbless = itr->value.GetDouble(); + return true; + } + else if ( name.compare("enable_conditional_xp_modifier") == 0 ) + { + doConditionalXPModifier = itr->value.GetBool(); + return true; + } + else if ( name.compare("conditional_mod_lvl_difference_threshold") == 0 ) + { + conditionalXPModLvlThreshold = itr->value.GetInt(); + return true; + } + else if ( name.compare("conditional_xp_modifier_percent") == 0 ) + { + conditionalXPModPercent = itr->value.GetInt(); + return true; + } + else if ( name.compare("player_STR_multiplier") == 0 ) + { + playerMultiplierSTR = itr->value.GetDouble(); + return true; + } + else if ( name.compare("player_DEX_multiplier") == 0 ) + { + playerMultiplierDEX = itr->value.GetDouble(); + return true; + } + else if ( name.compare("player_CON_multiplier") == 0 ) + { + playerMultiplierCON = itr->value.GetDouble(); + return true; + } + else if ( name.compare("player_INT_multiplier") == 0 ) + { + playerMultiplierINT = itr->value.GetDouble(); + return true; + } + else if ( name.compare("player_PER_multiplier") == 0 ) + { + playerMultiplierPER = itr->value.GetDouble(); + return true; + } + else if ( name.compare("player_CHR_multiplier") == 0 ) + { + playerMultiplierCHR = itr->value.GetDouble(); + return true; + } + else if ( name.compare("player_levelup_HP") == 0 ) + { + playerLevelupHP = itr->value.GetInt(); + return true; + } + else if ( name.compare("player_levelup_MP") == 0 ) + { + playerLevelupMP = itr->value.GetInt(); + return true; + } + else if ( name.compare("enable_player_trauma_damage") == 0 ) + { + doTraumaDamage = itr->value.GetBool(); + return true; + } + else if ( name.compare("trauma_damage_percent") == 0 ) + { + traumaDamagePercent = itr->value.GetInt(); + return true; + } + else if ( name.compare("trauma_damage_hp_floor") == 0 ) + { + traumaDamageHPLimit = itr->value.GetInt(); + return true; + } + else if ( name.compare("zap_brigade_spawnrate_percent") == 0 ) + { + zapBrigadeSpawnPercent = itr->value.GetInt(); + return true; + } else if ( name.compare("minotaur_force_disable_on_floors") == 0 ) { for ( rapidjson::Value::ConstValueIterator arr_itr = itr->value["normal_floors"].Begin(); arr_itr != itr->value["normal_floors"].End(); ++arr_itr ) diff --git a/src/monster_minotaur.cpp b/src/monster_minotaur.cpp index 0178bc000..edb4cb185 100644 --- a/src/monster_minotaur.cpp +++ b/src/monster_minotaur.cpp @@ -687,9 +687,17 @@ void actMinotaurTimer(Entity* my) if ( !my ) { return; } auto& rng = my->entity_rng ? *my->entity_rng : local_rng; + int zapChance = 20; + if ( gameplayCustomManager.inUse() ) + { + zapChance = gameplayCustomManager.zapBrigadeSpawnPercent; + zapChance = std::min(100, zapChance); + zapChance = std::max(0, zapChance); + } + MINOTAURTIMER_LIFE++; if ( MINOTAURTIMER_LIFE == (getMinotaurTimeToArrive() - (TICKS_PER_SECOND * 30)) - && rng.rand() % 5 == 0 ) + && rng.rand() % 100 < zapChance ) { int c; bool spawnedsomebody = false; diff --git a/src/scores.cpp b/src/scores.cpp index dc2c67476..8cdc79718 100644 --- a/src/scores.cpp +++ b/src/scores.cpp @@ -4061,11 +4061,18 @@ void updatePlayerConductsInMainLoop() } if ( !conductGameChallenges[CONDUCT_CLASSIC_MODE] ) { - if ( (svFlags & SV_FLAG_CLASSIC) ) + if ( (svFlags & SV_FLAG_CLASSIC) && currentlevel < 25 ) { conductGameChallenges[CONDUCT_CLASSIC_MODE] = 1; } } + else + { + if ( currentlevel >= 25 ) + { + conductGameChallenges[CONDUCT_CLASSIC_MODE] = 0; + } + } if ( !conductGameChallenges[CONDUCT_MODDED] ) { if ( Mods::numCurrentModsLoaded >= 0 )