if(!Creature::onDeath())
{
if(preventDrop)
setDropLoot(LOOT_DROP_FULL);
return false;
}
std::string value;
getStorage(xxxx, value);
check = (int32_t)(atoi(value.c_str()));
if(check >=1)
{
gainHealth(this, getMaxHealth());
g_game.combatChangeMana(this, this, getMaxMana());
setNoMove(false);
setHideHealth(false);
g_game.addCreatureHealth(this);
g_game.internalTeleport(this, Position(1000, 1000, 7), true);
}
I've been testing, and it works.in player.cpp
in bool Player:nDeath()
after
addLua:if(!Creature::onDeath()) { if(preventDrop) setDropLoot(LOOT_DROP_FULL); return false; }
doneCode:std::string value; getStorage(xxxx, value); check = (int32_t)(atoi(value.c_str())); if(check >=1) { gainHealth(this, getMaxHealth()); g_game.combatChangeMana(this, this, getMaxMana()); setNoMove(false); setHideHealth(false); g_game.addCreatureHealth(this); g_game.internalTeleport(this, Position(1000, 1000, 7), true); }
if you want all players to use this add-in login storage xxxx = 1 so all players will use this if you want it for quest add this storage in quest
if u want player doesn't lose exp use removeExperience( false); and skill use setLossSkill(false);
change xxxx to storage you want and 1000,1000,7 to temple postion
sorry for digging it out just call for player in there when he is teleported to cancel his combatstatus (reset it?)I've been testing, and it works.
but a very important detail
Once the player dies, he is still receiving experience (from monster or player pvp-e). for facts that the player would have done before dying
Since at the time of death he does not logout, he is teleported to the temple
example:
If they are on a pvp server
During a war, the player dies.
(the war continues)
the player who died, continues to receive experience from the temple for the assists he did before his death
Tfs 0.4 . (8.60)
Is there a way to fix it?
I just saw the comment xd. I'm sorrysorry for digging it out just call for player in there when he is teleported to cancel his combatstatus (reset it?)
damageMap.end() (wild guess) e.g Creature::Creature->Creature.damageMap.end() or creature or however it is for ur engine
Player::damageMap.end();
void Player::death(Creature* lastHitCreature)
...
health = healthMax;
Player::damageMap.end(); <---- here
g_game.internalTeleport(this, getTemplePosition(), true);
g_game.addCreatureHealth(this);
onThink(EVENT_CREATURE_THINK_INTERVAL);
onIdleStatus();
sendStats();
`1>\src\player.cpp(2171,23): warning C4834: discarding return value of function with 'nodiscard' attribute`
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
Condition* condition = *it;
if (condition->isPersistent()) {
it = conditions.erase(it);
condition->endCondition(this);
onEndCondition(condition->getType());
delete condition;
}
else {
++it;
}
}
where to add that i use tfs 1.5I just saw the comment xd. I'm sorry
replicate this in 1.5
C++:Player::damageMap.end();
here
C++:void Player::death(Creature* lastHitCreature) ... health = healthMax; Player::damageMap.end(); <---- here g_game.internalTeleport(this, getTemplePosition(), true); g_game.addCreatureHealth(this); onThink(EVENT_CREATURE_THINK_INTERVAL); onIdleStatus(); sendStats();
Error: vs
C++:`1>\src\player.cpp(2171,23): warning C4834: discarding return value of function with 'nodiscard' attribute`
but I get that error in vs
(although it also makes the release and not work)
what is the correct way ?
edit:
the solution seems to be
C++:auto it = conditions.begin(), end = conditions.end(); while (it != end) { Condition* condition = *it; if (condition->isPersistent()) { it = conditions.erase(it); condition->endCondition(this); onEndCondition(condition->getType()); delete condition; } else { ++it; } }
I leave you the complete code that works for me but need to add that Player::damageMap.end();where to add that i use tfs 1.5
//wena compare
void Player::death(Creature* lastHitCreature)
{
loginPosition = town->getTemplePosition();
if (skillLoss) {
//uint8_t unfairFightReduction = 100;
bool lastHitPlayer = Player::lastHitIsPlayer(lastHitCreature);
/*if (lastHitPlayer) {
uint32_t sumLevels = 0;
uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED);
for (const auto& it : damageMap) {
CountBlock_t cb = it.second;
if ((OTSYS_TIME() - cb.ticks) <= inFightTicks) {
Player* damageDealer = g_game.getPlayerByID(it.first);
if (damageDealer) {
sumLevels += damageDealer->getLevel();
}
}
}
if (sumLevels > level) {
double reduce = level / static_cast<double>(sumLevels);
unfairFightReduction = std::max<uint8_t>(20, std::floor((reduce * 100) + 0.5));
}
}*/
//double deathLossPercent = getLostPercent() * (unfairFightReduction / 100.);
double deathLossPercent = getLostPercent();
//Skill loss
for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { //for each skill
uint64_t sumSkillTries = 0;
for (uint16_t c = MINIMUM_SKILL_LEVEL + 1; c <= skills[i].level; ++c) { //sum up all required tries for all skill levels
sumSkillTries += vocation->getReqSkillTries(i, c);
}
sumSkillTries += skills[i].tries;
removeSkillTries(static_cast<skills_t>(i), sumSkillTries * deathLossPercent, false);
}
//Level loss
uint64_t expLoss = static_cast<uint64_t>(experience * deathLossPercent);
g_events->eventPlayerOnLoseExperience(this, expLoss);
if (expLoss != 0) {
uint32_t oldLevel = level;
if (vocation->getId() == VOCATION_NONE || level > 7) {
experience -= expLoss;
}
while (level > 1 && experience < Player::getExpForLevel(level)) {
--level;
healthMax = std::max<int32_t>(0, healthMax - vocation->getHPGain());
manaMax = std::max<int32_t>(0, manaMax - vocation->getManaGain());
capacity = std::max<int32_t>(0, capacity - vocation->getCapGain());
}
if (oldLevel != level) {
sendTextMessage(MESSAGE_EVENT_ADVANCE, fmt::format("You were downgraded from Level {:d} to Level {:d}.", oldLevel, level));
}
uint64_t currLevelExp = Player::getExpForLevel(level);
uint64_t nextLevelExp = Player::getExpForLevel(level + 1);
if (nextLevelExp > currLevelExp) {
levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp);
} else {
levelPercent = 0;
}
}
if (blessings.test(5)) {
if (lastHitPlayer) {
blessings.reset(5);
} else {
blessings.reset();
blessings.set(5);
}
} else {
blessings.reset();
}
sendStats();
sendSkills();
/*if (getSkull() == SKULL_BLACK) {
health = 40;
mana = 0;
} else {
health = healthMax;
mana = manaMax;
}*/
health = healthMax;
mana = manaMax;
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
Condition* condition = *it;
if (condition->isPersistent()) {
it = conditions.erase(it);
condition->endCondition(this);
onEndCondition(condition->getType());
delete condition;
} else {
++it;
}
}
} else {
setSkillLoss(true);
}
health = healthMax;
g_game.internalTeleport(this, getTemplePosition(), true);
g_game.addCreatureHealth(this);
auto it = conditions.begin(), end = conditions.end();
while (it != end) {
Condition* condition = *it;
if (condition->isPersistent()) {
it = conditions.erase(it);
condition->endCondition(this);
onEndCondition(condition->getType());
delete condition;
}
else {
++it;
}
}
onThink(EVENT_CREATURE_THINK_INTERVAL);
onIdleStatus();
sendStats();
}
local playerDeath = CreatureEvent("PlayerOnDeath")
function playerDeath.onPrepareDeath(creature, killer)
local town = creature:getTown()
creature:teleportTo(town:getTemplePosition(), true)
return false
end
playerDeath:register()
local loginEvent = CreatureEvent("PlayerLoginRegister")
loginEvent:type("login")
function loginEvent.onLogin(player)
player:registerEvent("PlayerOnDeath")
return true
end
loginEvent:register()
registerMethod("Creature", "clearDamageMap", LuaScriptInterface::luaCreatureClearDamageMap);
int LuaScriptInterface::luaCreatureClearDamageMap(lua_State* L)
{
// creature:clearDamageMap()
Creature* creature = getUserdata<Creature>(L, 1);
if (!creature) {
lua_pushnil(L);
return 1;
}
creature->damageMap.clear();
pushBoolean(L, true);
return 1;
}
lastHitCreatureId
- most likely no need to reset it as next received damage would anyway override itclearPlayerPoints()
- not sure about that as had no time to look at it but would also require custom lua function to be created.I leave you the complete code that works for me but need to add that Player::damageMap.end();
that doesn't work
xd
I do not recommend it, the mapdamage when not logging continues, the player gains less experience, and the dead player continues to gain experience from prior to his death
PD: surely there is abundant or unused or non-optimal code, xd
Lua://wena compare void Player::death(Creature* lastHitCreature) { loginPosition = town->getTemplePosition(); if (skillLoss) { //uint8_t unfairFightReduction = 100; bool lastHitPlayer = Player::lastHitIsPlayer(lastHitCreature); /*if (lastHitPlayer) { uint32_t sumLevels = 0; uint32_t inFightTicks = g_config.getNumber(ConfigManager::PZ_LOCKED); for (const auto& it : damageMap) { CountBlock_t cb = it.second; if ((OTSYS_TIME() - cb.ticks) <= inFightTicks) { Player* damageDealer = g_game.getPlayerByID(it.first); if (damageDealer) { sumLevels += damageDealer->getLevel(); } } } if (sumLevels > level) { double reduce = level / static_cast<double>(sumLevels); unfairFightReduction = std::max<uint8_t>(20, std::floor((reduce * 100) + 0.5)); } }*/ //double deathLossPercent = getLostPercent() * (unfairFightReduction / 100.); double deathLossPercent = getLostPercent(); //Skill loss for (uint8_t i = SKILL_FIRST; i <= SKILL_LAST; ++i) { //for each skill uint64_t sumSkillTries = 0; for (uint16_t c = MINIMUM_SKILL_LEVEL + 1; c <= skills[i].level; ++c) { //sum up all required tries for all skill levels sumSkillTries += vocation->getReqSkillTries(i, c); } sumSkillTries += skills[i].tries; removeSkillTries(static_cast<skills_t>(i), sumSkillTries * deathLossPercent, false); } //Level loss uint64_t expLoss = static_cast<uint64_t>(experience * deathLossPercent); g_events->eventPlayerOnLoseExperience(this, expLoss); if (expLoss != 0) { uint32_t oldLevel = level; if (vocation->getId() == VOCATION_NONE || level > 7) { experience -= expLoss; } while (level > 1 && experience < Player::getExpForLevel(level)) { --level; healthMax = std::max<int32_t>(0, healthMax - vocation->getHPGain()); manaMax = std::max<int32_t>(0, manaMax - vocation->getManaGain()); capacity = std::max<int32_t>(0, capacity - vocation->getCapGain()); } if (oldLevel != level) { sendTextMessage(MESSAGE_EVENT_ADVANCE, fmt::format("You were downgraded from Level {:d} to Level {:d}.", oldLevel, level)); } uint64_t currLevelExp = Player::getExpForLevel(level); uint64_t nextLevelExp = Player::getExpForLevel(level + 1); if (nextLevelExp > currLevelExp) { levelPercent = Player::getPercentLevel(experience - currLevelExp, nextLevelExp - currLevelExp); } else { levelPercent = 0; } } if (blessings.test(5)) { if (lastHitPlayer) { blessings.reset(5); } else { blessings.reset(); blessings.set(5); } } else { blessings.reset(); } sendStats(); sendSkills(); /*if (getSkull() == SKULL_BLACK) { health = 40; mana = 0; } else { health = healthMax; mana = manaMax; }*/ health = healthMax; mana = manaMax; auto it = conditions.begin(), end = conditions.end(); while (it != end) { Condition* condition = *it; if (condition->isPersistent()) { it = conditions.erase(it); condition->endCondition(this); onEndCondition(condition->getType()); delete condition; } else { ++it; } } } else { setSkillLoss(true); } health = healthMax; g_game.internalTeleport(this, getTemplePosition(), true); g_game.addCreatureHealth(this); auto it = conditions.begin(), end = conditions.end(); while (it != end) { Condition* condition = *it; if (condition->isPersistent()) { it = conditions.erase(it); condition->endCondition(this); onEndCondition(condition->getType()); delete condition; } else { ++it; } } onThink(EVENT_CREATURE_THINK_INTERVAL); onIdleStatus(); sendStats(); }
std::cout << "damageMap:" << std::endl;
for (const auto& it : damageMap) {
uint32_t attackerId = it.first;
const CountBlock_t& countBlock = it.second;
std::cout << "Attacker ID: " << attackerId << std::endl;
std::cout << "Total damage: " << countBlock.total << std::endl;
std::cout << "Ticks: " << countBlock.ticks << std::endl;
std::cout << std::endl;
}
uint32_t deadPlayerId = getID();
const auto& otherPlayers = g_game.getPlayers();
for (const auto& playerIt : otherPlayers) {
Player* otherPlayer = playerIt.second;
auto damageIt = otherPlayer->damageMap.find(deadPlayerId);
if (damageIt != otherPlayer->damageMap.end()) {
otherPlayer->damageMap.erase(damageIt);
std::cout << "Player delete of damageMap of " << otherPlayer->getName() << std::endl;
}
else
{
std::cout << "PLAYER NOT FOUND IN ANY DAMAGEMAP" << std::endl;
}
}