Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: hazard system #1091

Merged
merged 7 commits into from
May 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions config.lua.dist
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,20 @@ boostedBossSlot = true
boostedBossLootBonus = 250
boostedBossKillBonus = 3

-- Hazard system
toogleHazardSystem = true
hazardCriticalInterval = 2000
hazardCriticalMultiplier = 25
hazardDamageMultiplier = 200
hazardDodgeMultiplier = 85
hazardPodsDropMultiplier = 87
hazardPodsTimeToDamage = 2000
hazardPodsTimeToSpawn = 4000
hazardExpBonusMultiplier = 2
hazardLootBonusMultiplier = 2
hazardPodsDamage = 5
hazardSpawnPlunderMultiplier = 25

-- Familiar system
-- NOTE: the time will be divided by 2 to get half the value, the familiar lasts 15 minutes by default and the cooldown of the spell is 30 minutes
-- Only change it here if you know what you are doing or to make testing easier with familiars
Expand Down
17 changes: 17 additions & 0 deletions data-canary/scripts/lib/register_monster_type.lua
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,23 @@ registerMonsterType.defenses = function(mtype, mask)
end
end

registerMonsterType.hazard = function(mtype, mask)
if mask.hazard ~= nil then
if mask.hazard.criticalChance ~= nil then
mtype:hazardSystemCrit(mask.hazard.criticalChance)
end
if mask.hazard.canDodge ~= nil then
mtype:hazardSystemDodge(mask.hazard.canDodge)
end
if mask.hazard.canSpawnPod ~= nil then
mtype:hazardSystemSpawnPod(mask.hazard.canSpawnPod)
end
if mask.hazard.canDealMoreDamage ~= nil then
mtype:hazardSystemDamageBoost(mask.hazard.canDealMoreDamage)
end
end
end

local function loadcastSound(effect, incomingLua, mtype)
-- Throw shoottype
if effect == CONST_ANI_SPEAR or
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,9 @@ function loginEvents.onLogin(player)
-- Secret Library
"SecretLibraryKill",
-- The Dream Courts
"DreamCourtsKill"
"DreamCourtsKill",
-- Hazard System
"HazardSystemCombat"
}

for i = 1, #events do
Expand Down
110 changes: 110 additions & 0 deletions data-otservbr-global/scripts/hazard/hazard_system.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
local hazardSystemStepPod = MoveEvent()

function hazardSystemStepPod.onStepIn(creature, item, position, fromPosition)
if not configManager.getBoolean(configKeys.TOGGLE_HAZARDSYSTEM) then
item:remove()
return
end

local player = creature:getPlayer()
if not player then
return
end

local timer = item:getCustomAttribute("HazardSystem_PodTimer")
if timer then
local timeMs = os.time() * 1000
timer = timeMs - timer
if timer >= configManager.getNumber(configKeys.HAZARD_PODS_TIME_TO_DAMAGE) and timer < configManager.getNumber(configKeys.HAZARD_PODS_TIME_TO_SPAWN) then
player:sendCancelMessage("You stepped too late on the primal pod and it explodes.")
player:getPosition():sendMagicEffect(CONST_ME_ENERGYHIT)
local damage = math.ceil((player:getMaxHealth() * configManager.getNumber(configKeys.HAZARD_PODS_DAMAGE)) / 100)
local points = player:getHazardSystemPoints()
if points ~= 0 then
damage = math.ceil((damage * (100 + points)) / 100)
end
damage = damage + 500
doTargetCombatHealth(0, player, COMBAT_LIFEDRAIN, -damage, -damage, CONST_ME_DRAWBLOOD)
end
end

item:remove()
return true
end

hazardSystemStepPod:id(ITEM_PRIMAL_POD)
hazardSystemStepPod:register()

local SpawnHazardSystemFungosaurus = function(position)
local tile = Tile(position)
if tile then
local podItem = tile:getItemById(ITEM_PRIMAL_POD)
if podItem then
local monster = Game.createMonster("Fungosaurus", position, false, true)
if monster then
monster:say("The primal pod explode and wild emerges from it.")
end
podItem:remove()
end
end
end

