123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847 |
- #include "pch.h"
- /*-------------------------------------------------------------------------
- * Function: Drone::Drone
- *-------------------------------------------------------------------------
- * Purpose:
- * Does nothing accept initialize all of the drone variables
- */
- Drone::Drone(IshipIGC* id, DroneType dt) :
- m_pShip(id),
- m_goal(NULL),
- m_goalMemory(0,0),
- bVerbose(false),
- dType(dt),
- m_fDie(false),
- m_fDisappear(false),
- m_flShootSkill(0.0f),
- m_flMoveSkill(0.0f),
- m_flBravery(0.0f),
- m_pStation(NULL),
- m_index(g_drones.GetIndex())
- {}
- /*-------------------------------------------------------------------------
- * Function: Drone::Update
- *-------------------------------------------------------------------------
- * Purpose:
- * Update the ship controls....
- * Start by checking the instincts, then check the current goal. If that goal is
- * not done yet, then run that goal. Otherwise try to find a goal for next time
- * using DetermineGoal()
- */
- void Drone::Update(Time now, float dt)
- {
- if (m_pShip->GetStation()) // undock immediately
- {
- m_pShip->SetStation(NULL);
- }
-
- assert (m_pShip->GetCluster() != NULL);
- Instincts(); // Check some things EVERY round
- if (m_goal && m_goal->Done())
- {
- m_goal->DoneEvent(); // Mostly for done messages
- delete m_goal;
- m_goal = NULL;
- }
- if (!m_goal)
- {
- DetermineGoal();
- }
- if (m_goal)
- {
- m_goal->Update(now, dt); // The goal is not done, update the controls using that goal
- }
- else
- {
- //No goal ... well, do nothing
- m_pShip->SetStateM(now, 0);
- ControlData cd;
- cd.Reset();
- m_pShip->SetControls(cd);
- }
- if (m_fDie == true) // This has to be the last thing in the update cycle
- {
- //Self-destruct ... but first nuke parts, fuel & ammo
- {
- PartLinkIGC* ppl;
- while (ppl = m_pShip->GetParts()->first()) //intentional assignement
- {
- ppl->data()->Terminate();
- }
- }
- m_pShip->SetAmmo(0);
- m_pShip->SetFuel(0.0f);
- m_pShip->GetMission()->GetIgcSite()->KillShipEvent(now, m_pShip, NULL, 0.0f, m_pShip->GetPosition(), Vector::GetZero());
- }
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::SetShip
- *-------------------------------------------------------------------------
- * Purpose:
- * If I have to update the ship, I also have to update the goals which save the
- * ship seperately
- */
- void Drone::SetShip(IshipIGC* ship)
- {
- assert(ship);
- m_pShip = ship;
- // Kind of a pain, but I have to make sure that the goals are using the correct ship, too
- if (m_goal)
- m_goal->m_pShip = ship;
- for (int i=m_goalMemory.GetCount(); i>0; i--)
- {
- m_goalMemory[i-1]->m_pShip = ship;
- }
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::Message
- *-------------------------------------------------------------------------
- * Purpose:
- * Most commands end up using SetGoal(command), but there are a few exceptions
- * to that rule. Catch those exceptions here.
- */
- bool
- Drone::Message(Time now, CommandID cm, ImodelIGC* pmodelObject)
- {
- if (!m_pShip->AcceptsCommandF(cm)) // Make sure that this drone can do this command
- {
- SendChat(droneCantDoThatSound, "I can't do that, you must have the wrong drone");
- return false;
- }
- const CommandData& cmdata = m_pShip->GetMission()->GetCommand(cm);
- if (pmodelObject) // Make sure that the target is appropriate for that command
- {
- if (!cmdata.LegalObject(pmodelObject->GetObjectType()))
- {
- SendChat(droneCantDoThatSound, "I can't do that to %s", GetModelName(pmodelObject));
- return false;
- }
- if (pmodelObject == m_pShip) {
- SendChat(droneCantDoThatSound, "I can't do that to myself...");
- return false;
- }
- }
- else if (cmdata.otmLegal != 0)
- {
- SendChat(droneCantDoThatSound, "I can't do that to nothing");
- return false;
- }
- CommandType ct = (CommandType) cm;
-
- if (ct == c_ctNoCommand) // Cut out the junk commands
- {
- SendChat(droneCantDoThatSound, "I don't understand...");
- return false;
- }
- else if (ct == c_ctStatus) // Get the status
- Status();
- else if (ct == c_ctHome) // Set the home station
- {
- if (pmodelObject && pmodelObject->GetObjectType() == OT_station)
- SetStation(pmodelObject);
- else SendChat(droneCantDoThatSound, "That's not a station!");
- }
- else if (ct == c_ctVerbose) // Toggle verbose
- {
- ToggleVerbose();
- if (bVerbose)
- Status();
- }
- else if (ct == c_ctSDestruct) // Self Destruct
- {
- Die();
- }
- else if (ct == c_ctPop) // Pop a goal
- {
- if (m_goal)
- {
- delete m_goal;
- m_goal = NULL;
- }
- DetermineGoal();
- }
- else // It is a command associated with a goal.
- { // Clear the current goals and do this order
- ClearGoals();
- SetGoal(ct, pmodelObject, true);
- }
- return true;
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::SendChat
- *-------------------------------------------------------------------------
- * Purpose:
- * A wrapper on the GameSite::DroneSendChat function
- */
- void
- Drone::SendChat(SoundID soundID, const char* format, ...)
- {
- char szChat[256]; // $CRC: sync this with client
- va_list vl;
- va_start(vl, format);
- int cbChat = wvsprintfA(szChat, format, vl);
- assert(cbChat < sizeof(szChat));
- va_end(vl);
- m_pShip->GetMission()->GetIgcSite()->DroneSendChat(m_pShip, szChat, CHAT_TEAM, m_pShip, soundID);
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::Verbose
- *-------------------------------------------------------------------------
- * Purpose:
- * A wrapper on the m_pShip->GetMission()->GetIgcSite()->DroneSendChat function, but only send the chat
- * if verbose mode is on.
- */
- void Drone::Verbose(const char* format, ...)
- {
- if (!bVerbose)
- return;
- char szChat[256]; // $CRC: sync this with client
- va_list vl;
- va_start(vl, format);
- int cbChat = wvsprintfA(szChat, format, vl);
- assert(cbChat < sizeof(szChat));
- va_end(vl);
- m_pShip->GetMission()->GetIgcSite()->DroneSendChat(m_pShip, szChat, CHAT_TEAM, m_pShip);
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::Status
- *-------------------------------------------------------------------------
- * Purpose:
- * Send status information over the chat. Goal information and drone info, too
- */
- void Drone::Status (void)
- {
- if (m_goal)
- m_goal->Status();
- else
- SendChat(NA, "No goal information available");
- Verbose("I am in %s", m_pShip->GetCluster()->GetName());
- Verbose("Shooting skill: %d%% Moving Skill %d%% Bravery: %d%%", (int)(m_flShootSkill*100), (int)(m_flMoveSkill*100), (int)(m_flBravery*100));
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::DetermineGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Given the current goal, the goal stack, and the default goal, come up with a goal
- * for the drone
- */
- void Drone::DetermineGoal(void)
- {
- if (m_goal) // Already have a goal
- return;
-
- while (m_goalMemory.GetCount()) // Have a goal in memory, do that
- {
- RestoreGoal();
- assert(m_goal);
- if (!m_goal->Done())
- return;
- }
- SetGoal(GetNewDefaultGoal()); // No goals anywhere, use the default.
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::GetNewDefaultGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * This is meant to re-declared in the child classes. Default goal for a default
- * drone is to sit their and be dodge.
- */
- Goal* Drone::GetNewDefaultGoal(void)
- {
- Verbose("I'll just stay here and wait for an order");
- return new IdleGoal(this);
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::SetGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Given the commandtype and target, backup the current goal and set m_goal
- * appropriately. Also send a confirmation message.
- */
- void Drone::SetGoal(CommandType cm, ImodelIGC* pTarget, bool reply)
- {
- BackupGoal();
- assert(cm != c_ctNoCommand);
-
- switch(cm)
- {
- case c_ctDestroy:
- {
- if (pTarget) {
- m_goal = new DestroyGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'm going to try to destroy %s", GetModelName(pTarget));
- }
- else {
- m_goal = new KillAnythingGoal(this);
- if (reply)
- SendChat(NA, "I'm going to try to destroy any enemies that I see");
- }
- }
- break;
- case c_ctMine:
- {
- MiningDrone* pDrone = NULL;
- CastTo(pDrone, this);
- if ((pTarget->GetObjectType() == OT_asteroid) &&
- ((IasteroidIGC*)pTarget)->HasCapability(c_aabmMineHe3))
- {
- m_goal = new MineGoal(pDrone, pTarget);
- if (reply)
- {
- SendChat(droneInTransitSound, "I'm going to mine %s", GetModelName(pTarget));
- }
- }
- else
- {
- SendChat(droneCantDoThatSound, "I can't do that");
- }
- }
- break;
- case c_ctUnload:
- {
- MiningDrone* pDrone = NULL;
- CastTo(pDrone, this);
- IstationIGC* pStation;
- CastTo(pStation, pTarget);
- if (pStation)
- {
- m_goal = new UnloadGoal(pDrone, pStation);
- if (reply)
- {
- if (pStation)
- SendChat(NA, "I'm going to unload at %s", GetModelName(pStation));
- else
- SendChat(NA, "I'm going to go unload");
- }
- }
- }
- break;
- case c_ctPatrol:
- {
- if (pTarget) {
- m_goal = new PatrolGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'm going to patrol between where I am now, and %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctGoto:
- {
- if (pTarget)
- {
- //enter starbases by default, goto everything else
- m_goal = new NewGotoGoal(this, pTarget, (pTarget->GetObjectType() == OT_station) ||
- (pTarget->GetObjectType() == OT_warp)
- ? Waypoint::c_oEnter
- : Waypoint::c_oGoto);
- //m_goal = new GotoGoal(this, pTarget, true);
- if (reply)
- SendChat(NA, "I'm going to %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctPickup:
- {
- if (pTarget) {
- m_goal = new PickupGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'm going to pick up %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctDefend:
- {
- if (pTarget) {
- m_goal = new DefendGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'll defend %s to the end", GetModelName(pTarget));
- }
- }
- break;
- case c_ctStop:
- {
- m_goal = new StayPutGoal(this);
- if (reply)
- SendChat(NA, "Just hangin'");
- }
- break;
- case c_ctDisable:
- {
- if (pTarget) {
- m_goal = new DisableGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'm going to attempt to disable %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctFollow:
- {
- if (pTarget) {
- m_goal = new FollowGoal(this, pTarget);
- if (reply)
- SendChat(NA, "Following %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctScout:
- {
- m_goal = new ScoutGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'm scouting %s", (pTarget) ? GetModelName(pTarget) : m_pShip->GetCluster()->GetName());
- }
- break;
- case c_ctRepair:
- {
- if (pTarget)
- {
- m_goal = new RepairGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'm repairing");
- }
- }
- break;
- case c_ctCapture:
- {
- if (pTarget) {
- m_goal = new CaptureGoal(this, pTarget);
- if (reply)
- SendChat(NA, "Attempting to capture %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctFace:
- {
- if (pTarget)
- {
- m_goal = new FaceGoal(this, pTarget);
- if (reply)
- SendChat(NA, "I'll sit here and face %s", GetModelName(pTarget));
- }
- }
- break;
- case c_ctConstruct:
- {
- ConstructionDrone* pcd = NULL;
- CastTo(pcd, this);
- IstationTypeIGC* pst = pcd->GetBuildStationType();
- if ((pTarget->GetObjectType() == OT_asteroid) &&
- ((IasteroidIGC*)pTarget)->HasCapability(pst->GetBuildAABM()))
- {
- m_goal = new ConstructGoal(this,
- pst,
- (IasteroidIGC*)pTarget);
- if (reply)
- {
- SendChat(droneInTransitSound, "Building %s at %s", pst->GetName(), GetModelName(pTarget));
- }
- }
- else
- {
- SendChat(droneCantDoThatSound, "I can't do that");
- }
- }
- break;
- case c_ctTest:
- {
- m_goal = new TestGoal(this);
- bVerbose = true;
- if (reply)
- SendChat(NA, "Initializing test run");
- }
- break;
- }
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::SetGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Don't even have to switch on the command type, just backup and set the
- * goal
- */
- void Drone::SetGoal(Goal* goal)
- {
- if (goal) {
- BackupGoal();
- m_goal = goal;
- }
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::SetGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Take the current goal, and move it to the top of the memory stack.
- */
- void Drone::BackupGoal(void)
- {
- if (!m_goal)
- return;
- m_goalMemory.PushEnd(m_goal);
- m_goal = NULL;
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::RestoreGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Take the top of the stack, and put it as the current goal
- */
- void Drone::RestoreGoal(void)
- {
- int goalNum = m_goalMemory.GetCount();
- if (goalNum) {
- if (m_goal)
- delete m_goal;
-
- goalNum--; // the index equals the number of goals - 1
- m_goal = m_goalMemory[goalNum];
- m_goalMemory.Remove(goalNum);
- }
- else
- {
- Verbose("Tried to pop with no goals in memory");
- }
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::ClearGoals
- *-------------------------------------------------------------------------
- * Purpose:
- * Clear the current goal and the entire goal stack. Start fresh.
- */
- void Drone::ClearGoals(void)
- {
- int index = m_goalMemory.GetCount();
- while (index--)
- {
- if (m_goalMemory[index])
- delete m_goalMemory[index];
- m_goalMemory.Remove(index);
- }
- if (m_goal)
- delete m_goal;
- m_goal = NULL;
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::Instincts
- *-------------------------------------------------------------------------
- * Purpose:
- * There are certain things that I always want to check, regardless of my
- * goal. Put all of those in here.
- */
- bool Drone::Instincts(void)
- {
- if ((m_pShip->GetFraction() <= (1.0f - m_flBravery)) || (GetAmmoState(m_pShip) == c_asEmpty)) // Should I run away?
- {
- if ((dType == c_dtPirate) || (dType == c_dtBountyHunter))
- {
- if (!GetDisappear())
- {
- SendChat(NA, "It's just not worth it, I'm outta here");
- SetGoal(new DisappearGoal(this));
- return true;
- }
- }
- else
- {
- if (!m_goal || m_goal->GetType() != c_ctRepair)
- {
- // Check my entire goal history for a repair command, because I still want to be able to have sub-goals
- bool anyRepairGoals = false;
- for (int i = m_goalMemory.GetCount(); i>0; i--)
- {
- if (m_goalMemory[i-1]->GetType() == c_ctRepair)
- {
- anyRepairGoals = true;
- break;
- }
- }
-
- if (!anyRepairGoals)
- {
- IstationIGC* pstation = (IstationIGC*)(GetRepairStation());
- if (pstation)
- {
- SendChat(droneTooMuchDamageSound, "Forget this. I have to go get repaired");
- SetGoal(new RepairGoal(this, pstation));
- return true;
- }
- }
- }
- }
- }
- // When we get DamageTracking for the drones... Check to see if there is anyone that is just REALLY kicking our butts, REALLY being
- // defined in part by the bravery, and then decide to attack that person.
- return false;
- }
- /*-------------------------------------------------------------------------
- * Function: Drone::FindBestStation
- *-------------------------------------------------------------------------
- * Purpose:
- * When the drone needs to dock, this function will return the station which
- * he should dock at. It gives priority to any station that it has been
- * explicitly told.
- */
- IstationIGC* Drone::FindBestStation(bool fCheckEnemyStations)
- {
- IstationIGC* pHomeStation = m_pStation;
- // Go to my assigned station if it is in the cluster
- if (pHomeStation && m_pShip->GetCluster() == pHomeStation->GetCluster())
- return pHomeStation;
-
- // Find the closest friendly station in the cluster
- IstationIGC* pStation = (IstationIGC*) FindTarget(m_pShip,
- c_ttFriendly | c_ttStation | c_ttNearest | c_ttAnyCluster);
- return pStation;
- }
- /*-------------------------------------------------------------------------
- * Function: WingManDrone::GetNewDefaultGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Return a new default command for the drone
- */
- Goal* WingManDrone::GetNewDefaultGoal(void)
- {
- Verbose("Watching for enemy ships..");
- return new KillAnythingGoal(this);
- }
- /*-------------------------------------------------------------------------
- * Function: AutoPilotDrone::GetNewDefaultGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Return a new default command for the drone
- */
- Goal* AutoPilotDrone::GetNewDefaultGoal(void)
- {
- return new IdleGoal(this);
- }
- /*-------------------------------------------------------------------------
- * Function: PigPilotDrone::GetNewDefaultGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Return a new default command for the drone
- */
- Goal* PigPilotDrone::GetNewDefaultGoal(void)
- {
- return new IdleGoal(this);
- }
- #if 0
- void PigPilotDrone::Update(Time now, float dt)
- {
- // Do nothing until undocked
- if (m_pShip->GetStation())
- return;
- }
- #endif
- /*-------------------------------------------------------------------------
- * Function: BountyHunter::SetGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Can only take one target, once. Assert that here.
- */
- void BountyHunter::SetGoal(CommandType cm, ImodelIGC* pTarget, bool reply)
- {
- if (cm == c_ctDestroy && pTarget && pTarget->GetCluster())
- {
- if (m_pTarget)
- {
- if (reply)
- SendChat(NA, "I already have my target");
- return;
- }
- else
- {
- ClearGoals();
- if (reply)
- SendChat(NA, "As you wish, %s will be terminated", GetModelName(m_pTarget));
- m_pTarget = pTarget;
- }
- }
-
- Drone::SetGoal(cm, pTarget);
- }
- /*-------------------------------------------------------------------------
- * Function: BountyHunter::GetNewDefaultGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Return a new default command for the drone
- */
- Goal* BountyHunter::GetNewDefaultGoal(void)
- {
- if (m_pTarget) // Already got my target
- {
- if (m_pTarget->GetCluster()) // He's not dead
- {
- Verbose("Attempting to kill %s", GetModelName(m_pTarget));
- return new DestroyGoal(this, m_pTarget);
- }
- else // He is dead
- {
- Verbose("My work here is done. %s has been reduced to his component atoms", GetModelName(m_pTarget));
- return new DisappearGoal(this);
- }
- }
- else // Still waiting for a target
- {
- Verbose("Waiting for my kill command");
- return new IdleGoal(this);
- }
- }
- /*-------------------------------------------------------------------------
- * Function: Pirate::GetNewDefaultGoal
- *-------------------------------------------------------------------------
- * Purpose:
- * Return a new default command for the drone
- */
- Goal* Pirate::GetNewDefaultGoal(void)
- {
- // Look for a leader pirate in this sector
- // (aka, a pirate that is not currently just trying to follow someone else)
- // If I find one, then fly on his wing (follow)
- // If not, then I get to be the leader, and I should look for miners that I can take out
- // If I was already leaving, then I should still leave
- if (GetDisappear())
- {
- Verbose("Disappearing");
- return new DisappearGoal(this);
- }
- {
- Drone* leader = NULL;
- for (int i = 0; i < MAX_DRONES; i++)
- {
- if (leader = g_drones.m_pDroneList[i]) // This is an intentional assignment
- {
- if (leader != this && leader->GetDroneType() == c_dtPirate && leader->GetShip()->GetCluster() == m_pShip->GetCluster())
- { // Then it is another Pirate in this sector, now check his goal
- if (leader->GetGoal() && leader->GetGoal()->GetType() != c_ctMimic)
- { // Then we have our leader!
- Verbose("Following %s, he's my hero", GetModelName(leader->GetShip()));
- return new MimicGoal(this, leader);
- }
- }
- }
- }
- }
- // If I get here, then that means I get to be the leader! Let's find some trouble to get into...
- {
- Drone* target = NULL;
-
- for (int i = 0; i < MAX_DRONES; i++)
- {
- if (target = g_drones.m_pDroneList[i])
- {
- if (target != this && target->GetDroneType() == c_dtMining && target->GetShip()->GetCluster() == m_pShip->GetCluster())
- { // Then it is a Miner in this sector... that's good enough. Let's go get him
- Verbose("I'm off to kill the miners");
- return new DestroyGoal(this, target->GetShip());
- }
- }
- }
- }
-
- // If we get here, then there is really no damage that I can/should do in this sector... Disappear.
- Verbose("Disappearing");
- return new DisappearGoal(this);
- }
- void ConstructionDrone::Initialize(IstationTypeIGC* pstationtype)
- {
- m_pstationtype = pstationtype;
- SetGoal(new ConstructGoal(this, pstationtype, NULL));
- }
|