/** ** Kill a unit ** ** @param l Lua state. ** ** @return Returns true if a unit was killed. */ static int CclKillUnit(lua_State *l) { LuaCheckArgs(l, 2); lua_pushvalue(l, 1); const CUnitType *unittype = TriggerGetUnitType(l); lua_pop(l, 1); const int plynr = TriggerGetPlayer(l); if (plynr == -1) { CUnitManager::Iterator it = std::find_if(UnitManager.begin(), UnitManager.end(), HasSameUnitTypeAs(unittype)); if (it != UnitManager.end()) { LetUnitDie(**it); lua_pushboolean(l, 1); return 1; } } else { CPlayer &player = Players[plynr]; std::vector<CUnit *>::iterator it = std::find_if(player.UnitBegin(), player.UnitEnd(), HasSameUnitTypeAs(unittype)); if (it != player.UnitEnd()) { LetUnitDie(**it); lua_pushboolean(l, 1); return 1; } } lua_pushboolean(l, 0); return 1; }
/** ** Cancel the building construction, or kill a unit. ** ** @param unit pointer to unit. */ void CommandDismiss(CUnit &unit) { // Check if building is still under construction? (NETWORK!) if (unit.CurrentAction() == UnitActionBuilt) { unit.CurrentOrder()->Cancel(unit); } else { DebugPrint("Suicide unit ... \n"); LetUnitDie(unit, true); } ClearSavedAction(unit); }
/** ** Cancel the building construction, or kill an unit. ** ** @param unit pointer to unit. */ void CommandDismiss(CUnit *unit) { // // Check if building is still under construction? (NETWORK!) // if (unit->Orders[0]->Action == UnitActionBuilt) { unit->Data.Built.Cancel = 1; } else { DebugPrint("Suicide unit ... \n"); LetUnitDie(unit); } ClearSavedAction(unit); }
static void CancelBuilt(COrder_Built &order, CUnit &unit) { Assert(unit.CurrentOrder() == &order); CUnit *worker = order.GetWorkerPtr(); // Drop out unit if (worker != NULL) { worker->ClearAction(); DropOutOnSide(*worker, LookingW, &unit); } // Player gets back 75% of the original cost for a building. unit.Player->AddCostsFactor(unit.Stats->Costs, CancelBuildingCostsFactor); // Cancel building LetUnitDie(unit); }
/** ** Kill a unit at a location ** ** @param l Lua state. ** ** @return Returns the number of units killed. */ static int CclKillUnitAt(lua_State *l) { LuaCheckArgs(l, 5); lua_pushvalue(l, 1); const CUnitType *unittype = TriggerGetUnitType(l); lua_pop(l, 1); lua_pushvalue(l, 2); int plynr = TriggerGetPlayer(l); lua_pop(l, 1); int q = LuaToNumber(l, 3); if (!lua_istable(l, 4) || !lua_istable(l, 5)) { LuaError(l, "incorrect argument"); } Vec2i pos1; Vec2i pos2; CclGetPos(l, &pos1.x, &pos1.y, 4); CclGetPos(l, &pos2.x, &pos2.y, 5); std::vector<CUnit *> table; Select(pos1, pos2, table); int s = 0; for (std::vector<CUnit *>::iterator it = table.begin(); it != table.end() && s < q; ++it) { CUnit &unit = **it; if (unittype == ANY_UNIT || (unittype == ALL_FOODUNITS && !unit.Type->Building) || (unittype == ALL_BUILDINGS && unit.Type->Building) || unittype == unit.Type) { if ((plynr == -1 || plynr == unit.Player->Index) && unit.IsAlive()) { LetUnitDie(unit); ++s; } } } lua_pushnumber(l, s); return 1; }
void AnimationDie_OnCatch(CUnit &unit) { LetUnitDie(unit); }
/** ** Gather the resource ** ** @param unit Pointer to unit. ** ** @return non-zero if ready, otherwise zero. */ int COrder_Resource::GatherResource(CUnit &unit) { CUnit *source = 0; const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource]; int addload; //Wyrmgus start bool harvest_from_outside = (this->GetGoal() && this->GetGoal()->Type->BoolFlag[HARVESTFROMOUTSIDE_INDEX].value); // if (resinfo.HarvestFromOutside || resinfo.TerrainHarvester) { if (harvest_from_outside || Map.Info.IsPointOnMap(this->goalPos)) { //Wyrmgus end AnimateActionHarvest(unit); } else { unit.Anim.CurrAnim = NULL; } this->TimeToHarvest--; if (this->DoneHarvesting) { //Wyrmgus start // Assert(resinfo.HarvestFromOutside || resinfo.TerrainHarvester); Assert(harvest_from_outside || Map.Info.IsPointOnMap(this->goalPos)); //Wyrmgus end return !unit.Anim.Unbreakable; } // Target gone? //Wyrmgus start // if (resinfo.TerrainHarvester && !Map.Field(this->goalPos)->IsTerrainResourceOnMap(this->CurrentResource)) { if (Map.Info.IsPointOnMap(this->goalPos) && !Map.Field(this->goalPos)->IsTerrainResourceOnMap(this->CurrentResource)) { //Wyrmgus end if (!unit.Anim.Unbreakable) { // Action now breakable, move to resource again. this->State = SUB_MOVE_TO_RESOURCE; // Give it some reasonable look while searching. // FIXME: which frame? unit.Frame = 0; } return 0; // No wood? Freeze!!! } while (!this->DoneHarvesting && this->TimeToHarvest < 0) { //FIXME: rb - how should it look for WaitAtResource == 0 if (resinfo.WaitAtResource) { // Wyrmgus start // this->TimeToHarvest += std::max<int>(1, resinfo.WaitAtResource * SPEEDUP_FACTOR / unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]); int wait_at_resource = resinfo.WaitAtResource; int resource_harvest_speed = unit.Player->SpeedResourcesHarvest[resinfo.ResourceId]; if (!Map.Info.IsPointOnMap(this->goalPos) && !harvest_from_outside) { wait_at_resource = resinfo.WaitAtResource * 100 / resinfo.ResourceStep; } if (this->GetGoal()) { resource_harvest_speed += this->GetGoal()->Variable[TIMEEFFICIENCYBONUS_INDEX].Value; } this->TimeToHarvest += std::max<int>(1, wait_at_resource * SPEEDUP_FACTOR / resource_harvest_speed); //Wyrmgus end } else { this->TimeToHarvest += 1; } // Calculate how much we can load. //Wyrmgus start // if (resinfo.ResourceStep) { if (resinfo.ResourceStep && (harvest_from_outside || Map.Info.IsPointOnMap(this->goalPos))) { //Wyrmgus end addload = resinfo.ResourceStep; } else { addload = resinfo.ResourceCapacity; } // Make sure we don't bite more than we can chew. if (unit.ResourcesHeld + addload > resinfo.ResourceCapacity) { addload = resinfo.ResourceCapacity - unit.ResourcesHeld; } //Wyrmgus start // if (resinfo.TerrainHarvester) { if (Map.Info.IsPointOnMap(this->goalPos)) { //Wyrmgus end //Wyrmgus start CMapField &mf = *Map.Field(this->goalPos); if (addload > mf.Value) { addload = mf.Value; } mf.Value -= addload; //Wyrmgus end unit.ResourcesHeld += addload; //Wyrmgus start // if (addload && unit.ResourcesHeld == resinfo.ResourceCapacity) { if (mf.Value <= 0) { //Wyrmgus end //Wyrmgus start // Map.ClearWoodTile(this->goalPos); if (this->CurrentResource == WoodCost) { Map.ClearWoodTile(this->goalPos); } else if (this->CurrentResource == StoneCost) { Map.ClearRockTile(this->goalPos); } //Wyrmgus end } } else { //Wyrmgus start // if (resinfo.HarvestFromOutside) { if (harvest_from_outside) { //Wyrmgus end source = this->GetGoal(); } else { source = unit.Container; } Assert(source); Assert(source->ResourcesHeld <= 655350); //Wyrmgus start UpdateUnitVariables(*source); //update resource source's variables //Wyrmgus end bool is_visible = source->IsVisibleAsGoal(*unit.Player); // Target is not dead, getting resources. if (is_visible) { // Don't load more that there is. addload = std::min(source->ResourcesHeld, addload); unit.ResourcesHeld += addload; source->ResourcesHeld -= addload; } // End of resource: destroy the resource. // FIXME: implement depleted resources. if ((!is_visible) || (source->ResourcesHeld == 0)) { if (unit.Anim.Unbreakable) { return 0; } DebugPrint("%d: Worker %d report: Resource is destroyed\n" _C_ unit.Player->Index _C_ UnitNumber(unit)); bool dead = source->IsAlive() == false; // Improved version of DropOutAll that makes workers go to the depot. LoseResource(unit, *source); for (CUnit *uins = source->Resource.Workers; uins; uins = uins->NextWorker) { if (uins != &unit && uins->CurrentOrder()->Action == UnitActionResource) { COrder_Resource &order = *static_cast<COrder_Resource *>(uins->CurrentOrder()); if (!uins->Anim.Unbreakable && order.State == SUB_GATHER_RESOURCE) { order.LoseResource(*uins, *source); } } } // Don't destroy the resource twice. // This only happens when it's empty. if (!dead) { if (Preference.MineNotifications && unit.Player->Index == ThisPlayer->Index //Wyrmgus start // && source->Variable[GIVERESOURCE_INDEX].Max > DefaultIncomes[this->CurrentResource]) { && source->Variable[GIVERESOURCE_INDEX].Max > (DefaultIncomes[this->CurrentResource] * 10)) { //Wyrmgus end //Wyrmgus start // unit.Player->Notify(NotifyYellow, source->tilePos, _("%s has collapsed!"), source->Type->Name.c_str()); unit.Player->Notify(NotifyYellow, source->tilePos, _("Our %s has been depleted!"), source->Type->Name.c_str()); //Wyrmgus end } LetUnitDie(*source); // FIXME: make the workers inside look for a new resource. } source = NULL; return 0; } } //Wyrmgus start // if (resinfo.TerrainHarvester) { if (Map.Info.IsPointOnMap(this->goalPos)) { //Wyrmgus end if (unit.ResourcesHeld == resinfo.ResourceCapacity) { // Mark as complete. this->DoneHarvesting = true; } return 0; } else { //Wyrmgus start // if (resinfo.HarvestFromOutside) { if (harvest_from_outside) { //Wyrmgus end if ((unit.ResourcesHeld == resinfo.ResourceCapacity) || (source == NULL)) { // Mark as complete. this->DoneHarvesting = true; } return 0; } else { return unit.ResourcesHeld == resinfo.ResourceCapacity && source; } } } return 0; }
static void Finish(COrder_Built &order, CUnit &unit) { const CUnitType &type = *unit.Type; CPlayer &player = *unit.Player; DebugPrint("%d: Building %s(%s) ready.\n" _C_ player.Index _C_ type.Ident.c_str() _C_ type.Name.c_str()); // HACK: the building is ready now player.UnitTypesCount[type.Slot]++; if (unit.Active) { player.UnitTypesAiActiveCount[type.Slot]++; } unit.Constructed = 0; if (unit.Frame < 0) { unit.Frame = -1; } else { unit.Frame = 0; } CUnit *worker = order.GetWorkerPtr(); if (worker != NULL) { if (type.BoolFlag[BUILDERLOST_INDEX].value) { // Bye bye worker. LetUnitDie(*worker); worker = NULL; } else { // Drop out the worker. worker->ClearAction(); DropOutOnSide(*worker, LookingW, &unit); // If we can harvest from the new building, do it. if (worker->Type->ResInfo[type.GivesResource]) { CommandResource(*worker, unit, 0); } // If we can reurn goods to a new depot, do it. if (worker->CurrentResource && worker->ResourcesHeld > 0 && type.CanStore[worker->CurrentResource]) { CommandReturnGoods(*worker, &unit, 0); } } } if (type.GivesResource && type.StartingResources != 0) { // Has StartingResources, Use those unit.ResourcesHeld = type.StartingResources; } player.Notify(NotifyGreen, unit.tilePos, _("New %s done"), type.Name.c_str()); if (&player == ThisPlayer) { if (type.MapSound.Ready.Sound) { PlayUnitSound(unit, VoiceReady); } else if (worker) { PlayUnitSound(*worker, VoiceWorkCompleted); } else { PlayUnitSound(unit, VoiceBuilding); } } if (player.AiEnabled) { /* Worker can be NULL */ AiWorkComplete(worker, unit); } // FIXME: Vladi: this is just a hack to test wall fixing, // FIXME: also not sure if the right place... // FIXME: Johns: hardcoded unit-type wall / more races! if (&type == UnitTypeOrcWall || &type == UnitTypeHumanWall) { Map.SetWall(unit.tilePos, &type == UnitTypeHumanWall); unit.Remove(NULL); UnitLost(unit); UnitClearOrders(unit); unit.Release(); return ; } UpdateForNewUnit(unit, 0); // Set the direction of the building if it supports them if (type.NumDirections > 1 && type.BoolFlag[NORANDOMPLACING_INDEX].value == false) { if (type.BoolFlag[WALL_INDEX].value) { // Special logic for walls CorrectWallDirections(unit); CorrectWallNeighBours(unit); } else { unit.Direction = (MyRand() >> 8) & 0xFF; // random heading } UnitUpdateHeading(unit); } if (IsOnlySelected(unit) || &player == ThisPlayer) { SelectedUnitChanged(); } MapUnmarkUnitSight(unit); unit.CurrentSightRange = unit.Stats->Variables[SIGHTRANGE_INDEX].Max; MapMarkUnitSight(unit); order.Finished = true; }
/** ** Unit Demolishs ** ** @param unit Unit, for that the demolish is handled. */ global void HandleActionDemolish(Unit* unit) { Unit* table[UnitMax]; int i; int n; int xmin, ymin, xmax, ymax; int ix, iy; Unit* goal; int err; DebugLevel3Fn("Demolish %d\n" _C_ UnitNumber(unit)); switch( unit->SubAction ) { // // Move near to target. // case 0: // first entry. NewResetPath(unit); unit->SubAction=1; // FALL THROUGH case 1: // FIXME: reset first!! why? (johns) err=DoActionMove(unit); if( unit->Reset ) { goal=unit->Orders[0].Goal; // // Target is dead, stop demolish. // FIXME: what should I do, go back or explode on place? // if( goal ) { if( goal->Destroyed ) { DebugLevel0Fn("Destroyed unit\n"); RefsDebugCheck( !goal->Refs ); if( !--goal->Refs ) { ReleaseUnit(goal); } // FIXME: perhaps I should choose an alternative unit->Orders[0].Goal=NoUnitP; unit->Orders[0].Action=UnitActionStill; unit->SubAction=0; return; } else if( goal->Removed || !goal->HP || goal->Orders[0].Action==UnitActionDie ) { RefsDebugCheck( !goal->Refs ); --goal->Refs; RefsDebugCheck( !goal->Refs ); unit->Orders[0].Goal=NoUnitP; // FIXME: perhaps I should choose an alternative unit->Orders[0].Action=UnitActionStill; unit->SubAction=0; return; } } // // Have reached target? FIXME: could use pathfinder result? // if( goal ) { if( MapDistanceToUnit(unit->X,unit->Y,goal)<=1 ) { unit->State=0; unit->SubAction=2; } } else if( MapDistance(unit->X,unit->Y ,unit->Orders[0].X,unit->Orders[0].Y)<=1 ) { unit->State=0; unit->SubAction=2; } else if( err==PF_UNREACHABLE ) { unit->Orders[0].Action=UnitActionStill; return; } DebugCheck( unit->Orders[0].Action!=UnitActionDemolish ); } break; // // Demolish the target. // case 2: goal=unit->Orders[0].Goal; if( goal ) { RefsDebugCheck( !goal->Refs ); --goal->Refs; RefsDebugCheck( !goal->Refs ); unit->Orders[0].Goal=NoUnitP; } xmin = unit->X - 2; ymin = unit->Y - 2; xmax = unit->X + 2; ymax = unit->Y + 2; if (xmin<0) xmin=0; if (xmax > TheMap.Width-1) xmax = TheMap.Width-1; if (ymin<0) ymin=0; if (ymax > TheMap.Height-1) ymax = TheMap.Height-1; // FIXME: Must play explosion sound // FIXME: Currently we take the X fields, the original only the O // XXXXX ..O.. // XXXXX .OOO. // XX.XX OO.OO // XXXXX .OOO. // XXXXX ..O.. // // // Effect of the explosion on units. // n=SelectUnits(xmin,ymin, xmax, ymax,table); for( i=0; i<n; ++i ) { if( table[i]->Type->UnitType!=UnitTypeFly && table[i]->HP && table[i] != unit ) { // Don't hit flying units! HitUnit(unit,table[i],DEMOLISH_DAMAGE); } } // // Terrain effect of the explosion // for( ix=xmin; ix<=xmax; ix++ ) { for( iy=ymin; iy<=ymax; iy++ ) { n=TheMap.Fields[ix+iy*TheMap.Width].Flags; if( n&MapFieldWall ) { MapRemoveWall(ix,iy); } else if( n&MapFieldRocks ) { MapRemoveRock(ix,iy); } else if( n&MapFieldForest ) { MapRemoveWood(ix,iy); } } } LetUnitDie(unit); #ifdef HIERARCHIC_PATHFINDER PfHierMapChangedCallback (xmin, ymin, xmax, ymax); #endif break; } }