示例#1
0
/* virtual */ void COrder_Move::Execute(CUnit &unit)
{
	Assert(unit.CanMove());

	if (unit.Wait) {
		if (!unit.Waiting) {
			unit.Waiting = 1;
			unit.WaitBackup = unit.Anim;
		}
		UnitShowAnimation(unit, unit.Type->Animations->Still);
		unit.Wait--;
		return;
	}
	if (unit.Waiting) {
		unit.Anim = unit.WaitBackup;
		unit.Waiting = 0;
	}
	// FIXME: (mr-russ) Make a reachable goal here with GoalReachable ...

	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			// Some tries to reach the goal
			this->Range++;
			break;

		case PF_REACHED:
			this->Finished = true;
			break;
		default:
			break;
	}
}
示例#2
0
/**
**  Handle moving to the target.
**
**  @param unit  Unit, for that the spell cast is handled.
*/
bool COrder_SpellCast::SpellMoveToTarget(CUnit &unit)
{
	// Unit can't move
	int err = 1;
	if (unit.CanMove()) {
		err = DoActionMove(unit);
		if (unit.Anim.Unbreakable) {
			return false;
		}
	}

	// when reached DoActionMove changes unit action
	// FIXME: use return codes from pathfinder
	CUnit *goal = this->GetGoal();

	if (goal && unit.MapDistanceTo(*goal) <= this->Range) {
		// there is goal and it is in range
		UnitHeadingFromDeltaXY(unit, goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos);
		this->State++; // cast the spell
		return false;
	} else if (!goal && unit.MapDistanceTo(this->goalPos) <= this->Range) {
		// there is no goal and target spot is in range
		UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
		this->State++; // cast the spell
		return false;
	} else if (err == PF_UNREACHABLE || !unit.CanMove()) {
		// goal/spot unreachable and out of range -- give up
		return true;
	}
	return false;
}
示例#3
0
/**
**  Move to build location
**
**  @param unit  Unit to move
*/
bool COrder_Build::MoveToLocation(CUnit &unit)
{
	// First entry
	if (this->State == 0) {
		unit.pathFinderData->output.Cycles = 0; //moving counter
		this->State = 1;
	}
	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE: {
			// Some tries to reach the goal
			if (this->State++ < 10) {
				// To keep the load low, retry each 1/4 second.
				// NOTE: we can already inform the AI about this problem?
				unit.Wait = CYCLES_PER_SECOND / 4;
				return false;
			}

			unit.Player->Notify(NotifyYellow, unit.tilePos, "%s", _("You cannot reach building place"));
			if (unit.Player->AiEnabled) {
				AiCanNotReach(unit, this->GetUnitType());
			}
			return true;
		}
		case PF_REACHED:
			this->State = State_NearOfLocation;
			return false;

		default:
			// Moving...
			return false;
	}
}
示例#4
0
/**
**	Move to transporter.
**
**	@param unit	Pointer to unit, moving to transporter.
**
**	@return		>0 remaining path length, 0 wait for path, -1
**			reached goal, -2 can't reach the goal.
*/
local int MoveToTransporter(Unit* unit)
{
    int i;

    i=DoActionMove(unit);
    // New code has this as default.
    DebugCheck( unit->Orders[0].Action!=UnitActionBoard );
    return i;
}
示例#5
0
/**
**  Move to transporter.
**
**  @param unit  Pointer to unit, moving to transporter.
**
**  @return      >0 remaining path length, 0 wait for path, -1
**               reached goal, -2 can't reach the goal.
*/
int COrder_Board::MoveToTransporter(CUnit &unit)
{
	const Vec2i oldPos = unit.tilePos;
	const int res = DoActionMove(unit);

	// We have to reset a lot, or else they will circle each other and stuff.
	if (oldPos != unit.tilePos) {
		this->Range = 1;
	}
	return res;
}
示例#6
0
/**
**  Move to dropzone.
**
**  @param unit  Pointer to unit.
**
**  @return      -1 if unreachable, True if reached, False otherwise.
*/
static int MoveToDropZone(CUnit &unit)
{
	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			return PF_UNREACHABLE;
		case PF_REACHED:
			break;
		default:
			return 0;
	}

	Assert(unit.CurrentAction() == UnitActionUnload);
	return 1;
}
/**
**  Move to dropzone.
**
**  @param unit  Pointer to unit.
**
**  @return      -1 if unreachable, True if reached, False otherwise.
*/
static int MoveToDropZone(CUnit *unit)
{
	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			return -1;
		case PF_REACHED:
			break;
		default:
			return 0;
	}

	Assert(unit->Orders[0]->Action == UnitActionUnload);
	return 1;
}
示例#8
0
/**
**  Move to transporter.
**
**  @param unit  Pointer to unit, moving to transporter.
**
**  @return      >0 remaining path length, 0 wait for path, -1
**               reached goal, -2 can't reach the goal.
*/
static int MoveToTransporter(CUnit *unit)
{
	int i;
	int x;
	int y;

	x = unit->X;
	y = unit->Y;
	i = DoActionMove(unit);
	// We have to reset a lot, or else they will circle each other and stuff.
	if (x != unit->X || y != unit->Y) {
		unit->Orders[0]->Range = 1;
		NewResetPath(unit);
	}
	// New code has this as default.
	Assert(unit->Orders[0]->Action == UnitActionBoard);
	return i;
}
示例#9
0
/**
**  Move unit to unit resource.
**
**  @return      1 if reached, -1 if unreacheable, 0 if on the way.
*/
int COrder_Resource::MoveToResource_Unit(CUnit &unit)
{
	const CUnit *goal = this->GetGoal();
	Assert(goal);

	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			//Wyrmgus start
			//if is unreachable and is on a raft, see if the raft can move closer
			if ((Map.Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) {
				std::vector<CUnit *> table;
				Select(unit.tilePos, unit.tilePos, table);
				for (size_t i = 0; i != table.size(); ++i) {
					if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) {
						if (table[i]->CurrentAction() == UnitActionStill) {
							CommandStopUnit(*table[i]);
							CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands);
						}
						return 0;
					}
				}
			}
			//Wyrmgus end
			return -1;
		case PF_REACHED:
			break;
		case PF_WAIT:
			if (unit.Player->AiEnabled) {
				this->Range++;
				if (this->Range >= 5) {
					this->Range = 0;
					AiCanNotMove(unit);
				}
			}
		default:
			// Goal gone or something.
			if (unit.Anim.Unbreakable || goal->IsVisibleAsGoal(*unit.Player)) {
				return 0;
			}
			break;
	}
	return 1;
}
示例#10
0
/**
**	Move to coast.
**
**	@param unit	Pointer to unit.
**	@return		-1 if unreachable, True if reached, False otherwise.
*/
local int MoveToCoast(Unit* unit)
{
    DebugLevel3Fn("%p\n" _C_ unit->Orders[0].Goal);

    switch( DoActionMove(unit) ) {	// reached end-point?
	case PF_UNREACHABLE:
	    DebugLevel2Fn("COAST NOT REACHED\n");
	    return -1;
	case PF_REACHED:
	    break;
	default:
	    return 0;
    }

    IfDebug(
	if( !CoastOnMap(unit->X,unit->Y) ) {
	    DebugLevel2Fn("COAST NOT REACHED\n");
	    return -1;
	}
    )
示例#11
0
/* virtual */ void COrder_Move::Execute(CUnit &unit)
{
	Assert(unit.CanMove());

	if (unit.Wait) {
		unit.Wait--;
		return ;
	}
	// FIXME: (mr-russ) Make a reachable goal here with GoalReachable ...

	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			// Some tries to reach the goal
			this->Range++;
			break;

		case PF_REACHED:
			this->Finished = true;
			break;
		default:
			break;
	}
}
示例#12
0
/**
**  Controls moving a unit to its target when attacking
**
**  @param unit  Unit that is attacking and moving
*/
void COrder_Attack::MoveToTarget(CUnit &unit)
{
	Assert(!unit.Type->Vanishes && !unit.Destroyed && !unit.Removed);
	Assert(unit.CurrentOrder() == this);
	Assert(unit.CanMove());
	Assert(this->HasGoal() || Map.Info.IsPointOnMap(this->goalPos));

	int err = DoActionMove(unit);

	if (unit.Anim.Unbreakable) {
		return;
	}

	// Look if we have reached the target.
	if (err == 0 && !this->HasGoal()) {
		// Check if we're in range when attacking a location and we are waiting
		if (unit.MapDistanceTo(this->goalPos) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) {
			err = PF_REACHED;
		}
	}
	if (err >= 0) {
		if (CheckForTargetInRange(unit)) {
			return;
		}
		return;
	}
	if (err == PF_REACHED) {
		CUnit *goal = this->GetGoal();
		// Have reached target? FIXME: could use the new return code?
		if (goal
			&& unit.MapDistanceTo(*goal) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) {
			// Reached another unit, now attacking it
			const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
			UnitHeadingFromDeltaXY(unit, dir);
			this->State++;
			return;
		}
		// Attacking wall or ground.
		if (((goal && goal->Type && goal->Type->Wall)
			 || (!goal && (Map.WallOnMap(this->goalPos) || this->Action == UnitActionAttackGround)))
			&& unit.MapDistanceTo(this->goalPos) <= unit.Stats->Variables[ATTACKRANGE_INDEX].Max) {
			// Reached wall or ground, now attacking it
			UnitHeadingFromDeltaXY(unit, this->goalPos - unit.tilePos);
			this->State &= WEAK_TARGET;
			this->State |= ATTACK_TARGET;
			return;
		}
	}
	// Unreachable.

	if (err == PF_UNREACHABLE) {
		if (!this->HasGoal()) {
			// When attack-moving we have to allow a bigger range
			this->Range++;
			unit.Wait = 5;
			return;
		} else {
			this->ClearGoal();
		}
	}

	// Return to old task?
	if (!unit.RestoreOrder()) {
		this->Finished = true;
	}
}
示例#13
0
/**
**  Unit repairs
**
**  @param unit  Unit, for that the attack is handled.
*/
void HandleActionRepair(CUnit *unit)
{
	CUnit *goal;
	int err;

	switch (unit->SubAction) {
		case 0:
			NewResetPath(unit);
			unit->SubAction = 1;
			// FALL THROUGH
		//
		// Move near to target.
		//
		case 1:
			// FIXME: RESET FIRST!! Why? We move first and than check if
			// something is in sight.
			err = DoActionMove(unit);
			if (!unit->Anim.Unbreakable) {
				//
				// No goal: if meeting damaged building repair it.
				//
				goal = unit->Orders[0]->Goal;

				//
				// Target is dead, choose new one.
				//
				// Check if goal is correct unit.
				if (goal) {
					if (!goal->IsVisibleAsGoal(unit->Player)) {
						DebugPrint("repair target gone.\n");
						unit->Orders[0]->X = goal->X;
						unit->Orders[0]->Y = goal->Y;
						goal->RefsDecrease();
						// FIXME: should I clear this here?
						unit->Orders[0]->Goal = goal = NULL;
						NewResetPath(unit);
					}
				} else if (unit->Player->AiEnabled) {
					// Ai players workers should stop if target is killed
					err = -1;
				}

				//
				// Have reached target? FIXME: could use return value
				//
				if (goal && MapDistanceBetweenUnits(unit, goal) <= unit->Type->RepairRange &&
						goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
					unit->State = 0;
					unit->SubAction = 2;
					unit->Data.Repair.Cycles = 0;
					UnitHeadingFromDeltaXY(unit,
						goal->X + (goal->Type->TileWidth - 1) / 2 - unit->X,
						goal->Y + (goal->Type->TileHeight - 1) / 2 - unit->Y);
				} else if (err < 0) {
					if (goal) { // release reference
						goal->RefsDecrease();
						unit->Orders[0]->Goal = NoUnitP;
					}
					unit->Orders[0]->Action = UnitActionStill;
					unit->State = unit->SubAction = 0;
					if (unit->Selected) { // update display for new action
						SelectedUnitChanged();
					}
					return;
				}

				// FIXME: Should be it already?
				Assert(unit->Orders[0]->Action == UnitActionRepair);
			}
			break;

		//
		// Repair the target.
		//
		case 2:
			AnimateActionRepair(unit);
			unit->Data.Repair.Cycles++;
			if (!unit->Anim.Unbreakable) {
				goal = unit->Orders[0]->Goal;

				//
				// Target is dead, choose new one.
				//
				// Check if goal is correct unit.
				// FIXME: should I do a function for this?
				if (goal) {
					if (!goal->IsVisibleAsGoal(unit->Player)) {
						DebugPrint("repair goal is gone\n");
						unit->Orders[0]->X = goal->X;
						unit->Orders[0]->Y = goal->Y;
						goal->RefsDecrease();
						// FIXME: should I clear this here?
						unit->Orders[0]->Goal = goal = NULL;
						NewResetPath(unit);
					}
				}
				if (goal && MapDistanceBetweenUnits(unit, goal) <= unit->Type->RepairRange) {
					RepairUnit(unit, goal);
					goal = unit->Orders[0]->Goal;
				} else if (goal && MapDistanceBetweenUnits(unit, goal) > unit->Type->RepairRange) {
					// If goal has move, chase after it
					unit->State = 0;
					unit->SubAction = 0;
				}


				//
				// Target is fine, choose new one.
				//
				if (!goal || goal->Variable[HP_INDEX].Value >= goal->Variable[HP_INDEX].Max) {
					if (goal) { // release reference
						goal->RefsDecrease();
						unit->Orders[0]->Goal = NULL;
					}
					unit->Orders[0]->Action = UnitActionStill;
					unit->SubAction = unit->State = 0;
					if (unit->Selected) { // update display for new action
						SelectedUnitChanged();
					}
					return;
				}

				// FIXME: automatic repair
			}
			break;
	}
}
示例#14
0
/* virtual */ void COrder_Defend::Execute(CUnit &unit)
{
	if (unit.Wait) {
		if (!unit.Waiting) {
			unit.Waiting = 1;
			unit.WaitBackup = unit.Anim;
		}
		//Wyrmgus start
//		UnitShowAnimation(unit, unit.Type->Animations->Still);
		VariationInfo *varinfo = unit.Type->VarInfo[unit.Variation];
		if (varinfo && varinfo->Animations && varinfo->Animations->Still) {
			UnitShowAnimation(unit, varinfo->Animations->Still);
		} else {
			UnitShowAnimation(unit, unit.Type->Animations->Still);
		}
		//Wyrmgus end
		unit.Wait--;
		return;
	}
	if (unit.Waiting) {
		unit.Anim = unit.WaitBackup;
		unit.Waiting = 0;
	}
	CUnit *goal = this->GetGoal();

	if (this->State == State_Init) {
		if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
			this->Finished = true;
			return;
		}
		this->State = State_MovingToTarget;
	} else if (this->State == State_Defending) {
		if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
			this->Finished = true;
			return;
		}
	}

	if (!unit.Anim.Unbreakable) {
		if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) {
			return;
		}
	}

	switch (DoActionMove(unit)) {
		case PF_UNREACHABLE:
			// Some tries to reach the goal
			this->Range++;
			break;
		case PF_REACHED: {
			if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died
				this->Finished = true;
				return;
			}

			// Now defend the goal
			this->goalPos = goal->tilePos;
			this->State = State_Defending;
		}
		default:
			break;
	}

	// Target destroyed?
	if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
		DebugPrint("Goal gone\n");
		this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
		this->ClearGoal();
		goal = NULL;
		if (this->State == State_Defending) {
			this->Finished = true;
			return;
		}
	}
}
示例#15
0
/**
**	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;
    }
}
示例#16
0
/**
**  Move to resource depot
**
**  @param unit  Pointer to unit.
**
**  @return      TRUE if reached, otherwise FALSE.
*/
int COrder_Resource::MoveToDepot(CUnit &unit)
{
	const ResourceInfo &resinfo = *unit.Type->ResInfo[this->CurrentResource];
	CUnit &goal = *this->GetGoal();
	CPlayer &player = *unit.Player;
	Assert(&goal);

	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			//Wyrmgus start
			//if is unreachable and is on a raft, see if the raft can move closer
			if ((Map.Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) {
				std::vector<CUnit *> table;
				Select(unit.tilePos, unit.tilePos, table);
				for (size_t i = 0; i != table.size(); ++i) {
					if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) {
						if (table[i]->CurrentAction() == UnitActionStill) {
							CommandStopUnit(*table[i]);
							CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands);
						}
						return 0;
					}
				}
			}
			//Wyrmgus end
			return -1;
		case PF_REACHED:
			break;
		case PF_WAIT:
			if (unit.Player->AiEnabled) {
				this->Range++;
				if (this->Range >= 5) {
					this->Range = 0;
					AiCanNotMove(unit);
				}
			}
		default:
			if (unit.Anim.Unbreakable || goal.IsVisibleAsGoal(player)) {
				return 0;
			}
			break;
	}

	//
	// Target is dead, stop getting resources.
	//
	if (!goal.IsVisibleAsGoal(player)) {
		DebugPrint("%d: Worker %d report: Destroyed depot\n" _C_ player.Index _C_ UnitNumber(unit));

		unit.CurrentOrder()->ClearGoal();

		CUnit *depot = FindDeposit(unit, 1000, unit.CurrentResource);

		if (depot) {
			UnitGotoGoal(unit, depot, SUB_MOVE_TO_DEPOT);
			DebugPrint("%d: Worker %d report: Going to new deposit.\n" _C_ player.Index _C_ UnitNumber(unit));
		} else {
			DebugPrint("%d: Worker %d report: Can't find a new resource deposit.\n"
					   _C_ player.Index _C_ UnitNumber(unit));

			// FIXME: perhaps we should choose an alternative
			this->Finished = true;
		}
		return 0;
	}

	// If resource depot is still under construction, wait!
	if (goal.CurrentAction() == UnitActionBuilt) {
		unit.Wait = 10;
		return 0;
	}

	this->ClearGoal();
	unit.Wait = resinfo.WaitAtDepot;

	// Place unit inside the depot
	if (unit.Wait) {
		int selected = unit.Selected;
		unit.Remove(&goal);
		if (selected && !Preference.DeselectInMine) {
			unit.Removed = 0;
			SelectUnit(unit);
			SelectionChanged();
			unit.Removed = 1;
		}
		unit.Anim.CurrAnim = NULL;
	}

	// Update resource.
	const int rindex = resinfo.FinalResource;
	//Wyrmgus start
