void CameraDirector::SetViewObjectGroup(ListIter<Ship> group, bool quick) { if (!ship) return; Starshatter* stars = Starshatter::GetInstance(); if (!stars->InCutscene()) { // only view solid contacts: while (++group) { Ship* s = group.value(); if (s->GetIFF() != ship->GetIFF()) { Contact* c = ship->FindContact(s); if (!c || !c->ActLock()) return; } if (s->Life() == 0 || s->IsDying() || s->IsDead()) return; } } group.reset(); if (external_group.size() > 1 && external_group.size() == group.size()) { bool same = true; for (int i = 0; same && i < external_group.size(); i++) { if (external_group[i] != group.container()[i]) same = false; } if (same) { SetMode(MODE_ZOOM); return; } } ClearGroup(); if (quick) { mode = MODE_ORBIT; transition = 0; } else { SetMode(MODE_TRANSLATE); } external_group.append(group.container()); ListIter<Ship> iter = external_group; while (++iter) { Ship* s = iter.value(); region = s->GetRegion(); Observe(s); } }
GroundAI::GroundAI(SimObject* s) : ship((Ship*) s), target(0), subtarget(0), exec_time(0), carrier_ai(0) { Sim* sim = Sim::GetSim(); Ship* pship = sim->GetPlayerShip(); int player_team = 1; int ai_level = 1; if (pship) player_team = pship->GetIFF(); Player* player = Player::GetCurrentPlayer(); if (player) { if (ship && ship->GetIFF() && ship->GetIFF() != player_team) { ai_level = player->AILevel(); } else if (player->AILevel() == 0) { ai_level = 1; } } // evil alien ships are *always* smart: if (ship && ship->GetIFF() > 1 && ship->Design()->auto_roll > 1) { ai_level = 2; } if (ship && ship->GetHangar() && ship->GetCommandAILevel() > 0) carrier_ai = new(__FILE__,__LINE__) CarrierAI(ship, ai_level); }
void RadioTraffic::SendMessage(RadioMessage* msg) { if (!msg) return; Sim* sim = Sim::GetSim(); Ship* player = sim->GetPlayerShip(); int iff = 0; if (player) iff = player->GetIFF(); if (msg->DestinationShip()) { traffic.append(msg); if (msg->Channel() == 0 || msg->Channel() == iff) DisplayMessage(msg); if (!NetGame::IsNetGameClient()) msg->DestinationShip()->HandleRadioMessage(msg); } else if (msg->DestinationElem()) { traffic.append(msg); if (msg->Channel() == 0 || msg->Channel() == iff) DisplayMessage(msg); if (!NetGame::IsNetGameClient()) msg->DestinationElem()->HandleRadioMessage(msg); } else { if (msg->Channel() == 0 || msg->Channel() == iff) DisplayMessage(msg); delete msg; } }
void TacticalAI::CheckTarget() { SimObject* tgt = ship_ai->GetTarget(); if (!tgt) return; if (tgt->GetRegion() != ship->GetRegion()) { ship_ai->DropTarget(); return; } if (tgt->Type() == SimObject::SIM_SHIP) { Ship* target = (Ship*) tgt; // has the target joined our side? if (target->GetIFF() == ship->GetIFF() && !target->IsRogue()) { ship_ai->DropTarget(); return; } // is the target already jumping/breaking/dying? if (target->InTransition()) { ship_ai->DropTarget(); return; } // have we been ordered to pursue the target? if (directed_tgtid) { if (directed_tgtid != target->Identity()) { ship_ai->DropTarget(); } return; } // can we catch the target? if (target->Design()->vlimit <= ship->Design()->vlimit || ship->Velocity().length() <= ship->Design()->vlimit) return; // is the target now out of range? WeaponDesign* wep_dsn = ship->GetPrimaryDesign(); if (!wep_dsn) return; // compute the "give up" range: double drop_range = 3 * wep_dsn->max_range; if (drop_range > 0.75 * ship->Design()->commit_range) drop_range = 0.75 * ship->Design()->commit_range; double range = Point(target->Location() - ship->Location()).length(); if (range < drop_range) return; // is the target closing or separating? Point delta = (target->Location() + target->Velocity()) - (ship->Location() + ship->Velocity()); if (delta.length() < range) return; ship_ai->DropTarget(); } else if (tgt->Type() == SimObject::SIM_DRONE) { Drone* drone = (Drone*) tgt; // is the target still a threat? if (drone->GetEta() < 1 || drone->GetTarget() == 0) ship_ai->DropTarget(); } }
void MissionEvent::Execute(bool silent) { Starshatter* stars = Starshatter::GetInstance(); HUDView* hud = HUDView::GetInstance(); Sim* sim = Sim::GetSim(); Ship* player = sim->GetPlayerShip(); Ship* ship = 0; Ship* src = 0; Ship* tgt = 0; Element* elem = 0; int pan = 0; bool end_mission = false; if (event_ship.length()) ship = sim->FindShip(event_ship); else ship = player; if (event_source.length()) src = sim->FindShip(event_source); if (event_target.length()) tgt = sim->FindShip(event_target); if (ship) elem = ship->GetElement(); else if (event_ship.length()) { elem = sim->FindElement(event_ship); if (elem) ship = elem->GetShip(1); } // expire the delay, if any remains delay = 0; // fire the event action switch (event) { case MESSAGE: if (event_message.length() > 0) { if (ship) { RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(ship, src, event_param[0]); msg->SetInfo(event_message); msg->SetChannel(ship->GetIFF()); if (tgt) msg->AddTarget(tgt); RadioTraffic::Transmit(msg); } else if (elem) { RadioMessage* msg = new(__FILE__,__LINE__) RadioMessage(elem, src, event_param[0]); msg->SetInfo(event_message); msg->SetChannel(elem->GetIFF()); if (tgt) msg->AddTarget(tgt); RadioTraffic::Transmit(msg); } } if (event_sound.length() > 0) { pan = event_param[0]; } break; case OBJECTIVE: if (elem) { if (event_param[0]) { elem->ClearInstructions(); elem->ClearObjectives(); } Instruction* obj = new(__FILE__,__LINE__) Instruction(event_param[0], 0); obj->SetTarget(event_target); elem->AddObjective(obj); if (elem->Contains(player)) { HUDView* hud = HUDView::GetInstance(); if (hud) hud->ShowHUDInst(); } } break; case INSTRUCTION: if (elem) { if (event_param[0]) elem->ClearInstructions(); elem->AddInstruction(event_message); if (elem->Contains(player) && event_message.length() > 0) { HUDView* hud = HUDView::GetInstance(); if (hud) hud->ShowHUDInst(); } } break; case IFF: if (elem) { elem->SetIFF(event_param[0]); } else if (ship) { ship->SetIFF(event_param[0]); } break; case DAMAGE: if (ship) { ship->InflictDamage(event_param[0]); if (ship->Integrity() < 1) { NetUtil::SendObjKill(ship, 0, NetObjKill::KILL_MISC); ship->DeathSpiral(); Print(" %s Killed By Scripted Event %d (%s)\n", (const char*) ship->Name(), id, FormatGameTime()); } } else { Print(" EVENT %d: Could not apply damage to ship '%s' (not found).\n", id, (const char*) event_ship); } break; case JUMP: if (ship) { SimRegion* rgn = sim->FindRegion(event_target); if (rgn && ship->GetRegion() != rgn) { if (rgn->IsOrbital()) { QuantumDrive* quantum_drive = ship->GetQuantumDrive(); if (quantum_drive) { quantum_drive->SetDestination(rgn, Point(0,0,0)); quantum_drive->Engage(true); // request immediate jump } else if (ship->IsAirborne()) { ship->MakeOrbit(); } } else { ship->DropOrbit(); } } } break; case HOLD: if (elem) elem->SetHoldTime(event_param[0]); break; case SKIP: { for (int i = 0; i < event_nparams; i++) { int skip_id = event_param[i]; ListIter<MissionEvent> iter = sim->GetEvents(); while (++iter) { MissionEvent* e = iter.value(); if (e->EventID() == skip_id) { if (e->status != COMPLETE) e->status = SKIPPED; } } } } break; case END_MISSION: Print(" END MISSION By Scripted Event %d (%s)\n", id, FormatGameTime()); end_mission = true; break; // // NOTE: CUTSCENE EVENTS DO NOT APPLY IN MULTIPLAYER // case BEGIN_SCENE: Print(" ------------------------------------\n"); Print(" Begin Cutscene '%s'\n", event_message.data()); stars->BeginCutscene(); break; case END_SCENE: Print(" End Cutscene '%s'\n", event_message.data()); Print(" ------------------------------------\n"); stars->EndCutscene(); break; case CAMERA: if (stars->InCutscene()) { CameraDirector* cam_dir = CameraDirector::GetInstance(); if (!cam_dir->GetShip()) cam_dir->SetShip(player); switch (event_param[0]) { case 1: if (cam_dir->GetMode() != CameraDirector::MODE_COCKPIT) cam_dir->SetMode(CameraDirector::MODE_COCKPIT, event_rect.x); break; case 2: if (cam_dir->GetMode() != CameraDirector::MODE_CHASE) cam_dir->SetMode(CameraDirector::MODE_CHASE, event_rect.x); break; case 3: if (cam_dir->GetMode() != CameraDirector::MODE_ORBIT) cam_dir->SetMode(CameraDirector::MODE_ORBIT, event_rect.x); break; case 4: if (cam_dir->GetMode() != CameraDirector::MODE_TARGET) cam_dir->SetMode(CameraDirector::MODE_TARGET, event_rect.x); break; } if (event_target.length()) { ::Print("Mission Event %d: setting camera target to %s\n", id, (const char*) event_target); Ship* s_tgt = 0; if (event_target.indexOf("body:") < 0) s_tgt = sim->FindShip(event_target); if (s_tgt) { ::Print(" found ship %s\n", s_tgt->Name()); cam_dir->SetViewOrbital(0); if (cam_dir->GetViewObject() != s_tgt) { if (event_param[0] == 6) { s_tgt->DropCam(event_param[1], event_param[2]); cam_dir->SetShip(s_tgt); cam_dir->SetMode(CameraDirector::MODE_DROP, 0); } else { Ship* cam_ship = cam_dir->GetShip(); if (cam_ship && cam_ship->IsDropCam()) { cam_ship->CompleteTransition(); } if (cam_dir->GetShip() != sim->GetPlayerShip()) cam_dir->SetShip(sim->GetPlayerShip()); cam_dir->SetViewObject(s_tgt, true); // immediate, no transition } } } else { const char* body_name = event_target.data(); if (!strncmp(body_name, "body:", 5)) body_name += 5; Orbital* orb = sim->FindOrbitalBody(body_name); if (orb) { ::Print(" found body %s\n", orb->Name()); cam_dir->SetViewOrbital(orb); } } } if (event_param[0] == 3) { cam_dir->SetOrbitPoint(event_point.x, event_point.y, event_point.z); } else if (event_param[0] == 5) { cam_dir->SetOrbitRates(event_point.x, event_point.y, event_point.z); } } break; case VOLUME: if (stars->InCutscene()) { AudioConfig* audio_cfg = AudioConfig::GetInstance(); audio_cfg->SetEfxVolume(event_param[0]); audio_cfg->SetWrnVolume(event_param[0]); } break; case DISPLAY: if (stars->InCutscene()) { DisplayView* disp_view = DisplayView::GetInstance(); if (disp_view) { Color color; color.Set(event_param[0]); if (event_message.length() && event_source.length()) { if (event_message.contains('$')) { Campaign* campaign = Campaign::GetCampaign(); Player* user = Player::GetCurrentPlayer(); CombatGroup* group = campaign->GetPlayerGroup(); if (user) { event_message = FormatTextReplace(event_message, "$NAME", user->Name().data()); event_message = FormatTextReplace(event_message, "$RANK", Player::RankName(user->Rank())); } if (group) { event_message = FormatTextReplace(event_message, "$GROUP", group->GetDescription()); } if (event_message.contains("$TIME")) { char timestr[32]; FormatDayTime(timestr, campaign->GetTime(), true); event_message = FormatTextReplace(event_message, "$TIME", timestr); } } disp_view->AddText( event_message, FontMgr::Find(event_source), color, event_rect, event_point.y, event_point.x, event_point.z); } else if (event_target.length()) { DataLoader* loader = DataLoader::GetLoader(); if (loader) { loader->SetDataPath(0); loader->LoadBitmap(event_target, image, 0, true); } if (image.Width() && image.Height()) disp_view->AddImage( &image, color, Video::BLEND_ALPHA, event_rect, event_point.y, event_point.x, event_point.z); } } } break; case FIRE_WEAPON: if (ship) { // fire single weapon: if (event_param[0] >= 0) { ship->FireWeapon(event_param[0]); } // fire all weapons: else { ListIter<WeaponGroup> g_iter = ship->Weapons(); while (++g_iter) { ListIter<Weapon> w_iter = g_iter->GetWeapons(); while (++w_iter) { Weapon* w = w_iter.value(); w->Fire(); } } } } break; default: break; } sim->ProcessEventTrigger(TRIGGER_EVENT, id); if (!silent && !sound && event_sound.length()) { DataLoader* loader = DataLoader::GetLoader(); bool use_fs = loader->IsFileSystemEnabled(); DWORD flags = pan ? Sound::LOCKED|Sound::LOCALIZED : Sound::LOCKED|Sound::AMBIENT; loader->UseFileSystem(true); loader->SetDataPath("Sounds/"); loader->LoadSound(event_sound, sound, flags); loader->SetDataPath(0); if (!sound) { loader->SetDataPath("Mods/Sounds/"); loader->LoadSound(event_sound, sound, flags); loader->SetDataPath(0); } if (!sound) { loader->LoadSound(event_sound, sound, flags); } loader->UseFileSystem(use_fs); // fire and forget: if (sound) { if (sound->GetFlags() & Sound::STREAMED) { sound->SetFlags(flags | sound->GetFlags()); sound->SetVolume(AudioConfig::VoxVolume()); sound->Play(); } else { sound->SetFlags(flags); sound->SetVolume(AudioConfig::VoxVolume()); sound->SetPan(pan); sound->SetFilename(event_sound); sound->AddToSoundCard(); sound->Play(); } } } status = COMPLETE; if (end_mission) { StarServer* server = StarServer::GetInstance(); if (stars) { stars->EndMission(); } else if (server) { // end mission event uses event_target member // to forward server to next mission in the chain: if (event_target.length()) server->SetNextMission(event_target); server->SetGameMode(StarServer::MENU_MODE); } } }
bool MissionEvent::CheckTrigger() { Sim* sim = Sim::GetSim(); if (time > 0 && time > sim->MissionClock()) return false; switch (trigger) { case TRIGGER_TIME: { if (time <= sim->MissionClock()) Activate(); } break; case TRIGGER_DAMAGE: { Ship* ship = sim->FindShip(trigger_ship); if (ship) { double damage = 100.0 * (ship->Design()->integrity - ship->Integrity()) / (ship->Design()->integrity); if (damage >= trigger_param[0]) Activate(); } } break; case TRIGGER_DETECT: { Ship* ship = sim->FindShip(trigger_ship); Ship* tgt = sim->FindShip(trigger_target); if (ship && tgt) { if (ship->FindContact(tgt)) Activate(); } else { Skip(); } } break; case TRIGGER_RANGE: { Ship* ship = sim->FindShip(trigger_ship); Ship* tgt = sim->FindShip(trigger_target); if (ship && tgt) { double range = (ship->Location() - tgt->Location()).length(); double min_range = 0; double max_range = 1e12; if (trigger_param[0] > 0) min_range = trigger_param[0]; else max_range = -trigger_param[0]; if (range < min_range || range > max_range) Activate(); } else { Skip(); } } break; case TRIGGER_SHIPS_LEFT: { int alive = 0; int count = 0; int iff = -1; int nparams = NumTriggerParams(); if (nparams > 0) count = TriggerParam(0); if (nparams > 1) iff = TriggerParam(1); ListIter<SimRegion> iter = sim->GetRegions(); while (++iter) { SimRegion* rgn = iter.value(); ListIter<Ship> s_iter = rgn->Ships(); while (++s_iter) { Ship* ship = s_iter.value(); if (ship->Type() >= Ship::STATION) continue; if (ship->Life() == 0 && ship->RespawnCount() < 1) continue; if (iff < 0 || ship->GetIFF() == iff) alive++; } } if (alive <= count) Activate(); } break; case TRIGGER_EVENT_ALL: { bool all = true; int nparams = NumTriggerParams(); for (int i = 0; all && i < nparams; i++) { int trigger_id = TriggerParam(i); ListIter<MissionEvent> iter = sim->GetEvents(); while (++iter) { MissionEvent* e = iter.value(); if (e->EventID() == trigger_id) { if (e->Status() != COMPLETE) all = false; break; } else if (e->EventID() == -trigger_id) { if (e->Status() == COMPLETE) all = false; break; } } } if (all) Activate(); } break; case TRIGGER_EVENT_ANY: { bool any = false; int nparams = NumTriggerParams(); for (int i = 0; !any && i < nparams; i++) { int trigger_id = TriggerParam(i); ListIter<MissionEvent> iter = sim->GetEvents(); while (++iter) { MissionEvent* e = iter.value(); if (e->EventID() == trigger_id) { if (e->Status() == COMPLETE) any = true; break; } } } if (any) Activate(); } break; } return status == ACTIVE; }
void NetGameClient::DoObjKill(NetMsg* msg) { if (!msg) return; NetObjKill obj_kill; obj_kill.Unpack(msg->Data()); Ship* ship = FindShipByObjID(obj_kill.GetObjID()); if (ship) { Ship* killer = FindShipByObjID(obj_kill.GetKillerID()); Text killer_name = Game::GetText("NetGameClient.unknown"); if (killer) killer_name = killer->Name(); // log the kill: switch (obj_kill.GetKillType()) { default: case NetObjKill::KILL_MISC: Print("Ship '%s' destroyed (misc) (%s)\n", ship->Name(), FormatGameTime()); break; case NetObjKill::KILL_PRIMARY: case NetObjKill::KILL_SECONDARY: Print("Ship '%s' killed by '%s' (%s)\n", ship->Name(), killer_name.data(), FormatGameTime()); break; case NetObjKill::KILL_COLLISION: Print("Ship '%s' killed in collision with '%s' (%s)\n", ship->Name(), killer_name.data(), FormatGameTime()); break; case NetObjKill::KILL_CRASH: Print("Ship '%s' destroyed (crash) (%s)\n", ship->Name(), FormatGameTime()); case NetObjKill::KILL_DOCK: Print("Ship '%s' docked (%s)\n", ship->Name(), FormatGameTime()); } // record the kill in the stats: if (killer && obj_kill.GetKillType() != NetObjKill::KILL_DOCK) { ShipStats* kstats = ShipStats::Find(killer->Name()); if (kstats) { if (obj_kill.GetKillType() == NetObjKill::KILL_PRIMARY) kstats->AddEvent(SimEvent::GUNS_KILL, ship->Name()); else if (obj_kill.GetKillType() == NetObjKill::KILL_SECONDARY) kstats->AddEvent(SimEvent::MISSILE_KILL, ship->Name()); } if (killer && killer->GetIFF() != ship->GetIFF()) { if (ship->GetIFF() > 0 || killer->GetIFF() > 1) kstats->AddPoints(ship->Value()); } } ShipStats* killee = ShipStats::Find(ship->Name()); if (killee) { if (obj_kill.GetKillType() == NetObjKill::KILL_DOCK) killee->AddEvent(SimEvent::DOCK, killer_name); else killee->AddEvent(SimEvent::DESTROYED, killer_name); } if (obj_kill.GetKillType() == NetObjKill::KILL_DOCK) { FlightDeck* deck = killer->GetFlightDeck(obj_kill.GetFlightDeck()); sim->NetDockShip(ship, killer, deck); } else { ship->InflictNetDamage(ship->Integrity()); ship->DeathSpiral(); if (!obj_kill.GetRespawn()) ship->SetRespawnCount(0); else ship->SetRespawnLoc(obj_kill.GetRespawnLoc()); } } // this shouldn't happen in practice, // but if it does, this is what should be done: else { Shot* shot = FindShotByObjID(obj_kill.GetObjID()); if (shot) { ::Print("NetGameClient::DoObjKill destroying shot '%s'\n", shot->Name()); shot->Destroy(); } } }