Beispiel #1
0
/**
**  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;
}
Beispiel #2
0
/**
**  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);
}
Beispiel #3
0
/**
**  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);
}
Beispiel #4
0
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);
}
Beispiel #5
0
/**
**  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;
}
Beispiel #6
0
void AnimationDie_OnCatch(CUnit &unit)
{
	LetUnitDie(unit);
}
Beispiel #7
0
/**
**  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;
}
Beispiel #8
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;
    }
}