krafttomten
Well-Known Member
Hello OTLand,
I am making a RPPvP server. I have modified AoL and blessings so that they do not prevent item loss in PvP. But now I want to disable it in case there was a severely unfair fight (level 200 killing a level 50 is an exaggerated example). But I need some help.
First, I have tried to implement this strictly in Lua.
Lua
I figured that the onDeath() function used in droploot.lua could be changed so that it calculates if the kill was severely unfair.
The problem is that I do not have access to all the killers in the onDeath() function, I can only see player, corpse, killer, mostDamageKiller, lastHitUnjustified, and mostDamageUnjustified. I don't see how that is enough information to cover all scenarios of an unfair fight. For instance, if a level 50 was killed by ten level 45:s, it would not be possible, to my knowledge, to deduce that it was an unfair fight in Lua, and thus prevent item loss. At best I have managed to cover the scenario where one high level kills a low level, but that is far from satisfying.
The second method I have tried is to change the parameters of the onDeath() lua function through source editing.
C++
In C++ there are two parts I think I could combine somehow, but I am very inexperienced with C++, and I don't know how to make it work.
In creature.cpp there is a code that.. makes the lua function.. somehow..
Void Creature:nDeath()
I figured, if I could add a parameter into this function, a parameter containing all the killers, then I could solve the rest in Lua. There is a C++ function called getKillers(), but I don't know how to implement that as a parameter in the Creature:nDeath() function.
I guess my question is:
How do I add a new parameter containing all killers in the Lua function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)?
My secondary question is:
Is there any other way I could prevent item loss in severely unfair pvp situations?
I am making a RPPvP server. I have modified AoL and blessings so that they do not prevent item loss in PvP. But now I want to disable it in case there was a severely unfair fight (level 200 killing a level 50 is an exaggerated example). But I need some help.
First, I have tried to implement this strictly in Lua.
Lua
I figured that the onDeath() function used in droploot.lua could be changed so that it calculates if the kill was severely unfair.
Lua:
function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)
-- I am using the standard TFS 1.4 code here, because it is familiar to other people.
-- I can implement any solution into my own modified code without problem.
-- I will release the final solution in case anyone is interested.
if player:hasFlag(PlayerFlag_NotGenerateLoot) or player:getVocation():getId() == VOCATION_NONE then
return true
end
local amulet = player:getSlotItem(CONST_SLOT_NECKLACE)
local isRedOrBlack = table.contains({SKULL_RED, SKULL_BLACK}, player:getSkull())
if amulet and amulet.itemid == ITEM_AMULETOFLOSS and not isRedOrBlack then
local isPlayer = false
if killer then
if killer:isPlayer() then
isPlayer = true
else
local master = killer:getMaster()
if master and master:isPlayer() then
isPlayer = true
end
end
end
if not isPlayer or not player:hasBlessing(6) then
player:removeItem(ITEM_AMULETOFLOSS, 1, -1, false)
end
else
for i = CONST_SLOT_HEAD, CONST_SLOT_AMMO do
local item = player:getSlotItem(i)
local lossPercent = player:getLossPercent()
if item then
if isRedOrBlack or math.random(item:isContainer() and 100 or 1000) <= lossPercent then
if (isRedOrBlack or lossPercent ~= 0) and not item:moveTo(corpse) then
item:remove()
end
end
end
end
end
if not player:getSlotItem(CONST_SLOT_BACKPACK) then
player:addItem(ITEM_BAG, 1, false, CONST_SLOT_BACKPACK)
end
return true
end
The second method I have tried is to change the parameters of the onDeath() lua function through source editing.
C++
In C++ there are two parts I think I could combine somehow, but I am very inexperienced with C++, and I don't know how to make it work.
In creature.cpp there is a code that.. makes the lua function.. somehow..
Void Creature:nDeath()
C++:
void Creature::onDeath()
{
bool lastHitUnjustified = false;
bool mostDamageUnjustified = false;
Creature* lastHitCreature = g_game.getCreatureByID(lastHitCreatureId);
Creature* lastHitCreatureMaster;
if (lastHitCreature) {
lastHitUnjustified = lastHitCreature->onKilledCreature(this);
lastHitCreatureMaster = lastHitCreature->getMaster();
} else {
lastHitCreatureMaster = nullptr;
}
Creature* mostDamageCreature = nullptr;
const int64_t timeNow = OTSYS_TIME();
const uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
int32_t mostDamage = 0;
std::map<Creature*, uint64_t> experienceMap;
for (const auto& it : damageMap) {
if (Creature* attacker = g_game.getCreatureByID(it.first)) {
CountBlock_t cb = it.second;
if ((cb.total > mostDamage && (timeNow - cb.ticks <= inFightTicks))) {
mostDamage = cb.total;
mostDamageCreature = attacker;
}
if (attacker != this) {
uint64_t gainExp = getGainedExperience(attacker);
if (Player* attackerPlayer = attacker->getPlayer()) {
attackerPlayer->removeAttacked(getPlayer());
Party* party = attackerPlayer->getParty();
if (party && party->getLeader() && party->isSharedExperienceActive() && party->isSharedExperienceEnabled()) {
attacker = party->getLeader();
}
}
auto tmpIt = experienceMap.find(attacker);
if (tmpIt == experienceMap.end()) {
experienceMap[attacker] = gainExp;
} else {
tmpIt->second += gainExp;
}
}
}
}
for (const auto& it : experienceMap) {
it.first->onGainExperience(it.second, this);
}
if (mostDamageCreature) {
if (mostDamageCreature != lastHitCreature && mostDamageCreature != lastHitCreatureMaster) {
Creature* mostDamageCreatureMaster = mostDamageCreature->getMaster();
if (lastHitCreature != mostDamageCreatureMaster && (lastHitCreatureMaster == nullptr || mostDamageCreatureMaster != lastHitCreatureMaster)) {
mostDamageUnjustified = mostDamageCreature->onKilledCreature(this, false);
}
}
}
bool droppedCorpse = dropCorpse(lastHitCreature, mostDamageCreature, lastHitUnjustified, mostDamageUnjustified);
death(lastHitCreature);
if (master) {
setMaster(nullptr);
}
if (droppedCorpse) {
g_game.removeCreature(this, false);
}
}
I guess my question is:
How do I add a new parameter containing all killers in the Lua function onDeath(player, corpse, killer, mostDamageKiller, lastHitUnjustified, mostDamageUnjustified)?
My secondary question is:
Is there any other way I could prevent item loss in severely unfair pvp situations?