local hazardSystemSpawnPod = CreatureEvent("HazardSystemCombat")

function hazardSystemSpawnPod.onKill(player, creature, lastHit)
if not configManager.getBoolean(configKeys.TOGGLE_HAZARDSYSTEM) then
return true
end

local monster = creature:getMonster()
if not creature or not monster or not monster:isOnHazardSystem() then
return true
end

local points = player:getHazardSystemPoints()
if points > 0 then
local party = player:getParty()
if party then
for _, member in ipairs(party:getMembers()) do
if member and member:getHazardSystemPoints() < points then
points = member:getHazardSystemPoints()
end
end

local leader = party:getLeader()
if leader and leader:getHazardSystemPoints() < points then
points = leader:getHazardSystemPoints()
end
end
end

if points == 0 then
return true
end

local chanceTo = math.random(1, 10000)
if chanceTo <= (points * configManager.getNumber(configKeys.HAZARD_PODS_DROP_MULTIPLIER)) then
local closesestPosition = player:getClosestFreePosition(monster:getPosition(), 4, true)
local primalPod = Game.createItem(ITEM_PRIMAL_POD, 1, closesestPosition.x == 0 and monster:getPosition() or closesestPosition)
if primalPod then
primalPod:setCustomAttribute("HazardSystem_PodTimer", os.time() * 1000)
local podPos = primalPod:getPosition()
addEvent(SpawnHazardSystemFungosaurus, configManager.getNumber(configKeys.HAZARD_PODS_TIME_TO_SPAWN), podPos)
end
return true
end

chanceTo = math.random(1, 10000)
if chanceTo <= (points * configManager.getNumber(configKeys.HAZARDSYSTEM_SPAWN_PLUNDER_MULTIPLIER)) then
local closesestPosition = player:getClosestFreePosition(monster:getPosition(), 4, true)
local monster = Game.createMonster("Plunder Patriarch", closesestPosition.x == 0 and monster:getPosition() or closesestPosition, false, true)
if monster then
monster:say("The Plunder Patriarch rises from the ashes.")
end
return true
end

return true
end

hazardSystemSpawnPod:register()
17 changes: 17 additions & 0 deletions data-otservbr-global/scripts/lib/register_monster_type.lua
Original file line number Diff line number Diff line change
Expand Up @@ -530,6 +530,23 @@ registerMonsterType.defenses = function(mtype, mask)
end
end

registerMonsterType.hazard = function(mtype, mask)
if mask.hazard ~= nil then
if mask.hazard.criticalChance ~= nil then
mtype:hazardSystemCrit(mask.hazard.criticalChance)
end
if mask.hazard.canDodge ~= nil then
mtype:hazardSystemDodge(mask.hazard.canDodge)
end
if mask.hazard.canSpawnPod ~= nil then
mtype:hazardSystemSpawnPod(mask.hazard.canSpawnPod)
end
if mask.hazard.canDealMoreDamage ~= nil then
mtype:hazardSystemDamageBoost(mask.hazard.canDealMoreDamage)
end
end
end

