diff --git a/server/gameserver/human.cc b/server/gameserver/human.cc index 48cbb0d..cc9ce9f 100644 --- a/server/gameserver/human.cc +++ b/server/gameserver/human.cc @@ -492,12 +492,52 @@ void Human::BeKill(int killer_id, const std::string& killer_name) void Human::DecHP(float dec_hp, int killer_id, const std::string& killer_name) { + auto downed_func = [] (const a8::XParams& param) + { + Human* hum = (Human*)param.sender.GetUserData(); + if (!hum->downed) { + hum->room->xtimer.DeleteTimer(hum->downed_timer); + return; + } + if (hum->dead) { + return; + } + if (!hum->HasLiveTeammate()) { + hum->BeKill(param.param1, param.param2); + return; + } + int dec_hp = MetaMgr::Instance()->GetSysParamAsInt("downed_dec_hp"); + hum->DecHP(dec_hp, param.param1, param.param2); + }; if (energy_shield > 0.001f) { energy_shield = std::max(0.0f, energy_shield - dec_hp); } else { health = std::max(0.0f, health - dec_hp); - if (health <= 0.0001f) { - BeKill(killer_id, killer_name); + if (health <= 0.0001f && !dead) { + if (downed) { + if (downed_timer) { + room->xtimer.DeleteTimer(downed_timer); + } + downed = false; + downed_timer = nullptr; + BeKill(killer_id, killer_name); + } else { + if (HasLiveTeammate()) { + health = MetaMgr::Instance()->GetSysParamAsInt("downed_recover_hp"); + downed = true; + downed_timer = room->xtimer.AddRepeatTimerAndAttach( + SERVER_FRAME_RATE, + a8::XParams() + .SetSender(this) + .SetParam1(killer_id) + .SetParam2(killer_name), + downed_func, + &xtimer_attacher.timer_list_ + ); + } else { + BeKill(killer_id, killer_name); + } + } } } SyncAroundPlayers(); @@ -522,3 +562,15 @@ void Human::RemovePartObjects(Entity* entity) { part_objects.erase(entity); } + +bool Human::HasLiveTeammate() +{ + if (team_members) { + for (auto& hum : *team_members) { + if (!hum->dead) { + return true; + } + } + } + return false; +} diff --git a/server/gameserver/human.h b/server/gameserver/human.h index a8f5b83..3eb700f 100644 --- a/server/gameserver/human.h +++ b/server/gameserver/human.h @@ -76,6 +76,8 @@ class Human : public Entity int pain_killer_lastingtime = 0; xtimer_list* pain_killer_timer = nullptr; + xtimer_list* downed_timer = nullptr; + std::set* team_members = nullptr; Human(); @@ -109,6 +111,7 @@ class Human : public Entity void AddToPartObjects(Entity* entity); void RemoveNewObjects(Entity* entity); void RemovePartObjects(Entity* entity); + bool HasLiveTeammate(); protected: long long last_shot_frameno_ = 0; diff --git a/server/gameserver/player.cc b/server/gameserver/player.cc index 642a28f..2f9acde 100644 --- a/server/gameserver/player.cc +++ b/server/gameserver/player.cc @@ -82,6 +82,9 @@ void Player::Update(int delta_time) void Player::UpdateMove() { + if (action_type == AT_Relive) { + CancelAction(); + } ++moved_frames; if (moved_frames > 4) { moving = false; @@ -243,6 +246,24 @@ void Player::UpdateAction() } } break; + case AT_Relive: + { + Entity* entity = room->GetEntityByUniId(action_target_id); + if (entity->entity_type != ET_Player) { + return; + } + Human* hum = (Human*)entity; + if (!hum->dead && hum->downed) { + hum->health = MetaMgr::Instance()->GetSysParamAsInt("downed_relive_recover_hp"); + hum->downed = false; + if (hum->downed_timer) { + room->xtimer.DeleteTimer(hum->downed_timer); + hum->downed_timer = nullptr; + } + SyncAroundPlayers(); + } + } + break; default: { } @@ -472,6 +493,11 @@ void Player::ProcInteraction() LootInteraction((Loot*)entity); } break; + case ET_Player: + { + HumanInteraction((Human*)entity); + } + break; default: break; } @@ -651,6 +677,22 @@ void Player::LootInteraction(Loot* entity) room->AddDeletedObject(entity->entity_uniid, false); } +void Player::HumanInteraction(Human* hum) +{ + if (hum == this) { + return; + } + if (!hum->downed) { + return; + } + StartAction( + AT_Relive, + MetaMgr::Instance()->GetSysParamAsInt("downed_relive_time") * 1000, + room->frame_no, + hum->entity_uniid + ); +} + void Player::SendUpdateMsg() { MakeUpdateMsg(); diff --git a/server/gameserver/player.h b/server/gameserver/player.h index d82030e..36a7057 100644 --- a/server/gameserver/player.h +++ b/server/gameserver/player.h @@ -86,6 +86,7 @@ class Player : public Human void ProcInteraction(); void ObstacleInteraction(Obstacle* entity); void LootInteraction(Loot* entity); + void HumanInteraction(Human* hum); void SendUpdateMsg(); void _CMMove(f8::MsgHdr& hdr, const cs::CMMove& msg);