Skip to content

Commit

Permalink
feat: hazard system (opentibiabr#1091)
Browse files Browse the repository at this point in the history
This modification introduces the implementation of the Hazard System. The Hazard System is an advanced game mechanic that offers players the opportunity to increase the difficulty and rewards of their hunts in Gnomprona.

The system allows players to increase the hazard level of a hunt, which both increases the damage dealt by monsters and the amount of loot and experience rewards received. The hazard level is adjusted individually by players, but in a team, it's the lowest hazard level among the players that counts for the whole team.

The benefits of increasing the hazard level include greater loot and experience, as well as a higher chance of spawning a Plunder Patriarch when killing a monster. However, with a higher hazard level, all damage dealt by monsters increases, as does the chance for monsters to land critical hits and dodge attacks. Furthermore, the chance of generating Primal Pods when killing a creature increases with a higher hazard level.

Additionally, this modification also implements the mechanic associated with the "Primal Ordeal" quest, where players must defeat the boss "The Primal Menace" to increase hazard qualification. The recommended combat strategy includes focusing on the Primal Pack Beasts, and dealing with the threats of Primal Pods that can transform into the powerful Fungosaurus creature.
  • Loading branch information
dudantas authored and enzerah committed May 21, 2023
1 parent 529e3f8 commit c55242a
Show file tree
Hide file tree
Showing 23 changed files with 448 additions and 3 deletions.
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 Down Expand Up @@ -63,6 +64,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 @@ -132,6 +144,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
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

0 comments on commit c55242a

Please sign in to comment.