local function loadcastSound(effect, incomingLua, mtype)
-- Throw shoottype
if effect == CONST_ANI_SPEAR or
Expand Down
15 changes: 15 additions & 0 deletions data/events/scripts/monster.lua
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function Monster:onDropLoot(corpse)
if not player or player:getStamina() > 840 then
local monsterLoot = mType:getLoot()
local charmBonus = false
local hazardMsg = false
if player and mType and mType:raceId() > 0 then
local charm = player:getCharmMonsterType(CHARM_GUT)
if charm and charm:raceId() == mType:raceId() then
Expand All @@ -49,6 +50,17 @@ function Monster:onDropLoot(corpse)
Spdlog.warn(string.format("[1][Monster:onDropLoot] - Could not add loot item to boosted monster: %s, from corpse id: %d.", self:getName(), corpse:getId()))
end
end
if self:isOnHazardSystem() and player ~= nil then
local chanceTo = math.random(1, 100)
if chanceTo <= (2 * player:getHazardSystemPoints() * configManager.getNumber(configKeys.HAZARDSYSTEM_LOOT_BONUS_MULTIPLIER)) then
local podItem = corpse:createLootItem(monsterLoot[i], charmBonus, preyChanceBoost)
if not podItem then
Spdlog.warn(string.format("[Monster:onDropLoot] - Could not add loot item to hazard monster: %s, from corpse id: %d.", self:getName(), corpse:getId()))
else
hazardMsg = true
end
end
end
if not item then
Spdlog.warn(string.format("[2][Monster:onDropLoot] - Could not add loot item to monster: %s, from corpse id: %d.", self:getName(), corpse:getId()))
end
Expand Down Expand Up @@ -113,6 +125,9 @@ function Monster:onDropLoot(corpse)
if charmBonus then
text = text .. " (active charm bonus)"
end
if hazardMsg then
text = text .. " (Hazard system)"
end
local party = player:getParty()
if party then
party:broadcastPartyLoot(text)
Expand Down
12 changes: 12 additions & 0 deletions src/config/config_definitions.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ enum booleanConfig_t {
TOGGLE_SERVER_IS_RETRO,
TOGGLE_TRAVELS_FREE,
OLD_PROTOCOL,
TOGGLE_HAZARDSYSTEM,

LAST_BOOLEAN_CONFIG
};
Expand Down Expand Up @@ -200,6 +201,17 @@ enum integerConfig_t {
BOOSTED_BOSS_LOOT_BONUS,
BOOSTED_BOSS_KILL_BONUS,
FAMILIAR_TIME,
HAZARD_CRITICAL_INTERVAL,
HAZARD_CRITICAL_MULTIPLIER,
HAZARD_DAMAGE_MULTIPLIER,
HAZARD_DODGE_MULTIPLIER,
HAZARD_PODS_DROP_MULTIPLIER,
HAZARD_PODS_TIME_TO_DAMAGE,
HAZARD_EXP_BONUS_MULTIPLIER,
HAZARD_LOOT_BONUS_MULTIPLIER,
HAZARD_PODS_DAMAGE,
HAZARD_PODS_TIME_TO_SPAWN,
HAZARD_SPAWN_PLUNDER_MULTIPLIER,

LAST_INTEGER_CONFIG
};
Expand Down
13 changes: 13 additions & 0 deletions src/config/configmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,19 @@ bool ConfigManager::load() {
boolean[TOGGLE_SERVER_IS_RETRO] = getGlobalBoolean(L, "toggleServerIsRetroPVP", false);
boolean[TOGGLE_TRAVELS_FREE] = getGlobalBoolean(L, "toggleTravelsFree", false);

boolean[TOGGLE_HAZARDSYSTEM] = getGlobalBoolean(L, "toogleHazardSystem", true);
integer[HAZARD_CRITICAL_INTERVAL] = getGlobalNumber(L, "hazardCriticalInterval", 2000);
integer[HAZARD_CRITICAL_MULTIPLIER] = getGlobalNumber(L, "hazardCriticalMultiplier", 25);
integer[HAZARD_DAMAGE_MULTIPLIER] = getGlobalNumber(L, "hazardDamageMultiplier", 200);
integer[HAZARD_DODGE_MULTIPLIER] = getGlobalNumber(L, "hazardDodgeMultiplier", 85);
integer[HAZARD_PODS_DROP_MULTIPLIER] = getGlobalNumber(L, "hazardPodsDropMultiplier", 87);
integer[HAZARD_PODS_TIME_TO_DAMAGE] = getGlobalNumber(L, "hazardPodsTimeToDamage", 2000);
integer[HAZARD_PODS_TIME_TO_SPAWN] = getGlobalNumber(L, "hazardPodsTimeToSpawn", 4000);
integer[HAZARD_EXP_BONUS_MULTIPLIER] = getGlobalNumber(L, "hazardExpBonusMultiplier", 2);
integer[HAZARD_LOOT_BONUS_MULTIPLIER] = getGlobalNumber(L, "hazardLootBonusMultiplier", 2);
integer[HAZARD_PODS_DAMAGE] = getGlobalNumber(L, "hazardPodsDamage", 5);
integer[HAZARD_SPAWN_PLUNDER_MULTIPLIER] = getGlobalNumber(L, "hazardSpawnPlunderMultiplier", 25);

loaded = true;
lua_close(L);
return true;
Expand Down
14 changes: 14 additions & 0 deletions src/creatures/monsters/monster.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,14 @@ void Monster::removeFriend(Creature* creature) {
}
}

