Пример #1
0
/**
**  Reappear unit on map.
**
**  @param unit  Unit to drop out.
**
**  @return      True if unit is unloaded.
**
**  @bug         FIXME: Place unit only on fields reachable from the transporter
*/
static int UnloadUnit(CUnit &transporter, CUnit &unit)
{
	const int maxRange = 1;
	Vec2i pos;

	Assert(unit.Removed);
	if (!FindUnloadPosition(transporter, unit, transporter.tilePos, maxRange, &pos)) {
		return false;
	}
	unit.Boarded = 0;
	unit.Place(pos);
	transporter.BoardCount -= unit.Type->BoardSize;
	return true;
}
Пример #2
0
/**
**  Create a unit and place it on the map
**
**  @param l  Lua state.
**
**  @return   Returns the slot number of the made unit.
*/
static int CclCreateUnit(lua_State *l)
{
	LuaCheckArgs(l, 3);

	lua_pushvalue(l, 1);
	CUnitType *unittype = CclGetUnitType(l);
	if (unittype == NULL) {
		LuaError(l, "Bad unittype");
	}
	lua_pop(l, 1);
	Vec2i ipos;
	CclGetPos(l, &ipos.x, &ipos.y, 3);

	lua_pushvalue(l, 2);
	const int playerno = TriggerGetPlayer(l);
	lua_pop(l, 1);
	if (playerno == -1) {
		printf("CreateUnit: You cannot use \"any\" in create-unit, specify a player\n");
		LuaError(l, "bad player");
		return 0;
	}
	if (Players[playerno].Type == PlayerNobody) {
		printf("CreateUnit: player %d does not exist\n", playerno);
		LuaError(l, "bad player");
		return 0;
	}
	CUnit *unit = MakeUnit(*unittype, &Players[playerno]);
	if (unit == NULL) {
		DebugPrint("Unable to allocate unit");
		return 0;
	} else {
		if (UnitCanBeAt(*unit, ipos)
			|| (unit->Type->Building && CanBuildUnitType(NULL, *unit->Type, ipos, 0))) {
			unit->Place(ipos);
		} else {
			const int heading = SyncRand() % 256;

			unit->tilePos = ipos;
			DropOutOnSide(*unit, heading, NULL);
		}
		UpdateForNewUnit(*unit, 0);

		lua_pushnumber(l, UnitNumber(*unit));
		return 1;
	}
}
Пример #3
0
/* virtual */ void CAnimation_SpawnUnit::Action(CUnit &unit, int &/*move*/, int /*scale*/) const
{
	Assert(unit.Anim.Anim == this);

	const int offX = ParseAnimInt(unit, this->offXStr.c_str());
	const int offY = ParseAnimInt(unit, this->offYStr.c_str());
	const int range = ParseAnimInt(unit, this->rangeStr.c_str());
	const int playerId = ParseAnimInt(unit, this->playerStr.c_str());
	const SpawnUnit_Flags flags = (SpawnUnit_Flags)(ParseAnimFlags(unit, this->flagsStr.c_str()));

	CPlayer &player = Players[playerId];
	const Vec2i pos(unit.tilePos.x + offX, unit.tilePos.y + offY);
	CUnitType *type = UnitTypeByIdent(this->unitTypeStr.c_str());
	Assert(type);
	Vec2i resPos;
	DebugPrint("Creating a %s\n" _C_ type->Name.c_str());
	FindNearestDrop(*type, pos, resPos, LookingW);
	if (SquareDistance(pos, resPos) <= square(range)) {
		CUnit *target = MakeUnit(*type, &player);
		if (target != NULL) {
			target->tilePos = resPos;
			target->Place(resPos);
			if (flags & SU_Summoned) {
				target->Summoned = 1;
			}
			if ((flags & SU_JoinToAIForce) && unit.Player->AiEnabled) {
				int force = unit.Player->Ai->Force.GetForce(unit);
				if (force != -1) {
					unit.Player->Ai->Force[force].Insert(*target);
					target->GroupId = unit.GroupId;
					CommandDefend(*target, unit, FlushCommands);
				}
			}
			//DropOutOnSide(*target, LookingW, NULL);
		} else {
			DebugPrint("Unable to allocate Unit");
		}
	}
}
Пример #4
0
/**
**  Move a unit on map.
**
**  @param l  Lua state.
**
**  @return   Returns the slot number of the made placed.
*/
static int CclMoveUnit(lua_State *l)
{
	LuaCheckArgs(l, 2);

	lua_pushvalue(l, 1);
	CUnit *unit = CclGetUnit(l);
	lua_pop(l, 1);

	Vec2i ipos;
	CclGetPos(l, &ipos.x, &ipos.y, 2);

	if (UnitCanBeAt(*unit, ipos)) {
		unit->Place(ipos);
	} else {
		const int heading = SyncRand() % 256;

		unit->tilePos = ipos;
		DropOutOnSide(*unit, heading, NULL);
	}
	lua_pushvalue(l, 1);
	return 1;
}
Пример #5
0
/* virtual */ void COrder_Die::Execute(CUnit &unit)
{
	// Show death animation
	if (AnimateActionDie(unit) == false) {
		// some units has no death animation
		unit.Anim.Unbreakable = 0;
	}
	if (unit.Anim.Unbreakable) {
		return ;
	}
	const CUnitType &type = *unit.Type;

	// Die sequence terminated, generate corpse.
	if (type.CorpseType == NULL) {
		unit.Remove(NULL);
		unit.Release();
		return ;
	}

	const CUnitType &corpseType = *type.CorpseType;
	Assert(type.TileWidth >= corpseType.TileWidth && type.TileHeight >= corpseType.TileHeight);

	// Update sight for new corpse
	// We have to unmark BEFORE changing the type.
	// Always do that, since types can have different vision properties.

	unit.Remove(NULL);
	unit.Type = &corpseType;
	unit.Stats = &corpseType.Stats[unit.Player->Index];
	UpdateUnitSightRange(unit);
	//Wyrmgus start
//	unit.Place(unit.tilePos);
	unit.Place(unit.tilePos, unit.MapLayer);
	//Wyrmgus end

	unit.Frame = 0;
	UnitUpdateHeading(unit);
	AnimateActionDie(unit); // with new corpse.
}
Пример #6
0
/**
**  Find the closest available drop zone for a transporter.
**  Fail if transporter don't transport any unit..
**
**  @param  transporter  the transporter
**  @param  startPos     start location for the search
**	@param  maxRange     The maximum distance from initial position to search...
**  @param  resPos       drop zone position
**
**  @return              1 if a location was found, 0 otherwise
*/
static int ClosestFreeDropZone(CUnit &transporter, const Vec2i &startPos, int maxRange, Vec2i *resPos)
{
	// Check there are units onboard
	if (!transporter.UnitInside) {
		return 0;
	}
	const bool isTransporterRemoved = transporter.Removed;
	const bool selected = transporter.Selected;

	if (!isTransporterRemoved) {
		// Remove transporter to avoid "collision" with itself.
		transporter.Remove(NULL);
	}
	const bool res = ClosestFreeDropZone_internal(transporter, startPos, maxRange, resPos);
	if (!isTransporterRemoved) {
		transporter.Place(transporter.tilePos);
		if (selected) {
			SelectUnit(transporter);
			SelectionChanged();
		}
	}
	return res;
}
Пример #7
0
bool COrder_Build::StartBuilding(CUnit &unit, CUnit &ontop)
{
	const CUnitType &type = this->GetUnitType();

	unit.Player->SubUnitType(type);

	CUnit *build = MakeUnit(const_cast<CUnitType &>(type), unit.Player);

	// If unable to make unit, stop, and report message
	if (build == NULL) {
		// FIXME: Should we retry this?
		unit.Player->Notify(NotifyYellow, unit.tilePos,
							_("Unable to create building %s"), type.Name.c_str());
		if (unit.Player->AiEnabled) {
			AiCanNotBuild(unit, type);
		}
		return false;
	}
	build->Constructed = 1;
	build->CurrentSightRange = 0;

	// Building on top of something, may remove what is beneath it
	if (&ontop != &unit) {
		CBuildRestrictionOnTop *b;

		b = static_cast<CBuildRestrictionOnTop *>(OnTopDetails(*build, ontop.Type));
		Assert(b);
		if (b->ReplaceOnBuild) {
			build->ResourcesHeld = ontop.ResourcesHeld; // We capture the value of what is beneath.
			build->Variable[GIVERESOURCE_INDEX].Value = ontop.Variable[GIVERESOURCE_INDEX].Value;
			build->Variable[GIVERESOURCE_INDEX].Max = ontop.Variable[GIVERESOURCE_INDEX].Max;
			build->Variable[GIVERESOURCE_INDEX].Enable = ontop.Variable[GIVERESOURCE_INDEX].Enable;
			ontop.Remove(NULL); // Destroy building beneath
			UnitLost(ontop);
			UnitClearOrders(ontop);
			ontop.Release();
		}
	}

	// Must set action before placing, otherwise it will incorrectly mark radar
	delete build->CurrentOrder();
	build->Orders[0] = COrder::NewActionBuilt(unit, *build);

	UpdateUnitSightRange(*build);
	// Must place after previous for map flags
	build->Place(this->goalPos);

	// HACK: the building is not ready yet
	build->Player->UnitTypesCount[type.Slot]--;
	if (build->Active) {
		build->Player->UnitTypesAiActiveCount[type.Slot]--;
	}

	// We need somebody to work on it.
	if (!type.BoolFlag[BUILDEROUTSIDE_INDEX].value) {
		UnitShowAnimation(unit, unit.Type->Animations->Still);
		unit.Remove(build);
		this->State = State_BuildFromInside;
		if (unit.Selected) {
			SelectedUnitChanged();
		}
	} else {
		this->State = State_BuildFromOutside;
		this->BuildingUnit = build;
		unit.Direction = DirectionToHeading(build->tilePos - unit.tilePos);
		UnitUpdateHeading(unit);
	}
	return true;
}
Пример #8
0
//Wyrmgus start
//static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype)
int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype)
//Wyrmgus end
{
	const CUnitType &oldtype = *unit.Type;
	if (&oldtype == &newtype) { // nothing to do
		return 1;
	}
	const Vec2i pos = unit.tilePos + oldtype.GetHalfTileSize() - newtype.GetHalfTileSize();
	CUnit *container = unit.Container;

	//Wyrmgus start
	/*
	if (container) {
		MapUnmarkUnitSight(unit);
	} else {
		SaveSelection();
		unit.Remove(NULL);
		if (!UnitTypeCanBeAt(newtype, pos)) {
			unit.Place(unit.tilePos);
			RestoreSelection();
			// FIXME unit is not modified, try later ?
			return 0;
		}
	}
	*/
	if (!SaveGameLoading) {
		if (container) {
			MapUnmarkUnitSight(unit);
		} else {
			SaveSelection();
			unit.Remove(NULL);
			if (!UnitTypeCanBeAt(newtype, pos)) {
				unit.Place(unit.tilePos);
				RestoreSelection();
				// FIXME unit is not modified, try later ?
				return 0;
			}
		}
	}
	//Wyrmgus end
	CPlayer &player = *unit.Player;
	player.UnitTypesCount[oldtype.Slot]--;
	player.UnitTypesCount[newtype.Slot]++;
	if (unit.Active) {
		player.UnitTypesAiActiveCount[oldtype.Slot]--;
		player.UnitTypesAiActiveCount[newtype.Slot]++;
	}
	//Wyrmgus start
	if (unit.Character == NULL) {
		player.UnitTypesNonHeroCount[oldtype.Slot]--;
		player.UnitTypesNonHeroCount[newtype.Slot]++;
	}
	//Wyrmgus end

	player.Demand += newtype.Stats[player.Index].Variables[DEMAND_INDEX].Value - oldtype.Stats[player.Index].Variables[DEMAND_INDEX].Value;
	player.Supply += newtype.Stats[player.Index].Variables[SUPPLY_INDEX].Value - oldtype.Stats[player.Index].Variables[SUPPLY_INDEX].Value;

	// Change resource limit
	for (int i = 0; i < MaxCosts; ++i) {
		if (player.MaxResources[i] != -1) {
			player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i];
			player.SetResource(i, player.StoredResources[i], STORE_BUILDING);
		}
	}

	//  adjust Variables with percent.
	const CUnitStats &newstats = newtype.Stats[player.Index];
	//Wyrmgus start
	const CUnitStats &oldstats = oldtype.Stats[player.Index];
	//Wyrmgus end

	for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) {
		//Wyrmgus start
		/*
		if (unit.Variable[i].Max && unit.Variable[i].Value) {
			unit.Variable[i].Value = newstats.Variables[i].Max *
									 unit.Variable[i].Value / unit.Variable[i].Max;
		} else {
			unit.Variable[i].Value = newstats.Variables[i].Value;
		}
		if (i == KILL_INDEX || i == XP_INDEX) {
			unit.Variable[i].Value = unit.Variable[i].Max;
		} else {
			unit.Variable[i].Max = newstats.Variables[i].Max;
			unit.Variable[i].Increase = newstats.Variables[i].Increase;
			unit.Variable[i].Enable = newstats.Variables[i].Enable;
		}
		*/
		if (i == LEVEL_INDEX) { //if the unit's level changed in accordance to the difference between the levels of the two unit types, then its level change would be duplicated when leveling up, so let's skip the level variable here
			continue;
		}
		
		if (unit.Variable[i].Max && unit.Variable[i].Value) {
			unit.Variable[i].Value += newstats.Variables[i].Max - oldstats.Variables[i].Max;
		} else {
			unit.Variable[i].Value += newstats.Variables[i].Value - oldstats.Variables[i].Value;
		}
		if (i == KILL_INDEX || i == XP_INDEX) {
			unit.Variable[i].Value = unit.Variable[i].Max;
		} else {
			unit.Variable[i].Max += newstats.Variables[i].Max - oldstats.Variables[i].Max;
			unit.Variable[i].Increase += newstats.Variables[i].Increase - oldstats.Variables[i].Increase;
			unit.Variable[i].Enable = newstats.Variables[i].Enable;
		}
		//Wyrmgus end
	}

	//Wyrmgus start
	for (size_t i = 0; i < UnitTypes.size(); ++i) {
		if (newstats.UnitStock[i] != oldstats.UnitStock[i]) {
			unit.UnitStock[i] += newstats.UnitStock[i] - oldstats.UnitStock[i];
			unit.UnitStock[i] = std::max(unit.UnitStock[i], 0);
		}
	}
	//Wyrmgus end
					
	//Wyrmgus start
	//change variation if upgrading (new unit type may have different variations)
	unit.ChooseVariation(&newtype);
	for (int i = 0; i < MaxImageLayers; ++i) {
		unit.ChooseVariation(&newtype, false, i);
	}
	//Wyrmgus end
	
	unit.Type = const_cast<CUnitType *>(&newtype);
	unit.Stats = &unit.Type->Stats[player.Index];
	
	//Wyrmgus start
	//deequip the current equipment if they are incompatible with the new unit type
	for (int i = 0; i < MaxItemSlots; ++i) {
		for (size_t j = 0; j < unit.EquippedItems[i].size(); ++j) {
			if (!unit.CanEquipItemClass(unit.EquippedItems[i][j]->Type->ItemClass)) {
				unit.DeequipItem(*unit.EquippedItems[i][j]);
			}
		}
	}
	//Wyrmgus end
	
	//Wyrmgus start
	//change personal name if new unit type's civilization is different from old unit type's civilization
	if (unit.Character == NULL && !oldtype.Civilization.empty() && !newtype.Civilization.empty() && oldtype.Civilization != newtype.Civilization) {
		unit.UpdatePersonalName();
	}
	//Wyrmgus end

	if (newtype.CanCastSpell && !unit.AutoCastSpell) {
		unit.AutoCastSpell = new char[SpellTypeTable.size()];
		unit.SpellCoolDownTimers = new int[SpellTypeTable.size()];
		memset(unit.AutoCastSpell, 0, SpellTypeTable.size() * sizeof(char));
		memset(unit.SpellCoolDownTimers, 0, SpellTypeTable.size() * sizeof(int));
	}

	UpdateForNewUnit(unit, 1);
	//Wyrmgus start
	/*
	//  Update Possible sight range change
	UpdateUnitSightRange(unit);
	if (!container) {
		unit.Place(pos);
		RestoreSelection();
	} else {
		MapMarkUnitSight(unit);
	}
	*/
	if (!SaveGameLoading) {
		//  Update Possible sight range change
		UpdateUnitSightRange(unit);
		if (!container) {
			unit.Place(pos);
			RestoreSelection();
		} else {
			MapMarkUnitSight(unit);
			//Wyrmgus start
			//if unit has a container, update the container's attack range, as the unit's range may have been changed with the upgrade
			container->UpdateContainerAttackRange();
			//Wyrmgus end
		}
	}
	//Wyrmgus end
	//Wyrmgus start
	//update the unit's XP required, as its level or points may have changed
	unit.UpdateXPRequired();
	//Wyrmgus end
	
	//Wyrmgus start
	/*
	//
	// Update possible changed buttons.
	//
	if (IsOnlySelected(unit) || &player == ThisPlayer) {
		// could affect the buttons of any selected unit
		SelectedUnitChanged();
	}
	*/
	if (!SaveGameLoading) {
		//
		// Update possible changed buttons.
		//
		if (IsOnlySelected(unit) || &player == ThisPlayer) {
			// could affect the buttons of any selected unit
			SelectedUnitChanged();
		}
	}
	//Wyrmgus end
	return 1;
}
Пример #9
0
/**
**  Transform a unit in another.
**
**  @param unit     unit to transform.
**  @param newtype  new type of the unit.
**
**  @return 0 on error, 1 if nothing happens, 2 else.
*/
static int TransformUnitIntoType(CUnit &unit, const CUnitType &newtype)
{
	const CUnitType &oldtype = *unit.Type;
	if (&oldtype == &newtype) { // nothing to do
		return 1;
	}
	const Vec2i pos = unit.tilePos + oldtype.GetHalfTileSize() - newtype.GetHalfTileSize();
	CUnit *container = unit.Container;

	if (container) {
		MapUnmarkUnitSight(unit);
	} else {
		SaveSelection();
		unit.Remove(NULL);
		if (!UnitTypeCanBeAt(newtype, pos)) {
			unit.Place(unit.tilePos);
			RestoreSelection();
			// FIXME unit is not modified, try later ?
			return 0;
		}
	}
	CPlayer &player = *unit.Player;
	player.UnitTypesCount[oldtype.Slot]--;
	player.UnitTypesCount[newtype.Slot]++;

	player.Demand += newtype.Demand - oldtype.Demand;
	player.Supply += newtype.Supply - oldtype.Supply;

	// Change resource limit
	for (int i = 0; i < MaxCosts; ++i) {
		if (player.MaxResources[i] != -1) {
			player.MaxResources[i] += newtype.Stats[player.Index].Storing[i] - oldtype.Stats[player.Index].Storing[i];
			player.SetResource(i, player.StoredResources[i], STORE_BUILDING);
		}
	}

	//  adjust Variables with percent.
	const CUnitStats &newstats = newtype.Stats[player.Index];

	for (unsigned int i = 0; i < UnitTypeVar.GetNumberVariable(); ++i) {
		if (unit.Variable[i].Max && unit.Variable[i].Value) {
			unit.Variable[i].Value = newstats.Variables[i].Max *
									 unit.Variable[i].Value / unit.Variable[i].Max;
		} else {
			unit.Variable[i].Value = newstats.Variables[i].Value;
		}
		unit.Variable[i].Max = newstats.Variables[i].Max;
		unit.Variable[i].Increase = newstats.Variables[i].Increase;
		unit.Variable[i].Enable = newstats.Variables[i].Enable;
	}

	unit.Type = const_cast<CUnitType *>(&newtype);
	unit.Stats = &unit.Type->Stats[player.Index];

	if (newtype.CanCastSpell && !unit.AutoCastSpell) {
		unit.AutoCastSpell = new char[SpellTypeTable.size()];
		memset(unit.AutoCastSpell, 0, SpellTypeTable.size() * sizeof(char));
	}

	UpdateForNewUnit(unit, 1);
	//  Update Possible sight range change
	UpdateUnitSightRange(unit);
	if (!container) {
		unit.Place(pos);
		RestoreSelection();
	} else {
		MapMarkUnitSight(unit);
	}
	//
	// Update possible changed buttons.
	//
	if (IsOnlySelected(unit) || &player == ThisPlayer) {
		// could affect the buttons of any selected unit
		SelectedUnitChanged();
	}
	return 1;
}