/* base/npc.cc This file is part of the Osirion project and is distributed under the terms of the GNU General Public License version 2 */ #include "base/npc.h" #include "base/game.h" #include "base/patrol.h" namespace game { // NPC Wingman factory function NPC *NPC::add_wingman(Ship *leader) { if (!leader) { return 0; } if (leader->state() != Entity::Normal) { return 0; } NPC *npc = new NPC(ProfileWingman, leader->shipmodel()); npc->set_leader(leader); //npc->set_owner(leader->owner()); npc->set_name("Wingman"); npc->set_mood(MoodFormation); npc->set_color(npc->leader()->color()); npc->set_color_second(npc->leader()->color_second()); npc->set_location(leader->location() - leader->axis().forward() * 2.0f * (leader->radius() + npc->radius())); npc->set_axis(leader->axis()); npc->set_zone(leader->zone()); // copy weapon layout if (!npc->inventory()) { npc->add_inventory(); } // TODO ship models should be identical, otherwise the slot loeading can fail in horrible ways assert (npc->shipmodel() == leader->shipmodel()); for (size_t i = 0; i < leader->slots()->size(); ++i) { core::Slot *slot = leader->slots()->operator[](i); if (!slot->has_flag(core::Slot::Mounted) && slot->item()) { continue; } core::Item *npc_item = new core::Item(slot->item()->info()); npc_item->set_amount(slot->item()->amount()); npc_item->set_flags(slot->item()->flags()); npc_item->set_flag(core::Item::Mounted); npc->inventory()->add(npc_item); core::Slot *npc_slot = npc->slots()->operator[](i); npc_slot->set_item(npc_item); npc_slot->set_flag(core::Slot::Active); npc_slot->set_flag(core::Slot::Mounted); } npc->reset(); return npc; } NPC::NPC(const Profile profile, const ShipModel *shipmodel) : Ship(0, shipmodel) { npc_profile = profile; npc_mood = MoodWander; npc_destroyed_timestamp = 0; npc_patrol = 0; npc_leader = 0; } void NPC::set_mood(const Mood mood) { npc_mood = mood; } void NPC::set_leader(Ship *leader) { npc_leader = leader; } void NPC::set_patrol(Patrol *patrol) { npc_patrol = patrol; } void NPC::frame(const unsigned long elapsed) { if (state() == core::Entity::Destroyed) { if (!npc_destroyed_timestamp) { npc_destroyed_timestamp = core::game()->time(); } else if (npc_destroyed_timestamp + 10.0f < core::game()->time()) { // stay alive for 10 more seconds while explosion particles are drawn die(); } } else { // TODO pilot magic and mood witchcraft if (leader()) { // verify leader still exists if (!core::Entity::find(leader())) { set_leader(0); explode(); npc_destroyed_timestamp = core::game()->time(); } else if (leader()->zone() == zone()) { // leader is in this zone if (leader()->state() == Docked) { if (state() != core::Entity::Docked) { set_autopilot_target(leader()->dock()); set_autopilot_flag(Ship::AutoPilotEnabled); set_autopilot_flag(Ship::AutoPilotDock); unset_autopilot_flag(Ship::AutoPilotFormation); } else { unset_autopilot_flag(Ship::AutoPilotEnabled); } } else if ((leader()->state() == JumpInitiate) || (leader()->state() == Jump)) { // goto wherever the leader is jumping set_autopilot_target(leader()->jumpdepart()); set_autopilot_flag(Ship::AutoPilotEnabled); set_autopilot_flag(Ship::AutoPilotDock); unset_autopilot_flag(Ship::AutoPilotFormation); } else { if (state() == core::Entity::Docked) { // FIXME check launch conditions when docked at another player's ship launch(); } else { set_autopilot_target(leader()); set_autopilot_flag(Ship::AutoPilotEnabled); unset_autopilot_flag(Ship::AutoPilotDock); set_autopilot_flag(Ship::AutoPilotFormation); /* if (leader()->has_target_controlflag(core::EntityControlable::ControlFlagFire)) { set_target_controlflag(core::EntityControlable::ControlFlagFire); target_aim.assign(leader()->aim()); } else { unset_target_controlflag(core::EntityControlable::ControlFlagFire); } */ } } } else { // leader is not in this zone if (!autopilot_target()) { target_direction = 0; target_pitch = 0; target_roll = 0; target_strafe = 0.0f; target_vstrafe = 0.0f; target_afterburner = 0.0f; target_thrust = 0; if (state() == core::Entity::Impulse) { func_impulse(); } } else { set_autopilot_flag(Ship::AutoPilotEnabled); set_autopilot_flag(Ship::AutoPilotDock); unset_autopilot_flag(Ship::AutoPilotFormation); } } } } // run a ship game frame Ship::frame(elapsed); } } // namespace game