//	player.ChangeResource(rindex, (unit.ResourcesHeld * player.Incomes[rindex]) / 100, true);
//	player.TotalResources[rindex] += (unit.ResourcesHeld * player.Incomes[rindex]) / 100;
	player.ChangeResource(rindex, (unit.ResourcesHeld * resinfo.FinalResourceConversionRate / 100 * player.Incomes[rindex]) / 100, true);
	player.TotalResources[rindex] += (unit.ResourcesHeld * resinfo.FinalResourceConversionRate / 100 * player.Incomes[rindex]) / 100;
	//Wyrmgus end
	unit.ResourcesHeld = 0;
	unit.CurrentResource = 0;

	if (unit.Wait) {
		//Wyrmgus start
//		unit.Wait /= std::max(1, unit.Player->SpeedResourcesReturn[resinfo.ResourceId] / SPEEDUP_FACTOR);
		unit.Wait /= std::max(1, (unit.Player->SpeedResourcesReturn[resinfo.ResourceId] + goal.Variable[TIMEEFFICIENCYBONUS_INDEX].Value) / SPEEDUP_FACTOR);
		//Wyrmgus end
		if (unit.Wait) {
			unit.Wait--;
		}
	}
	return 1;
}
示例#17
0
/**
**  Unit repairs
**
**  @param unit  Unit, for that the attack is handled.
*/
void HandleActionRepair(CUnit &unit)
{
	CUnit *goal;
	int err;

	switch (unit.SubAction) {
		case 0:
			NewResetPath(unit);
			unit.SubAction = 1;
			// FALL THROUGH
		//
		// Move near to target.
		//
		case 1:
			// FIXME: RESET FIRST!! Why? We move first and than check if
			// something is in sight.
			err = DoActionMove(unit);
			if (!unit.Anim.Unbreakable) {
				//
				// No goal: if meeting damaged building repair it.
				//
				goal = unit.CurrentOrder()->GetGoal();

				//
				// Target is dead, choose new one.
				//
				// Check if goal is correct unit.
				if (goal) {
					if (!goal->IsVisibleAsGoal(unit.Player)) {
						DebugPrint("repair target gone.\n");
						unit.CurrentOrder()->goalPos = goal->tilePos;
						// FIXME: should I clear this here?
						unit.CurrentOrder()->ClearGoal();
						goal = NULL;
						NewResetPath(unit);
					}
				} else if (unit.Player->AiEnabled) {
					// Ai players workers should stop if target is killed
					err = -1;
				}

				//
				// Have reached target? FIXME: could use return value
				//
				if (goal && unit.MapDistanceTo(*goal) <= unit.Type->RepairRange &&
						goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
					unit.State = 0;
					unit.SubAction = 2;
					unit.Data.Repair.Cycles = 0;
					const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
					UnitHeadingFromDeltaXY(unit, dir);
				} else if (err < 0) {
					unit.CurrentOrder()->ClearGoal();
					if (!unit.RestoreOrder()) {
						unit.ClearAction();
						unit.State = 0;
					}
					return;
				}

				// FIXME: Should be it already?
				Assert(unit.CurrentAction() == UnitActionRepair);
			}
			break;

		//
		// Repair the target.
		//
		case 2:
			AnimateActionRepair(unit);
			unit.Data.Repair.Cycles++;
			if (!unit.Anim.Unbreakable) {
				goal = unit.CurrentOrder()->GetGoal();

				//
				// Target is dead, choose new one.
				//
				// Check if goal is correct unit.
				// FIXME: should I do a function for this?
				if (goal) {
					if (!goal->IsVisibleAsGoal(unit.Player)) {
						DebugPrint("repair goal is gone\n");
						unit.CurrentOrder()->goalPos = goal->tilePos;
						// FIXME: should I clear this here?
						unit.CurrentOrder()->ClearGoal();
						goal = NULL;
						NewResetPath(unit);
					} else {
						int dist = unit.MapDistanceTo(*goal);
						if (dist <= unit.Type->RepairRange) {
							RepairUnit(unit, *goal);
							goal = unit.CurrentOrder()->GetGoal();
						} else if (dist > unit.Type->RepairRange) {
							// If goal has move, chase after it
							unit.State = 0;
							unit.SubAction = 0;
						}
					}
				}


				//
				// Target is fine, choose new one.
				//
				if (!goal || goal->Variable[HP_INDEX].Value >=
					 goal->Variable[HP_INDEX].Max) {
					unit.CurrentOrder()->ClearGoal();
					if (!unit.RestoreOrder()) {
						unit.ClearAction();
						unit.State = 0;
					}
					return;
				}

				// FIXME: automatic repair
			}
			break;
	}
}
示例#18
0
/* virtual */ void COrder_Defend::Execute(CUnit &unit)
{
	if (unit.Wait) {
		if (!unit.Waiting) {
			unit.Waiting = 1;
			unit.WaitBackup = unit.Anim;
		}
		//Wyrmgus start
//		UnitShowAnimation(unit, unit.Type->Animations->Still);
		UnitShowAnimation(unit, unit.GetAnimations()->Still);
		//Wyrmgus end
		unit.Wait--;
		return;
	}
	if (unit.Waiting) {
		unit.Anim = unit.WaitBackup;
		unit.Waiting = 0;
	}
	CUnit *goal = this->GetGoal();

	if (this->State == State_Init) {
		if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
			this->Finished = true;
			return;
		}
		this->State = State_MovingToTarget;
	} else if (this->State == State_Defending) {
		if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
			this->Finished = true;
			return;
		}
	}

	if (!unit.Anim.Unbreakable) {
		if (AutoCast(unit) || AutoAttack(unit) || AutoRepair(unit)) {
			return;
		}
	}

	switch (DoActionMove(unit)) {
		case PF_UNREACHABLE:
			//Wyrmgus start
			//if is unreachable and is on a raft, see if the raft can move closer to the enemy
			if ((Map.Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) {
				std::vector<CUnit *> table;
				Select(unit.tilePos, unit.tilePos, table);
				for (size_t i = 0; i != table.size(); ++i) {
					if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) {
						if (table[i]->CurrentAction() == UnitActionStill) {
							CommandStopUnit(*table[i]);
							CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands);
						}
						return;
					}
				}
			}
			//Wyrmgus end
			// Some tries to reach the goal
			this->Range++;
			break;
		case PF_REACHED: {
			if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) { // goal has died
				this->Finished = true;
				return;
			}

			// Now defend the goal
			this->goalPos = goal->tilePos;
			this->State = State_Defending;
		}
		default:
			break;
	}

	// Target destroyed?
	if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
		DebugPrint("Goal gone\n");
		this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
		this->ClearGoal();
		goal = NULL;
		if (this->State == State_Defending) {
			this->Finished = true;
			return;
		}
	}
}
示例#19
0
/**
**  Unit Patrol:
**    The unit patrols between two points.
**    Any enemy unit in reaction range is attacked.
**  @todo FIXME:
**    Should do some tries to reach the end-points.
**    Should support patrol between more points!
**    Patrol between units.
**
**  @param unit  Patroling unit pointer.
*/
void HandleActionPatrol(CUnit *unit)
{
	if (unit->Wait) {
		unit->Wait--;
		return;
	}

	if (!unit->SubAction) { // first entry.
		NewResetPath(unit);
		unit->SubAction = 1;
	}

	switch (DoActionMove(unit)) {
		case PF_FAILED:
			unit->SubAction = 1;
			break;
		case PF_UNREACHABLE:
			// Increase range and try again
			unit->SubAction = 1;
			if (unit->Orders[0]->Range <= Map.Info.MapWidth ||
					unit->Orders[0]->Range <= Map.Info.MapHeight) {
				unit->Orders[0]->Range++;
				break;
			}
			// FALL THROUGH
		case PF_REACHED:
			unit->SubAction = 1;
			unit->Orders[0]->Range = 0;
			SwapPatrolPoints(unit);
			break;
		case PF_WAIT:
			// Wait for a while then give up
			unit->SubAction++;
			if (unit->SubAction == 5) {
				unit->SubAction = 1;
				unit->Orders[0]->Range = 0;
				SwapPatrolPoints(unit);
			}
			break;
		default: // moving
			unit->SubAction = 1;
			break;
	}

	if (!unit->Anim.Unbreakable) {
		//
		// Attack any enemy in reaction range.
		//  If don't set the goal, the unit can then choose a
		//  better goal if moving nearer to enemy.
		//
		if (unit->Type->CanAttack) {
			const CUnit *goal = AttackUnitsInReactRange(unit);
			if (goal) {
				DebugPrint("Patrol attack %d\n" _C_ UnitNumber(goal));
				CommandAttack(unit, goal->X, goal->Y, NULL, FlushCommands);
				// Save current command to come back.
				unit->SavedOrder = *unit->Orders[0];
				unit->Orders[0]->Action = UnitActionStill;
				unit->Orders[0]->Goal = NoUnitP;
				unit->SubAction = 0;
			}
		}
	}
}
示例#20
0
/**
**  Move unit to terrain.
**
**  @return      1 if reached, -1 if unreacheable, 0 if on the way.
*/
int COrder_Resource::MoveToResource_Terrain(CUnit &unit)
{
	Vec2i pos = this->goalPos;

	// Wood gone, look somewhere else.
	if ((Map.Info.IsPointOnMap(pos) == false || Map.Field(pos)->IsTerrainResourceOnMap(CurrentResource) == false)
		&& (!unit.IX) && (!unit.IY)) {
		//Wyrmgus start
//		if (!FindTerrainType(unit.Type->MovementMask, MapFieldForest, 16, *unit.Player, this->goalPos, &pos)) {
		if ((this->CurrentResource == WoodCost && !FindTerrainType(unit.Type->MovementMask, MapFieldForest, 16, *unit.Player, this->goalPos, &pos)) || (this->CurrentResource == StoneCost && !FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 16, *unit.Player, this->goalPos, &pos))) {
		//Wyrmgus end
			// no wood in range
			return -1;
		} else {
			this->goalPos = pos;
		}
	}
	switch (DoActionMove(unit)) {
		case PF_UNREACHABLE:
			//Wyrmgus start
			//if is unreachable and is on a raft, see if the raft can move closer
			if ((Map.Field(unit.tilePos)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) {
				std::vector<CUnit *> table;
				Select(unit.tilePos, unit.tilePos, table);
				for (size_t i = 0; i != table.size(); ++i) {
					if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) {
						if (table[i]->CurrentAction() == UnitActionStill) {
							CommandStopUnit(*table[i]);
							CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands);
						}
						return 0;
					}
				}
			}
			//Wyrmgus end
			unit.Wait = 10;
			if (unit.Player->AiEnabled) {
				this->Range++;
				if (this->Range >= 5) {
					this->Range = 0;
					AiCanNotMove(unit);
				}
			}
			//Wyrmgus start
