// // Execute // U32 Turn::Execute(const U8 *data, Player &player) { const Data *d = (Data *) data; // Send the move order to all of the selected objects for (UnitObjList::Iterator i(&player.GetSelectedList()); *i; i++) { UnitObj *unit = **i; // Calculate desired front vector Vector v(d->x - unit->Position().x, 0, d->z - unit->Position().z); v.Normalize(); // Can the unit move if (unit->CanEverMove()) { if (!unit->GetDriver()->IsBoarded()) { // Convert the given task Id into a move type Tasks::UnitMove *task = new Tasks::UnitMove(unit); task->SetDir(v); IssueTask(d->mod, unit, task, player); } } } return (sizeof (Data)); }
// // TagCondition::TagTest // Bool TagCondition::TagTest(Team *team) { ASSERT(tag) U32 count = 0; // Test the Objects in Tag to see if there is enough of them on this team if (tag->tag.Alive()) { // Purge dead objects out of the list tag->tag->list.PurgeDead(); for (MapObjList::Iterator o(&tag->tag->list); *o; o++) { MapObj *obj = **o; UnitObj *unitObj = Promote::Object<UnitObjType, UnitObj>(obj); UnitObj *parentObj = obj->GetParent() ? Promote::Object<UnitObjType, UnitObj>(obj->GetParent()) : NULL; if ( unitObj && (unitObj->GetActiveTeam() == team) || parentObj && (parentObj->GetActiveTeam() == team)) { count++; } } } return (tag->oper(count, tag->GetAmount())); }
// // TagInTransport::Test // Bool TagInTransport::Test(class Team *) { // Check to see if all of the tag members are inside transports if (tag->tag.Alive()) { // Purge dead objects out of the list tag->tag->list.PurgeDead(); // Count the number of tag members who are in transports U32 count = 0; if (tag->tag->list.GetCount()) { for (MapObjList::Iterator o(&tag->tag->list); *o; o++) { MapObj *obj = **o; UnitObj *unitObj = Promote::Object<UnitObjType, UnitObj>(obj); if (unitObj && unitObj->GetFlag(UnitObj::FLAG_CARGO)) { count++; } } } return (tag->oper(count, tag->GetAmount())); } return (FALSE); }
// // Apply // void ExplosionObjType::Apply(const Vector &location, UnitObj *unit, Team *team) { MapObjIter::All i(NULL, MapObjIter::FilterData(location, areaOuter)); MapObj *obj; while ((obj = i.Next()) != NULL) { // Is the object within the full damage area F32 dist2 = i.GetProximity2() - areaInner2; S32 deltaHp; //Vector dir = obj->WorldMatrix().posit - location; //dir.Normalize(); if (dist2 <= 0.0f) { // Apply the full damage to this object deltaHp = -damage.GetAmount(obj->MapType()->GetArmourClass()); obj->ModifyHitPoints(deltaHp, unit, team/*, &dir*/); } else { F32 mod = 1.0f - (dist2 * areaDiff2Inv); ASSERT(mod >= 0 && mod <= 1.0f) // Apply a proportional damage to this object //Vector v = dir * mod; deltaHp = -(S32) (((F32) damage.GetAmount(obj->MapType()->GetArmourClass())) * mod); obj->ModifyHitPoints(deltaHp, unit, team/*, &v*/); } // Apply hit modifiers if (ArmourClass::Lookup(damage.GetDamageId(), obj->MapType()->GetArmourClass())) { damage.GetModifiers().Apply(obj); // Set blind target time if (blindTargetTime) { UnitObj *unitObj = Promote::Object<UnitObjType, UnitObj>(obj); if (unitObj) { unitObj->FlushTasks(); unitObj->StartBlindTarget(blindTargetTime); } } // Apply the generic effect StartGenericFX(obj, 0x32FBA304); // "ExplosionObj::ApplyTarget" } // Is there an action to execute if (action && team) { Action::Execute(team, action); } } }
// // Assign constructors to this base // void Base::AssignConstructors(const char *tagName) { processTokens = TRUE; // Was a tag specified ? if (tagName) { // Resolve the tag TagObj *tag = TagObj::FindTag(tagName); if (tag) { // Iterate the units in the tag for (MapObjList::Iterator i(&tag->list); *i; i++) { // Is it alive if (!(*i)->Alive()) { continue; } // Is this a unit ? UnitObj *unit = Promote::Object<UnitObjType, UnitObj>(**i); if (!unit) { continue; } // Is it on our team ? if (unit->GetTeam() != GetObject().GetTeam()) { continue; } // Is it a constructor ? if (!unit->HasProperty(0xDCDE71CD)) // "Ability::Construction" { continue; } // LOG_AI(("Assigning constructor [%d] '%s' to base '%s'", unit->Id(), unit->UnitType()->GetName(), GetName())) // Add this constructor to the list of idle constructors constructorsIdle.Append(unit); } } else { ERR_CONFIG(("Could not find tag '%s' when assign constructors to base '%s'", tagName, GetName())) } } else { // Iterate all of the units on this team for (NList<UnitObj>::Iterator u(&GetObject().GetTeam()->GetUnitObjects()); *u; u++)
// // Data constructor // Objects::Data::Data(MapObj *o) : object(o) { type = object->MapType(); matrix = object->WorldMatrix(); zipped = object->GetFootInstance() ? TRUE : FALSE; UnitObj *unit = Promote::Object<UnitObjType, UnitObj>(object); if (unit) { team = unit->GetTeam(); } }
// // Apply // void Tag::Apply() { MapObjList list; list.AppendList((const MapObjList &) script.GetSquad()->GetList()); if (clear) { // Go through all of the tags and remove any units which are in the squad for (NBinTree<TagObj>::Iterator t(&TagObj::allTags); *t; t++) { // Iterate the objects in this tag MapObjList::Iterator m(&(*t)->list); while (MapObjListNode *node = m++) { UnitObj *unit; // Is this a unit if ( node->Alive() && (unit = Promote::Object<UnitObjType, UnitObj>(*node)) != NULL ) { // If this unit is in our squad, remove it if (unit->GetSquad() == script.GetSquad()) { (*t)->list.Unlink(node); } } } } } if (append) { // Is there an existing tag with this name ? TagObj *tag = TagObj::FindTag(tagName.GetStr()); if (tag) { // Append the units in the tag to the list list.AppendList(tag->list); } } TagObj::CreateTag(tagName.GetStr(), list); list.Clear(); }
// // Execute // U32 SelfDestruct::Execute(const U8 *, Player &player) { // Tell each object to SelfDestruct for (UnitObjList::Iterator i(&player.GetSelectedList()); *i; i++) { // Get the unit UnitObj *unit = **i; // Ensure it can self destruct if (unit->HasProperty(0x54D4152A) && !unit->UnderConstruction()) // "Ability::SelfDestruct" { unit->SelfDestruct(TRUE, unit->GetTeam()); } } return (sizeof (Data)); }
// // Submit asset requests directly to the manager // Bool Asset::Request::TypeBase::DirectEvaluation(Manager &manager) { // Iterate the units in the base an evaluate them if (base.Alive()) { for (UnitObjList::Iterator u(&base->GetUnits()); *u; u++) { if ((*u)->Alive()) { UnitObj *unit = **u; manager.Evaluation(*this, *unit, config->GetAmounts().Find(unit->GameType()->Id()) ? 1.0f : 0.0f); } } } return (TRUE); }
// // Offer // // The given asset is being offered, do we want it ? // Bool Asset::Request::TypeBase::Offer(Asset &asset) { // Get the unit out of the asset UnitObj *unit = asset.GetUnit(); ASSERT(unit) // Do we have enough of this type ? U32 type = unit->GameType()->Id(); // We should only be offered this type if we asked for it ASSERT(config->GetAmount(type)) // How many of this type do we currently have ? U32 *amount = amounts.Find(type); // Is this less that what we need ? return ((!amount || *amount < config->GetAmount(type)) ? TRUE : FALSE); }
// // Execute // U32 Store::Execute(const U8 *data, Player &player) { const Data *d = (Data *) data; // Create an iterator for (UnitObjList::Iterator i(&player.GetSelectedList()); *i; i++) { // Get the unit UnitObj *unit = **i; // Is this a collector ? if (Tasks::UnitCollect *task = TaskCtrl::PromoteIdle<Tasks::UnitCollect>(unit)) { // Should we search for a place to store the resource if (d->search) { task->Store(); } else { // Convert ID into a pointer if (UnitObj *storeObj = Resolver::Object<UnitObj, UnitObjType>(d->object)) { // If not updating the position, flush tasks incase moving or something if (!d->update && unit->GetActiveTask()) { unit->FlushTasks(); } // Tell this task about the new storage point task->SetStorageObject(storeObj, d->update); } } } } return (sizeof (Data)); }
// // Initial state // void MapDeath::StateInit() { // Stop the objects driver UnitObj *unitObj = Promote::Object<UnitObjType, UnitObj>(subject); if (unitObj) { if (unitObj->GetWeapon()) { unitObj->GetWeapon()->HaltFire(); } if (unitObj->CanEverMove()) { unitObj->GetDriver()->Stop(Movement::Driver::STOP_DYING); } } // Play the death animation subject->SetAnimation(0xF40D135F); // "Death" NextState(0x382D3C63); // "Dead" }
// // RenderSpecialized // // Display specialized unit information // static void RenderSpecialized() { // Is there a unit under the cursor UnitObj *over = data.cInfo.gameWnd.Alive() ? data.cInfo.o.unit.GetPointer() : NULL; // Can we see this units special info if (over && Team::TestDisplayRelation(over, Relation::ALLY)) { over->RenderSpecialized(); } // Now display for all selected units for (UnitObjList::Iterator i(&data.sList); *i; ++i) { if (UnitObj *u = (*i)->GetPointer()) { if (u != over) { u->RenderSpecialized(); } } } }
// // Execute // U32 PowerDown::Execute(const U8 *data, Player &player) { const Data *d = (Data *) data; // Are we powering down or up if (d->down) { // Check each selected object for (UnitObjList::Iterator i(&player.GetSelectedList()); *i; i++) { UnitObj *subject = **i; // Can this unit power down ? if (subject->UnitType()->GetPower().GetRequired()) { IssueTask(FLUSH, subject, new Tasks::UnitPowerDown(subject), player); } } } else { // Check each selected object for (UnitObjList::Iterator i(&player.GetSelectedList()); *i; i++) { UnitObj *subject = **i; // Is this unit powered down ? if (Tasks::UnitPowerDown *task = TaskCtrl::Promote<Tasks::UnitPowerDown>(subject)) { task->ProcessEvent(Task::Event(0x57BE223A)); // "PowerUp" } } } return (sizeof (Data)); }
// // StateInit // void SquadBoard::StateInit() { // Get each of the units in the squad to board transports SquadObj::UnitList::Iterator u(&subject->GetList()); // We could enhance this to use units which are closest to transports etc. // Clear the squad's completed flags for (!u; *u; u++) { (*u)->completed = FALSE; (*u)->task = 0; } // Reset squad iterator !u; for (TransportObjList::Iterator t(&transports); *t; t++) { if ((*t)->Alive()) { TransportObj *transport = **t; U32 slots = transport->TransportType()->GetSpaces(); U32 added = 0; while (slots--) { UnitObjPtr *unitPtr = *u; if (unitPtr) { ASSERT(unitPtr->Alive()) UnitObj *unit = *unitPtr; if (unit->CanEverMove()) { // Tell the unit to board unit->FlushTasks(Tasks::UnitBoard::GetConfigBlockingPriority()); Task *task; // Is this a telepad if (TaskCtrl::PromoteIdle<Tasks::TransportPad>(transport)) { unit->PrependTask(task = new Tasks::UnitMove(unit, transport), GetFlags()); } else { unit->PrependTask(task = new Tasks::UnitBoard(unit, transport), GetFlags()); } (*u)->task = task->GetTaskId(); added++; } else { // This unit can't move so complete it (*u)->completed = TRUE; } } else { break; } // Increment iterator u++; } if (!added) { // No units were added break; } } } // Complete those units which missed out for (; *u; u++) { (*u)->completed = TRUE; } NextState(0x09E5F977); // "Boarding" }
// // RenderRallyPoint // // Display a rally point // static void RenderRallyPoint() { Point<S32> srcPoint(0, 0); Point<U32> dstPoint(0, 0); Matrix src, dst; // Get the single selected unit UnitObj *unit = data.cInfo.oneUnit.GetPointer(); // Is there a rally point if (unit && unit->GetFootInstance() && unit->GetRallyPoint(dstPoint)) { // Setup destination dst.ClearData(); dst.posit.x = WorldCtrl::CellToMetresX(dstPoint.x); dst.posit.z = WorldCtrl::CellToMetresZ(dstPoint.z); dst.posit.y = TerrainData::FindFloorWithWater(dst.posit.x, dst.posit.z); // Find the source srcPoint.Set(S32(dstPoint.x), S32(dstPoint.z)); unit->GetFootInstance()->ClampToFringe(srcPoint); src.ClearData(); src.posit.x = WorldCtrl::CellToMetresX(srcPoint.x); src.posit.z = WorldCtrl::CellToMetresZ(srcPoint.z); src.posit.y = TerrainData::FindFloorWithWater(src.posit.x, src.posit.z); } else { // Act as if not selected unit = NULL; } if ( // Rally unit has been deselected (!unit && rallyUnitId) || ( // Have a rally point unit unit && ( // Different to last one (unit->Id() != rallyUnitId) || // Rally point location has changed (rallyUnitId && (dstPoint != rallyPoint)) ) ) ) { // Dispose of any current particle if (rallyParticle.Alive()) { delete rallyParticle; } // Is there a unit selected if (unit) { // Never display a trail when same point if ((srcPoint.x != S32(dstPoint.x)) || (srcPoint.z != S32(dstPoint.z))) { // Create the runner particle if (ParticleClass *p = ParticleSystem::FindType(0x94E362BD)) // "Client::Rally" { Matrix m(src); m.posit.y += 3.0F; Vector v(0.0f, 0.0f, 0.0f); rallyParticle = ParticleSystem::New(p, m, v, v, dst.posit - src.posit, 0.0F); } } // Remember this unit's info rallyUnitId = unit->Id(); rallyPoint = dstPoint; } else { rallyUnitId = 0; } } // Render the start and end points if (unit) { Common::Display::Mesh(0x693D5359, src, Color(0.0F, 0.8F, 0.0F, 0.7F)); // "Location" Common::Display::Mesh(0x693D5359, dst, Color(0.0F, 1.0F, 0.0F, 0.7F)); // "Location" } }
// // Initial state // void SquadMoveTogether::StateInit() { LOG_DIAG(("SquadMoveTogether: Init")) // Find the slowest unit in the squad and use their traction type U8 traction = 0; F32 bottomSpeed = F32_MAX; // Work out the centre position of the squad Vector location(0.0f, 0.0f, 0.0f); U32 count = 0; SquadObj::UnitList::Iterator i(&subject->GetList()); for (!i; *i; i++) { if ((*i)->Alive()) { // Take this oportunity to reset the units node (*i)->completed = TRUE; (*i)->data = 0; if ((**i)->CanEverMove()) { // Grab the unit so we don't need to continually pound the iterator UnitObj *unit = **i; // Flush its tasks unit->FlushTasks(Tasks::UnitMove::GetConfigBlockingPriority()); // Add its position to the total location.x += unit->WorldMatrix().posit.x; location.z += unit->WorldMatrix().posit.z; count++; // Is this the slowest unit in the squad F32 speed = unit->GetMaxSpeed(); if (speed < bottomSpeed) { bottomSpeed = speed; traction = unit->MapType()->GetTractionIndex(unit->MapType()->GetDefaultLayer()); } } } } if (!count) { Quit(); return; } // Work out the averate location location.x /= count; location.z /= count; location.y = TerrainData::FindFloor(location.x, location.z); // What is the direction from the source (location) to the dest (destination) VectorDir dir; Vector(destination - location).Convert(dir); direction = dir.u; // Build a formation from the units using the direction to the destination Formation::Create(location, direction, subject, 16.0f); // Get the source and destination in terms of cells Point<F32> avg(location.x, location.z); Point<U32> srcCell; WorldCtrl::MetresToCellPoint(avg, srcCell); Point<U32> destCell; WorldCtrl::MetresToCellPoint(Point<F32>(destination.x, destination.z), destCell); switch (subject->GetPathFinder().RequestPath(srcCell.x, srcCell.z, destCell.x, destCell.z, traction)) { case PathSearch::Finder::RR_SUBMITTED: NextState(0xFDE9D5E3); // "Pathing" break; case PathSearch::Finder::RR_SAMECELL: case PathSearch::Finder::RR_OFFMAP: Quit(); return; default: ERR_FATAL(("Unknown path request result")) } }
// // Recycle // // Check timer and refund resources once recycled // void UnitRecycle::StateRecycle() { // Apply progress progressTotal -= progressMax; // Has recycling finished if (progressTotal <= 0.0F) { // Refund the resources if (subject->GetTeam() && refund > 0) { // Calculate the total refund U32 totalRefund = U32(subject->UnitType()->GetRecyclePercentage() * refund); // Add to the team subject->GetTeam()->AddResourceStore(totalRefund); // Report the resource type subject->GetTeam()->ReportResource(totalRefund, "resource.recycled"); // Generate a message if (Team::GetDisplayTeam() == subject->GetTeam()) { CON_MSG((TRANSLATE(("#game.messages.recyclerefund", 2, subject->GetUpgradedUnit().GetDesc(), totalRefund)))); } } // Trigger finish FX subject->StartGenericFX(0x2062BAAD, NULL, TRUE); // "Recycle::Finish" // Did this building consume its constructor if ( subject->UnitType()->GetConstructorType() && !subject->UnitType()->GetConstructorType()->GetIsFacility() && subject->UnitType()->GetConstructorConsume() ) { // Ensure the constructors resources are initialized subject->UnitType()->GetConstructorType()->InitializeResources(); // Create a fresh new constructor UnitObj *unit = subject->UnitType()->GetConstructorType()->SpawnClosest ( subject->Position(), subject->GetTeam() ); // If this team is controlled by AI then assign the // constructor to the primary base (if there is one) if (unit && unit->GetTeam() && unit->GetTeam()->IsAI()) { Strategic::Object *object = unit->GetTeam()->GetStrategicObject(); if (object) { Strategic::Base *base = object->GetBaseManager().GetPrimaryBase(); if (base) { base->AddUnit(unit); base->AddConstructor(unit); } } } } // Remove the object subject->MarkForDeletion(); // Remove boarded object if (subject->UnitType()->CanBoard() && subject->GetBoardManager()->InUse()) { subject->GetBoardManager()->GetUnitObj()->SelfDestruct(); } // Recycle completed Quit(); } }
// // Undo // // Undo operation // void Objects::Undo() { // Process each object for (NList<Data>::Iterator i(&dataList); *i; i++) { Data *d = *i; switch (op) { // Delete objects that were created case OP_CREATE: if (d->object.Alive()) { GameObjCtrl::MarkForDeletion(d->object); } break; // Create objects that were deleted case OP_DELETE: { MapObj *m = MapObjCtrl::ObjectNewOnMap(d->type, d->matrix, 0, d->zipped); // Restore zipping if (d->zipped) { m->ToggleFootPrint(TRUE); } // Is this a unit UnitObj *u = Promote::Object<UnitObjType, UnitObj>(m); // Restore correct team if (u && d->team) { u->SetTeam(d->team); } // Save the old id U32 oldId = d->object.DirectId(); // Now replace all references to the old object with the new object for (NList<Base>::Iterator items(&GetHistoryList()); *items; items++) { Objects *item = Promote<Objects>(*items); if (item) { for (NList<Data>::Iterator data(&item->dataList); *data; data++) { if ((*data)->object.DirectId() == oldId) { (*data)->object = m; } } } } break; } // Move objects back to original location case OP_MOVE: if (d->object.Alive()) { d->object->SetSimCurrent(d->matrix); // Toggle claiming if necessary UnitObj *unitObj = Promote::Object<UnitObjType, UnitObj>(d->object); if (unitObj && unitObj->CanEverMove()) { unitObj->GetDriver()->RemoveFromMapHook(); unitObj->GetDriver()->AddToMapHook(); } } break; // Restore zipped state case OP_ZIP: if (d->object.Alive()) { d->object->ToggleFootPrint(d->zipped); } break; } } }
// // GoToNextPoint // void SquadMoveTogether::GoToNextPoint(SquadObj::ListNode *node) { // We are attempting to go to the next point NPoint *p = points[node->data]; node->data++; node->completed = TRUE; point = Max(point, node->data); ASSERT(node->Alive()) UnitObj *unit = node->GetData(); if (p) { // Mark the time a unit attempts to move to this point if (p->timestamp) { // The squad will need to wait for me to catch up if (GameTime::SimCycle() - p->timestamp > timeDiffMax) { // LOG_DIAG(("Detected that we're [%d] way behind at this point, changing to waiting state", node->Id())) NextState(0xCC45C48B); // "Waiting" } } else { p->timestamp = GameTime::SimCycle(); // Since we're the first unit to this point we // should check to make sure that no units are // more than two points behind. If there are, // then we'll have to wait here for them SquadObj::UnitList::Iterator i(&subject->GetList()); for (!i; *i; i++) { if ( (*i)->Alive() && ((*i)->data + pointDiffMax < point) ) { // LOG_DIAG(("We're [%d] first to this point [%d] and detected that [%d] is way behind", node->Id(), node->data, (*i)->Id())) NextState(0xCC45C48B); // "Waiting" return; } } } // Find the closest point to that point that we can go to U32 x, z; // Use the formation slot offset for this unit Vector location(WorldCtrl::CellToMetresX(p->x), 0.0f, WorldCtrl::CellToMetresZ(p->z)); F32 dir = p->direction + node->slot.direction; VectorDir::FixU(dir); F32 orient = p->direction + node->slot.orientation; VectorDir::FixU(orient); Vector offset; offset.x = (F32) cos(dir); offset.y = 0.0f; offset.z = (F32) sin(dir); offset *= node->slot.distance; offset += location; // Make sure the point is on the map WorldCtrl::ClampMetreMap(offset.x, offset.z); x = WorldCtrl::MetresToCellX(offset.x); z = WorldCtrl::MetresToCellZ(offset.z); if (PathSearch::FindClosestCell(unit->MapType()->GetTractionIndex(unit->MapType()->GetDefaultLayer()), x, z, x, z, meetingRange)) { node->completed = FALSE; unit->PrependTask(new Tasks::UnitMove(unit, offset)); } else { // Cound not find a cell, go to the next point GoToNextPoint(node); } } }
// // Poll // // Attempt to trigger this trap // Bool TrapObj::Poll() { // Did we find a valid target Bool valid = FALSE; // Has recharging finished if (recharge.Test()) { UnitObj *target; // Find an enemy within the configured range UnitObjIter::Tactical i ( NULL, UnitObjIter::FilterData(GetTeam(), Relation::ENEMY, Position(), TrapType()->GetDistance()) ); // Step through each possible target while ((target = i.Next()) != NULL) { // Can this trap trigger on this target if (TrapType()->Test(target)) { // Does this trap self destruct if (TrapType()->GetSelfDestruct()) { SelfDestruct(TRUE, GetTeam()); valid = TRUE; } // Does this trap attach a parasite if (TrapType()->GetParasite() && TrapType()->GetParasite()->Infect(target, GetTeam())) { valid = TRUE; } // Should we fire a weapon if (TrapType()->GetWeaponSpeed() > 0.0F) { if (GetWeapon()) { Vector pos = Origin(); pos.y += 20.0f; GetWeapon()->SetTarget(Target(pos)); valid = TRUE; } else { LOG_WARN(("Trap %s configured to fire a weapon, but has none!", TypeName())); } } if (valid) { // Signal team radio that we were triggered if (GetTeam()) { // "Trap::Triggered" GetTeam()->GetRadio().Trigger(0xA0FF29A5, Radio::Event(this)); } // Signal the target that it has been trapped if (target->GetTeam()) { // "Trap::Triggered::Target" target->GetTeam()->GetRadio().Trigger(0x3070E869, Radio::Event(target)); } // Start charge time recharge.Start(TrapType()->GetChargeTime()); } // Only affect one target for now break; } } } return (valid); }