#include "precompile.h" #include "hero.h" #include "human.h" #include "room.h" #include "metamgr.h" #include "loot.h" #include "perfmonitor.h" #include "typeconvert.h" #include "hero.ai.h" #include "mine_sweeper.ai.h" #include "obstacle.h" #include "collider.h" #include "bullet.h" #include "explosion.h" Hero::Hero():Creature() { ++PerfMonitor::Instance()->entity_num[ET_Hero]; } Hero::~Hero() { DetachFromMaster(); if (ai) { A8_SAFE_DELETE(ai); } --PerfMonitor::Instance()->entity_num[ET_Hero]; } void Hero::Initialize() { Creature::Initialize(); RecalcSelfCollider(); MetaData::Equip* weapon_meta = MetaMgr::Instance()->GetEquip(meta->i->default_weapon()); if (weapon_meta) { weapons[GUN_SLOT1].weapon_idx = GUN_SLOT1; weapons[GUN_SLOT1].weapon_id = weapon_meta->i->id(); weapons[GUN_SLOT1].weapon_lv = 1; weapons[GUN_SLOT1].ammo = 10000; weapons[GUN_SLOT1].meta = weapon_meta; weapons[GUN_SLOT1].Recalc(); SetCurrWeapon(&weapons[GUN_SLOT1]); } SetInfiniteBulletMode(); InitAI(); } void Hero::FillMFObjectPart(Room* room, Human* hum, cs::MFObjectPart* part_data) { part_data->set_object_type(ET_Hero); cs::MFHeroPart* p = part_data->mutable_union_obj_10(); p->set_obj_uniid(GetUniId()); TypeConvert::ToPb(GetPos(), p->mutable_pos()); TypeConvert::ToPb(GetMoveDir(), p->mutable_dir()); } void Hero::FillMFObjectFull(Room* room, Human* hum, cs::MFObjectFull* full_data) { full_data->set_object_type(ET_Hero); cs::MFHeroFull* p = full_data->mutable_union_obj_10(); p->set_obj_uniid(GetUniId()); TypeConvert::ToPb(GetPos(), p->mutable_pos()); TypeConvert::ToPb(GetMoveDir(), p->mutable_dir()); p->set_heroid(meta->i->id()); p->set_master_uniid(master.Get() ? master.Get()->GetUniId() : 0); p->set_dead(dead); p->set_health(GetHP()); p->set_max_health(GetMaxHP()); FillBuffList(hum, p->mutable_buff_list()); } void Hero::Update(int delta_time) { ai->Update(delta_time); ++updated_times_; } void Hero::OnExplosionHit(Explosion* e) { if (IsInvincible()) { return; } if (dead) { return; } RemoveBuffByEffectId(kBET_PeaceMode); float dmg = e->GetDmg(); float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) + GetAbility()->GetAttrAbs(kHAT_Def); float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K); finaly_dmg = std::max(finaly_dmg, 0.0f); #ifdef DEBUG { room->BroadcastDebugMsg(a8::Format("explosion dmg:%d def:%d finaly_dmg:%d", {dmg, def, finaly_dmg})); } #endif #if 1 DecHP(finaly_dmg, 1, "", 1); #else DecHP(finaly_dmg, sender.Get()->GetUniId(), sender.Get()->GetName(), gun_meta->i->id()); #endif } void Hero::OnBulletHit(Bullet* bullet) { if (IsInvincible()) { return; } RemoveBuffByEffectId(kBET_PeaceMode); if (!IsDead(room) && (bullet->IsBomb() || bullet->sender.Get()->team_id != team_id)) { float dmg = bullet->GetAtk(); float def = GetDef() * (1 + GetAbility()->GetAttrRate(kHAT_Def)) + GetAbility()->GetAttrAbs(kHAT_Def); float finaly_dmg = dmg * (1 - def/MetaMgr::Instance()->K); finaly_dmg = std::max(finaly_dmg, 0.0f); if (bullet->sender.Get()->IsHuman()) { bullet->sender.Get()->AsHuman()->stats.damage_amount_out += finaly_dmg; } if (bullet->meta->buff_meta) { MustBeAddBuff(bullet->sender.Get(), bullet->meta->i->buffid()); } DecHP(finaly_dmg, bullet->sender.Get()->GetUniId(), bullet->sender.Get()->GetName(), bullet->gun_meta->i->id()); } } float Hero::GetSpeed() { float speed = meta->i->move_speed(); return speed; } void Hero::_UpdateMove(int speed) { do { int distance = std::min(5, speed); InternalUpdateMove(distance); speed -= distance; } while (speed > 0); } void Hero::InternalUpdateMove(float speed) { a8::Vec2 old_pos = GetPos(); a8::Vec2 new_pos = GetPos() + GetMoveDir() * speed; SetPos(new_pos); if (!CheckCollision()) { room->grid_service->MoveCreature(this); } else { if (on_move_collision && !on_move_collision()) { SetPos(old_pos); } } } void Hero::RecalcSelfCollider() { if (!self_collider_) { self_collider_ = new CircleCollider(); self_collider_->owner = this; AddEntityCollider(self_collider_); } self_collider_->pos = a8::Vec2(); self_collider_->rad = meta->i->radius(); } float Hero::GetRadius() { return meta->i->radius(); } float Hero::GetHitRadius() { return meta->i->hit_radius(); } void Hero::GetAabbBox(AabbCollider& aabb_box) { if (!meta) { abort(); } aabb_box.active = true; aabb_box.owner = this; aabb_box._min.x = -GetRadius(); aabb_box._min.y = -GetRadius(); aabb_box._max.x = GetRadius(); aabb_box._max.y = GetRadius(); } void Hero::GetHitAabbBox(AabbCollider& aabb_box) { if (!meta) { abort(); } aabb_box.active = true; aabb_box.owner = this; aabb_box._min.x = -GetHitRadius(); aabb_box._min.y = -GetHitRadius(); aabb_box._max.x = GetHitRadius(); aabb_box._max.y = GetHitRadius(); } void Hero::DetachFromMaster() { if (!detached_) { if (master.Get()) { master.Get()->SlaveOnRemove(this); } detached_ = true; } } void Hero::DecHP(float dec_hp, int killer_id, const std::string& killer_name, int weapon_id) { if (dec_hp < 0.001f) { return; } float old_health = GetHP(); float new_health = std::max(0.0f, GetHP() - dec_hp); SetHP(std::max(0.0f, new_health)); if (GetHP() <= 0.0001f && !IsDead(room)) { BeKill(killer_id, killer_name, weapon_id); } room->frame_event.AddHpChg(GetWeakPtrRef()); } void Hero::BeKill(int killer_id, const std::string& killer_name, int weapon_id) { dead = true; if (meta->i->dead_drop() != 0) { room->ScatterDrop(GetPos(), meta->i->dead_drop()); } room->frame_event.AddDead(GetWeakPtrRef(), 0); room->xtimer.AddDeadLineTimerAndAttach ( meta->i->delay_delete() / FRAME_RATE_MS, a8::XParams() .SetSender(this), [] (const a8::XParams& param) { Hero* hero = (Hero*)param.sender.GetUserData(); hero->BroadcastDeleteState(hero->room); hero->RemoveFromAroundPlayers(hero->room); hero->room->grid_service->RemoveCreature(hero); hero->room->RemoveObjectLater(hero); hero->delete_frameno = hero->room->GetFrameNo(); std::vector watch_list; hero->room->GetPartObjectWatchList(hero, watch_list); if (!watch_list.empty()) { abort(); } }, &xtimer_attacher.timer_list_); } void Hero::OnAddToTargetPartObject(Entity* target) { if (delete_frameno > 0) { abort(); } } void Hero::OnRemoveFromTargetPartObject(Entity* target) { } void Hero::InitAI() { MetaData::AI* ai_meta = MetaMgr::Instance()->GetHeroAI(meta->i->ai()); if (!ai_meta) { #ifdef DEBUG abort(); #endif ai_meta = MetaMgr::Instance()->GetHeroAI(ANDROID_AI_ID_START); } if (!ai_meta) { abort(); } if (ai_meta->i->ai_kind() == kAI_MineSweeper) { ai = new MineSweeperAI; ai->ai_meta = ai_meta; } else { ai = new HeroAI; ai->ai_meta = ai_meta; } ai->owner = this; int buff_uniid = MustBeAddBuff(this, kPeaceModeBuffId ); if (buff_uniid) { Buff* buff = GetBuffByUniId(buff_uniid); if (buff) { int peace_time = 1000 * 6; if (ai->ai_meta->i->peace_time() > 0) { peace_time += ai->ai_meta->i->peace_time(); } room->xtimer.ModifyTimer(buff->remover_timer, peace_time / FRAME_RATE_MS); } } }