//			if (FindTerrainType(unit.Type->MovementMask, MapFieldForest, 9999, *unit.Player, unit.tilePos, &pos)) {
			if ((this->CurrentResource == WoodCost && FindTerrainType(unit.Type->MovementMask, MapFieldForest, 9999, *unit.Player, unit.tilePos, &pos)) || (this->CurrentResource == StoneCost && FindTerrainType(unit.Type->MovementMask, MapFieldRocks, 9999, *unit.Player, unit.tilePos, &pos))) {
			//Wyrmgus end
				this->goalPos = pos;
				DebugPrint("Found a better place to harvest %d,%d\n" _C_ pos.x _C_ pos.y);
				// FIXME: can't this overflow? It really shouldn't, since
				// x and y are really supossed to be reachable, checked thorugh a flood fill.
				// I don't know, sometimes stuff happens.
				return 0;
			}
			return -1;
		case PF_REACHED:
			return 1;
		case PF_WAIT:
			if (unit.Player->AiEnabled) {
				this->Range++;
				if (this->Range >= 5) {
					this->Range = 0;
					AiCanNotMove(unit);
				}
			}
		default:
			return 0;
	}
}
示例#21
0
/* virtual */ void COrder_Follow::Execute(CUnit &unit)
{
	if (unit.Wait) {
		if (!unit.Waiting) {
			unit.Waiting = 1;
			unit.WaitBackup = unit.Anim;
		}
		//Wyrmgus start
//		UnitShowAnimation(unit, unit.Type->Animations->Still);
		UnitShowAnimation(unit, unit.GetAnimations()->Still);
		//Wyrmgus end
		unit.Wait--;
		return;
	}
	if (unit.Waiting) {
		unit.Anim = unit.WaitBackup;
		unit.Waiting = 0;
	}
	CUnit *goal = this->GetGoal();

	// Reached target
	if (this->State == State_TargetReached) {

		if (!goal || !goal->IsVisibleAsGoal(*unit.Player)) {
			DebugPrint("Goal gone\n");
			this->Finished = true;
			return ;
		}

		// Don't follow after immobile units
		if (goal && goal->CanMove() == false) {
			this->Finished = true;
			return;
		}

		//Wyrmgus start
//		if (goal->tilePos == this->goalPos) {
		if (goal->tilePos == this->goalPos && goal->MapLayer == this->MapLayer) {
		//Wyrmgus end
			// Move to the next order
			if (unit.Orders.size() > 1) {
				this->Finished = true;
				return ;
			}

			unit.Wait = 10;
			if (this->Range > 1) {
				this->Range = 1;
				this->State = State_Init;
			}
			return ;
		}
		this->State = State_Init;
	}
	if (this->State == State_Init) { // first entry
		this->State = State_Initialized;
	}
	switch (DoActionMove(unit)) { // reached end-point?
		case PF_UNREACHABLE:
			//Wyrmgus start
			if ((Map.Field(unit.tilePos, unit.MapLayer)->Flags & MapFieldBridge) && !unit.Type->BoolFlag[BRIDGE_INDEX].value && unit.Type->UnitType == UnitTypeLand) {
				std::vector<CUnit *> table;
				Select(unit.tilePos, unit.tilePos, table, unit.MapLayer);
				for (size_t i = 0; i != table.size(); ++i) {
					if (!table[i]->Removed && table[i]->Type->BoolFlag[BRIDGE_INDEX].value && table[i]->CanMove()) {
						if (table[i]->CurrentAction() == UnitActionStill) {
							CommandStopUnit(*table[i]);
							CommandMove(*table[i], this->HasGoal() ? this->GetGoal()->tilePos : this->goalPos, FlushCommands, this->HasGoal() ? this->GetGoal()->MapLayer : this->MapLayer);
						}
						return;
					}
				}
			}
			//Wyrmgus end
			// Some tries to reach the goal
			this->Range++;
			break;
		case PF_REACHED: {
			if (!goal) { // goal has died
				this->Finished = true;
				return ;
			}
			// Handle Teleporter Units
			// FIXME: BAD HACK
			// goal shouldn't be busy and portal should be alive
			if (goal->Type->BoolFlag[TELEPORTER_INDEX].value && goal->Goal && goal->Goal->IsAlive() && unit.MapDistanceTo(*goal) <= 1) {
				if (!goal->IsIdle()) { // wait
					unit.Wait = 10;
					return;
				}
				// Check if we have enough mana
				if (goal->Goal->Type->TeleportCost > goal->Variable[MANA_INDEX].Value) {
					this->Finished = true;
					return;
				} else {
					goal->Variable[MANA_INDEX].Value -= goal->Goal->Type->TeleportCost;
				}
				// Everything is OK, now teleport the unit
				unit.Remove(NULL);
				if (goal->Type->TeleportEffectIn) {
					goal->Type->TeleportEffectIn->pushPreamble();
					goal->Type->TeleportEffectIn->pushInteger(UnitNumber(unit));
					goal->Type->TeleportEffectIn->pushInteger(UnitNumber(*goal));
					goal->Type->TeleportEffectIn->pushInteger(unit.GetMapPixelPosCenter().x);
					goal->Type->TeleportEffectIn->pushInteger(unit.GetMapPixelPosCenter().y);
					goal->Type->TeleportEffectIn->run();
				}
				unit.tilePos = goal->Goal->tilePos;
				//Wyrmgus start
				unit.MapLayer = goal->Goal->MapLayer;
				//Wyrmgus end
				DropOutOnSide(unit, unit.Direction, NULL);

				// FIXME: we must check if the units supports the new order.
				CUnit &dest = *goal->Goal;
				if (dest.Type->TeleportEffectOut) {
					dest.Type->TeleportEffectOut->pushPreamble();
					dest.Type->TeleportEffectOut->pushInteger(UnitNumber(unit));
					dest.Type->TeleportEffectOut->pushInteger(UnitNumber(dest));
					dest.Type->TeleportEffectOut->pushInteger(unit.GetMapPixelPosCenter().x);
					dest.Type->TeleportEffectOut->pushInteger(unit.GetMapPixelPosCenter().y);
					dest.Type->TeleportEffectOut->run();
				}

				if (dest.NewOrder == NULL
					|| (dest.NewOrder->Action == UnitActionResource && !unit.Type->BoolFlag[HARVESTER_INDEX].value)
					//Wyrmgus start
//					|| (dest.NewOrder->Action == UnitActionAttack && !unit.Type->CanAttack)
					|| (dest.NewOrder->Action == UnitActionAttack && !unit.CanAttack(true))
					//Wyrmgus end
					|| (dest.NewOrder->Action == UnitActionBoard && unit.Type->UnitType != UnitTypeLand)) {
					this->Finished = true;
					return ;
				} else {
					if (dest.NewOrder->HasGoal()) {
						if (dest.NewOrder->GetGoal()->Destroyed) {
							delete dest.NewOrder;
							dest.NewOrder = NULL;
							this->Finished = true;
							return ;
						}
						unit.Orders.insert(unit.Orders.begin() + 1, dest.NewOrder->Clone());
						this->Finished = true;
						return ;
					}
				}
			}
			this->goalPos = goal->tilePos;
			//Wyrmgus start
			this->MapLayer = goal->MapLayer;
			//Wyrmgus end
			this->State = State_TargetReached;
		}
		// FALL THROUGH
		default:
			break;
	}

	// Target destroyed?
	if (goal && !goal->IsVisibleAsGoal(*unit.Player)) {
		DebugPrint("Goal gone\n");
		this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
		//Wyrmgus start
		this->MapLayer = goal->MapLayer;
		//Wyrmgus end
		this->ClearGoal();
		goal = NULL;
	}

	if (unit.Anim.Unbreakable) {
		return ;
	}
	// If our leader is dead or stops or attacks:
	// Attack any enemy in reaction range.
	// If don't set the goal, the unit can than choose a
	//  better goal if moving nearer to enemy.
	//Wyrmgus start
//	if (unit.Type->CanAttack
	if (unit.CanAttack()
	//Wyrmgus end
		&& (!goal || goal->CurrentAction() == UnitActionAttack || goal->CurrentAction() == UnitActionStill)) {
		CUnit *target = AttackUnitsInReactRange(unit);
		if (target) {
			// Save current command to come back.
			COrder *savedOrder = NULL;
			if (unit.CanStoreOrder(unit.CurrentOrder())) {
				savedOrder = this->Clone();
			}

			this->Finished = true;
			//Wyrmgus start
//			unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos));
			unit.Orders.insert(unit.Orders.begin() + 1, COrder::NewActionAttack(unit, target->tilePos, target->MapLayer));
			//Wyrmgus end

			if (savedOrder != NULL) {
				unit.SavedOrder = savedOrder;
			}
		}
	}
}
示例#22
0
/* virtual */ void COrder_Repair::Execute(CUnit &unit)
{
	Assert(this->ReparableTarget == this->GetGoal());

	switch (this->State) {
		case 0:
			this->State = 1;
		// FALL THROUGH
		case 1: { // Move near to target.
			// FIXME: RESET FIRST!! Why? We move first and than check if
			// something is in sight.
			int err = DoActionMove(unit);
			if (!unit.Anim.Unbreakable) {
				// No goal: if meeting damaged building repair it.
				CUnit *goal = this->GetGoal();

				if (goal) {
					if (!goal->IsVisibleAsGoal(*unit.Player)) {
						DebugPrint("repair target gone.\n");
						this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
						ReparableTarget = NULL;
						this->ClearGoal();
						goal = NULL;
					}
				} else if (unit.Player->AiEnabled) {
					// Ai players workers should stop if target is killed
					err = -1;
				}

				// Have reached target? FIXME: could use return value
				if (goal && unit.MapDistanceTo(*goal) <= unit.Type->RepairRange
					&& goal->Variable[HP_INDEX].Value < goal->Variable[HP_INDEX].Max) {
					this->State = 2;
					this->RepairCycle = 0;
					const Vec2i dir = goal->tilePos + goal->Type->GetHalfTileSize() - unit.tilePos;
					UnitHeadingFromDeltaXY(unit, dir);
				} else if (err < 0) {
					this->Finished = true;
					return ;
				}
			}
			break;
		}
		case 2: {// Repair the target.
			AnimateActionRepair(unit);
			this->RepairCycle++;
			if (unit.Anim.Unbreakable) {
				return ;
			}
			CUnit *goal = this->GetGoal();

			if (goal) {
				if (!goal->IsVisibleAsGoal(*unit.Player)) {
					DebugPrint("repair goal is gone\n");
					this->goalPos = goal->tilePos + goal->Type->GetHalfTileSize();
					// FIXME: should I clear this here?
					this->ClearGoal();
					ReparableTarget = NULL;
					goal = NULL;
				} else {
					const int dist = unit.MapDistanceTo(*goal);

					if (dist <= unit.Type->RepairRange) {
						if (RepairUnit(unit, *goal)) {
							this->Finished = true;
							return ;
						}
					} else if (dist > unit.Type->RepairRange) {
						// If goal has move, chase after it
						this->State = 0;
					}
				}
			}
			// Target is fine, choose new one.
			if (!goal || goal->Variable[HP_INDEX].Value >= goal->Variable[HP_INDEX].Max) {
				this->Finished = true;
				return ;
			}
			// FIXME: automatic repair
		}
		break;
	}
}