void Monster::handleHazardSystem(Creature &creature) const {
// Hazard system (Icon UI)
auto player = creature.getPlayer();
if (player && isOnHazardSystem()) {
player->incrementeHazardSystemReference();
}
}

void Monster::addTarget(Creature* creature, bool pushFront /* = false*/) {
assert(creature != this);
if (std::find(targetList.begin(), targetList.end(), creature) == targetList.end()) {
Expand All @@ -313,6 +321,8 @@ void Monster::addTarget(Creature* creature, bool pushFront /* = false*/) {
}
if (!master && getFaction() != FACTION_DEFAULT && creature->getPlayer())
totalPlayersOnScreen++;

handleHazardSystem(*creature);
}
}

Expand All @@ -327,6 +337,8 @@ void Monster::removeTarget(Creature* creature) {
totalPlayersOnScreen--;
}

handleHazardSystem(*creature);

creature->decrementReferenceCounter();
targetList.erase(it);
}
Expand All @@ -348,6 +360,7 @@ void Monster::updateTargetList() {
while (targetIterator != targetList.end()) {
Creature* creature = *targetIterator;
if (creature->getHealth() <= 0 || !canSee(creature->getPosition())) {
handleHazardSystem(*creature);
creature->decrementReferenceCounter();
targetIterator = targetList.erase(targetIterator);
} else {
Expand All @@ -374,6 +387,7 @@ void Monster::clearTargetList() {

void Monster::clearFriendList() {
for (Creature* creature : friendList) {
handleHazardSystem(*creature);
creature->decrementReferenceCounter();
}
friendList.clear();
Expand Down
23 changes: 23 additions & 0 deletions src/creatures/monsters/monster.h
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,28 @@ class Monster final : public Creature {
return mType->info.raceid;
}

// Hazard system
bool isOnHazardSystem() const {
return mType->info.hazardSystemCritChance != 0 || mType->info.canSpawnPod || mType->info.canDodge || mType->info.canDamageBoost;
}

bool getHazardSystemDodge() const {
return mType->info.canDodge;
}

bool getHazardSystemSpawnPod() const {
return mType->info.canSpawnPod;
}

bool getHazardSystemDamageBoost() const {
return mType->info.canDamageBoost;
}

uint16_t getHazardSystemCritChance() const {
return mType->info.hazardSystemCritChance;
}
// Hazard end

void updateTargetList();
void clearTargetList();
void clearFriendList();
Expand Down Expand Up @@ -360,6 +382,7 @@ class Monster final : public Creature {

void addFriend(Creature* creature);
void removeFriend(Creature* creature);
void handleHazardSystem(Creature &creature) const;
void addTarget(Creature* creature, bool pushFront = false);
void removeTarget(Creature* creature);

Expand Down
6 changes: 6 additions & 0 deletions src/creatures/monsters/monsters.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ class MonsterType {

uint64_t experience = 0;

// Hazard system (0-10000), divide by 100 gives us %
uint16_t hazardSystemCritChance = 0;
bool canDamageBoost = false;
bool canSpawnPod = false;
bool canDodge = false;

uint32_t manaCost = 0;
uint32_t yellChance = 0;
uint32_t yellSpeedTicks = 0;
Expand Down
Loading