Example #1
0
/**
** Send command: Unit return goods.
**
** @param unit    pointer to unit.
** @param goal    pointer to destination of the goods. (NULL=search best)
** @param flush   Flag flush all pending commands.
*/
void SendCommandReturnGoods(CUnit &unit, CUnit *goal, int flush)
{
	if (!IsNetworkGame()) {
		CommandLog("return", &unit, flush, -1, -1, goal, NULL, -1);
		CommandReturnGoods(unit, goal, flush);
	} else {
		NetworkSendCommand(MessageCommandReturn, unit, 0, 0, goal, 0, flush);
	}
}
Example #2
0
/**
** Execute a command (from network).
**
** @param msgnr    Network message type
** @param unum     Unit number (slot) that receive the command.
** @param x        optional X map position.
** @param y        optional y map position.
** @param dstnr    optional destination unit.
*/
void ExecCommand(unsigned char msgnr, UnitRef unum,
				 unsigned short x, unsigned short y, UnitRef dstnr)
{
	CUnit &unit = UnitManager.GetSlotUnit(unum);
	const Vec2i pos(x, y);
	const int arg1 = x;
	const int arg2 = y;
	//
	// Check if unit is already killed?
	//
	if (unit.Destroyed) {
		DebugPrint(" destroyed unit skipping %d\n" _C_ UnitNumber(unit));
		return;
	}
	Assert(unit.Type);

	const int status = (msgnr & 0x80) >> 7;
	// Note: destroyed destination unit is handled by the action routines.

	switch (msgnr & 0x7F) {
		case MessageSync:
			return;
		case MessageQuit:
			return;
		case MessageChat:
			return;

		case MessageCommandStop:
			CommandLog("stop", &unit, FlushCommands, -1, -1, NoUnitP, NULL, -1);
			CommandStopUnit(unit);
			break;
		case MessageCommandStand:
			CommandLog("stand-ground", &unit, status, -1, -1, NoUnitP, NULL, -1);
			CommandStandGround(unit, status);
			break;
		case MessageCommandDefend: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("defend", &unit, status, -1, -1, &dest, NULL, -1);
				CommandDefend(unit, dest, status);
			}
			break;
		}
		case MessageCommandFollow: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("follow", &unit, status, -1, -1, &dest, NULL, -1);
				CommandFollow(unit, dest, status);
			}
			break;
		}
		case MessageCommandMove:
			//Wyrmgus start
//			CommandLog("move", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1);
//			CommandMove(unit, pos, status);
			if (!unit.CanMove()) { //FIXME: find better way to identify whether the unit should move or set a rally point
				CommandLog("rally-point", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1);
				CommandRallyPoint(unit, pos);
			} else {
				CommandLog("move", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1);
				CommandMove(unit, pos, status);
			}
			//Wyrmgus end
			break;
		//Wyrmgus start
		case MessageCommandPickUp: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("pick-up", &unit, status, -1, -1, &dest, NULL, -1);
				CommandPickUp(unit, dest, status);
			}
			break;
		}
		//Wyrmgus end
		case MessageCommandRepair: {
			CUnit *dest = NoUnitP;
			if (dstnr != (unsigned short)0xFFFF) {
				dest = &UnitManager.GetSlotUnit(dstnr);
				Assert(dest && dest->Type);
			}
			CommandLog("repair", &unit, status, pos.x, pos.y, dest, NULL, -1);
			CommandRepair(unit, pos, dest, status);
			break;
		}
		case MessageCommandAutoRepair:
			CommandLog("auto-repair", &unit, status, arg1, arg2, NoUnitP, NULL, 0);
			CommandAutoRepair(unit, arg1);
			break;
		case MessageCommandAttack: {
			CUnit *dest = NoUnitP;
			if (dstnr != (unsigned short)0xFFFF) {
				dest = &UnitManager.GetSlotUnit(dstnr);
				Assert(dest && dest->Type);
			}
			CommandLog("attack", &unit, status, pos.x, pos.y, dest, NULL, -1);
			CommandAttack(unit, pos, dest, status);
			break;
		}
		case MessageCommandGround:
			CommandLog("attack-ground", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1);
			CommandAttackGround(unit, pos, status);
			break;
		//Wyrmgus start
		case MessageCommandUse: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("use", &unit, status, -1, -1, &dest, NULL, -1);
				CommandUse(unit, dest, status);
			}
			break;
		}
		//Wyrmgus end
		case MessageCommandPatrol:
			CommandLog("patrol", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1);
			CommandPatrolUnit(unit, pos, status);
			break;
		case MessageCommandBoard: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("board", &unit, status, arg1, arg2, &dest, NULL, -1);
				CommandBoard(unit, dest, status);
			}
			break;
		}
		case MessageCommandUnload: {
			CUnit *dest = NULL;
			if (dstnr != (unsigned short)0xFFFF) {
				dest = &UnitManager.GetSlotUnit(dstnr);
				Assert(dest && dest->Type);
			}
			CommandLog("unload", &unit, status, pos.x, pos.y, dest, NULL, -1);
			CommandUnload(unit, pos, dest, status);
			break;
		}
		case MessageCommandBuild:
			CommandLog("build", &unit, status, pos.x, pos.y, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1);
			CommandBuildBuilding(unit, pos, *UnitTypes[dstnr], status);
			break;
		case MessageCommandDismiss:
			CommandLog("dismiss", &unit, FlushCommands, -1, -1, NULL, NULL, -1);
			CommandDismiss(unit);
			break;
		case MessageCommandResourceLoc:
			CommandLog("resource-loc", &unit, status, pos.x, pos.y, NoUnitP, NULL, -1);
			CommandResourceLoc(unit, pos, status);
			break;
		case MessageCommandResource: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("resource", &unit, status, -1, -1, &dest, NULL, -1);
				CommandResource(unit, dest, status);
			}
			break;
		}
		case MessageCommandReturn: {
			CUnit *dest = (dstnr != (unsigned short)0xFFFF) ? &UnitManager.GetSlotUnit(dstnr) : NULL;
			CommandLog("return", &unit, status, -1, -1, dest, NULL, -1);
			CommandReturnGoods(unit, dest, status);
			break;
		}
		case MessageCommandTrain:
			//Wyrmgus start
//			CommandLog("train", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), -1);
//			CommandTrainUnit(unit, *UnitTypes[dstnr], status);
			CommandLog("train", &unit, status, -1, -1, NoUnitP, UnitTypes[dstnr]->Ident.c_str(), arg1); // use X as a way to mark the player
			CommandTrainUnit(unit, *UnitTypes[dstnr], arg1, status);
			//Wyrmgus end
			break;
		case MessageCommandCancelTrain:
			// We need (short)x for the last slot -1
			if (dstnr != (unsigned short)0xFFFF) {
				CommandLog("cancel-train", &unit, FlushCommands, -1, -1, NoUnitP,
						   UnitTypes[dstnr]->Ident.c_str(), (short)x);
				CommandCancelTraining(unit, (short)x, UnitTypes[dstnr]);
			} else {
				CommandLog("cancel-train", &unit, FlushCommands, -1, -1, NoUnitP, NULL, (short)x);
				CommandCancelTraining(unit, (short)x, NULL);
			}
			break;
		case MessageCommandUpgrade:
			//Wyrmgus start
			/*
			CommandLog("upgrade-to", &unit, status, -1, -1, NoUnitP,
					   UnitTypes[dstnr]->Ident.c_str(), -1);
			CommandUpgradeTo(unit, *UnitTypes[dstnr], status);
			break;
			*/
			if (arg1 == 2) { //use X as a way to mark whether this is an upgrade or a transformation
				CommandLog("transform-into", &unit, status, -1, -1, NoUnitP,
						   UnitTypes[dstnr]->Ident.c_str(), -1);
				CommandTransformIntoType(unit, *UnitTypes[dstnr]);
			} else {
				CommandLog("upgrade-to", &unit, status, -1, -1, NoUnitP,
						   UnitTypes[dstnr]->Ident.c_str(), -1);
				CommandUpgradeTo(unit, *UnitTypes[dstnr], status);
			}
			break;
			//Wyrmgus end
		case MessageCommandCancelUpgrade:
			CommandLog("cancel-upgrade-to", &unit, FlushCommands, -1, -1, NoUnitP, NULL, -1);
			CommandCancelUpgradeTo(unit);
			break;
		case MessageCommandResearch:
			CommandLog("research", &unit, status, -1, -1, NoUnitP,
					   AllUpgrades[arg1]->Ident.c_str(), -1);
			CommandResearch(unit, *AllUpgrades[arg1], status);
			break;
		case MessageCommandCancelResearch:
			CommandLog("cancel-research", &unit, FlushCommands, -1, -1, NoUnitP, NULL, -1);
			CommandCancelResearch(unit);
			break;
		//Wyrmgus start
		case MessageCommandQuest: {
			CommandLog("quest", &unit, 0, 0, 0, NoUnitP, Quests[arg1]->Ident.c_str(), -1);
			CommandQuest(unit, Quests[arg1]);
			break;
		}
		case MessageCommandBuy: {
			if (dstnr != (unsigned short)0xFFFF) {
				CUnit &dest = UnitManager.GetSlotUnit(dstnr);
				Assert(dest.Type);
				CommandLog("buy", &unit, 0, -1, -1, &dest, NULL, arg1);
				CommandBuy(unit, &dest, arg1);
			}
			break;
		}
		//Wyrmgus end
		default: {
			int id = (msgnr & 0x7f) - MessageCommandSpellCast;
			if (arg2 != (unsigned short)0xFFFF) {
				CUnit *dest = NULL;
				if (dstnr != (unsigned short)0xFFFF) {
					dest = &UnitManager.GetSlotUnit(dstnr);
					Assert(dest && dest->Type);
				}
				CommandLog("spell-cast", &unit, status, pos.x, pos.y, dest, NULL, id);
				CommandSpellCast(unit, pos, dest, *SpellTypeTable[id], status);
			} else {
				CommandLog("auto-spell-cast", &unit, status, arg1, -1, NoUnitP, NULL, id);
				CommandAutoSpellCast(unit, id, arg1);
			}
			break;
		}
	}
}
Example #3
0
/**
**  Assign workers to collect resources.
**
**  If we have a shortage of a resource, let many workers collecting this.
**  If no shortage, split workers to all resources.
*/
static void AiCollectResources()
{
	CUnit *units_with_resource[MaxCosts][UnitMax]; // Worker with resource
	CUnit *units_assigned[MaxCosts][UnitMax]; // Worker assigned to resource
	CUnit *units_unassigned[MaxCosts][UnitMax]; // Unassigned workers
	int num_units_with_resource[MaxCosts];
	int num_units_assigned[MaxCosts];
	int num_units_unassigned[MaxCosts];
	int c;
	int src_c;
	int i;
	int j;
	int k;
	int n;
	CUnit **units;
	int percent[MaxCosts];
	int percent_total;

	int priority_resource[MaxCosts];
	int priority_needed[MaxCosts];
	int wanted[MaxCosts];
	int total_harvester;

	memset(num_units_with_resource, 0, sizeof(num_units_with_resource));
	memset(num_units_unassigned, 0, sizeof(num_units_unassigned));
	memset(num_units_assigned, 0, sizeof(num_units_assigned));

	//
	// Collect statistics about the current assignment
	//
	total_harvester = 0;

	n = AiPlayer->Player->TotalNumUnits;
	units = AiPlayer->Player->Units;
	for (i = 0; i < n; ++i) {
		CUnit &unit = *units[i];
		if (!unit.Type->Harvester) {
			continue;
		}

		c = unit.CurrentResource;

		//
		// See if it's assigned already
		//
		if (c && unit.OrderCount == 1 &&
			unit.CurrentAction() == UnitActionResource) {
			units_assigned[c][num_units_assigned[c]++] = &unit;
			total_harvester++;
			continue;
		}

		//
		// Ignore busy units. ( building, fighting, ... )
		//
		if (!unit.IsIdle()) {
			continue;
		}

		//
		// Send workers with resources back home.
		//
		if (unit.ResourcesHeld && c) {
			units_with_resource[c][num_units_with_resource[c]++] = &unit;
			CommandReturnGoods(unit, 0, FlushCommands);
			total_harvester++;
			continue;
		}

		//
		// Look what the unit can do
		//
		for (c = 1; c < MaxCosts; ++c) {
			if (unit.Type->ResInfo[c]) {
				units_unassigned[c][num_units_unassigned[c]++] = &unit;
			}
		}
		++total_harvester;
	}

	if(!total_harvester) {
		return;
	}

	memset(wanted, 0, sizeof(wanted));

	percent_total = 100;
	for (c = 1; c < MaxCosts; ++c) {
		percent[c] = AiPlayer->Collect[c];
		if ((AiPlayer->NeededMask & (1 << c))) { // Double percent if needed
			percent_total += percent[c];
			percent[c] <<= 1;
		}
	}

	//
	// Turn percent values into harvester numbers.
	//
	for (c = 1; c < MaxCosts; ++c ) {
		if(percent[c]) {
			// Wanted needs to be representative.
			if (total_harvester < 5) {
				wanted[c] = 1 + (percent[c] * 5) / percent_total;
			} else {
				wanted[c] = 1 + (percent[c] * total_harvester) / percent_total;
			}
		}
	}

	//
	// Initialise priority & mapping
	//
	for (c = 0; c < MaxCosts; ++c) {
		priority_resource[c] = c;
		priority_needed[c] = wanted[c] - num_units_assigned[c] - num_units_with_resource[c];

		if (c && num_units_assigned[c] > 1) {
			//first should go workers with lower ResourcesHeld value
			qsort(units_assigned[c], num_units_assigned[c],
							 sizeof(CUnit*), CmpWorkers);
		}

	}
	CUnit* unit;
	do {
		//
		// sort resources by priority
		//
		for (i = 0; i < MaxCosts; ++i) {
			for (j = i + 1; j < MaxCosts; ++j) {
				if (priority_needed[j] > priority_needed[i]) {
					c = priority_needed[j];
					priority_needed[j] = priority_needed[i];
					priority_needed[i] = c;
					c = priority_resource[j];
					priority_resource[j] = priority_resource[i];
					priority_resource[i] = c;
				}
			}
		}
		unit = NoUnitP;
		//
		// Try to complete each ressource in the priority order
		//

		for (i = 0; i < MaxCosts; ++i) {
			c = priority_resource[i];

			//
			// If there is a free worker for c, take it.
			//
			if (num_units_unassigned[c]) {
				// Take the unit.
				j = 0;
				while (j < num_units_unassigned[c] && !AiAssignHarvester(*units_unassigned[c][j], c)) {
					// can't assign to c => remove from units_unassigned !
					units_unassigned[c][j] = units_unassigned[c][--num_units_unassigned[c]];
				}

				// unit is assigned
				if (j < num_units_unassigned[c]) {
					unit = units_unassigned[c][j];
					units_unassigned[c][j] = units_unassigned[c][--num_units_unassigned[c]];

					// remove it from other ressources
					for (j = 0; j < MaxCosts; ++j) {
						if (j == c || !unit->Type->ResInfo[j]) {
							continue;
						}
						for (k = 0; k < num_units_unassigned[j]; ++k) {
							if (units_unassigned[j][k] == unit) {
								units_unassigned[j][k] = units_unassigned[j][--num_units_unassigned[j]];
								break;
							}
						}
					}
				}
			}

			//
			// Else : Take from already assigned worker with lower priority.
			//
			if (!unit) {
				// Take from lower priority only (i+1).
				for (j = i + 1; j < MaxCosts && !unit; ++j) {
					// Try to move worker from src_c to c
					src_c = priority_resource[j];

					// Don't complete with lower priority ones...
					if (wanted[src_c] > wanted[c] ||
							(wanted[src_c] == wanted[c] &&
								num_units_assigned[src_c] <= num_units_assigned[c] + 1)) {
						continue;
					}

					for (k = num_units_assigned[src_c] - 1; k >= 0 && !unit; --k) {
						unit = units_assigned[src_c][k];

						if (unit->SubAction >= 65 /* SUB_STOP_GATHERING */ ) {
							//worker returning with resource
							continue;
						}

						// unit can't harvest : next one
						if (!unit->Type->ResInfo[c] || !AiAssignHarvester(*unit, c)) {
							unit = NoUnitP;
							continue;
						}

						// Remove from src_c
						units_assigned[src_c][k] = units_assigned[src_c][--num_units_assigned[src_c]];

						// j need one more
						priority_needed[j]++;
					}
				}
			}

			//
			// We just moved an unit. Adjust priority & retry
			//
			if (unit) {
				// i got a new unit.
				priority_needed[i]--;

				// Add to the assigned
				units_assigned[c][num_units_assigned[c]++] = unit;

				// Recompute priority now
				break;
			}
		}
	} while (unit);

	// Unassigned units there can't be assigned ( ie : they can't move to ressource )
	// IDEA : use transporter here.
}
Example #4
0
/**
**  Assign workers to collect resources.
**
**  If we have a shortage of a resource, let many workers collecting this.
**  If no shortage, split workers to all resources.
*/
static void AiCollectResources()
{
    std::vector<CUnit *> units_assigned[MaxCosts]; // Worker assigned to resource
    std::vector<CUnit *> units_unassigned[MaxCosts]; // Unassigned workers
    int num_units_with_resource[MaxCosts];
    int num_units_assigned[MaxCosts];
    int num_units_unassigned[MaxCosts];
    int percent[MaxCosts];
    int priority_resource[MaxCosts];
    int priority_needed[MaxCosts];
    int wanted[MaxCosts];
    int total_harvester = 0;

    memset(num_units_with_resource, 0, sizeof(num_units_with_resource));
    memset(num_units_unassigned, 0, sizeof(num_units_unassigned));
    memset(num_units_assigned, 0, sizeof(num_units_assigned));

    // Collect statistics about the current assignment
    const int n = AiPlayer->Player->GetUnitCount();
    for (int i = 0; i < n; ++i) {
        CUnit &unit = AiPlayer->Player->GetUnit(i);
        if (!unit.Type->Harvester) {
            continue;
        }

        // See if it's assigned already
        if (unit.Orders.size() == 1 &&
                unit.CurrentAction() == UnitActionResource) {
            const COrder_Resource &order = *static_cast<COrder_Resource *>(unit.CurrentOrder());
            const int c = order.GetCurrentResource();
            units_assigned[c].push_back(&unit);
            num_units_assigned[c]++;
            total_harvester++;
            continue;
        }

        // Ignore busy units. ( building, fighting, ... )
        if (!unit.IsIdle()) {
            continue;
        }

        // Send workers with resources back home.
        if (unit.ResourcesHeld) {
            const int c = unit.CurrentResource;

            num_units_with_resource[c]++;
            CommandReturnGoods(unit, 0, FlushCommands);
            total_harvester++;
            continue;
        }

        // Look what the unit can do
        for (int c = 1; c < MaxCosts; ++c) {
            if (unit.Type->ResInfo[c]) {
                units_unassigned[c].push_back(&unit);
                num_units_unassigned[c]++;
            }
        }
        ++total_harvester;
    }

    if (!total_harvester) {
        return;
    }

    memset(wanted, 0, sizeof(wanted));

    int percent_total = 100;
    for (int c = 1; c < MaxCosts; ++c) {
        percent[c] = AiPlayer->Collect[c];
        if ((AiPlayer->NeededMask & (1 << c))) { // Double percent if needed
            percent_total += percent[c];
            percent[c] <<= 1;
        }
    }

    // Turn percent values into harvester numbers.
    for (int c = 1; c < MaxCosts; ++c) {
        if (percent[c]) {
            // Wanted needs to be representative.
            if (total_harvester < 5) {
                wanted[c] = 1 + (percent[c] * 5) / percent_total;
            } else {
                wanted[c] = 1 + (percent[c] * total_harvester) / percent_total;
            }
        }
    }

    // Initialise priority & mapping
    for (int c = 0; c < MaxCosts; ++c) {
        priority_resource[c] = c;
        priority_needed[c] = wanted[c] - num_units_assigned[c] - num_units_with_resource[c];

        if (c && num_units_assigned[c] > 1) {
            //first should go workers with lower ResourcesHeld value
            std::sort(units_assigned[c].begin(), units_assigned[c].end(), CmpWorkers);
        }
    }
    CUnit *unit;
    do {
        // sort resources by priority
        for (int i = 0; i < MaxCosts; ++i) {
            for (int j = i + 1; j < MaxCosts; ++j) {
                if (priority_needed[j] > priority_needed[i]) {
                    std::swap(priority_needed[i], priority_needed[j]);
                    std::swap(priority_resource[i], priority_resource[j]);
                }
            }
        }
        unit = NULL;

        // Try to complete each ressource in the priority order
        for (int i = 0; i < MaxCosts; ++i) {
            int c = priority_resource[i];

            // If there is a free worker for c, take it.
            if (num_units_unassigned[c]) {
                // Take the unit.
                while (0 < num_units_unassigned[c] && !AiAssignHarvester(*units_unassigned[c][0], c)) {
                    // can't assign to c => remove from units_unassigned !
                    units_unassigned[c][0] = units_unassigned[c][--num_units_unassigned[c]];
                    units_unassigned[c].pop_back();
                }

                // unit is assigned
                if (0 < num_units_unassigned[c]) {
                    unit = units_unassigned[c][0];
                    units_unassigned[c][0] = units_unassigned[c][--num_units_unassigned[c]];
                    units_unassigned[c].pop_back();

                    // remove it from other ressources
                    for (int j = 0; j < MaxCosts; ++j) {
                        if (j == c || !unit->Type->ResInfo[j]) {
                            continue;
                        }
                        for (int k = 0; k < num_units_unassigned[j]; ++k) {
                            if (units_unassigned[j][k] == unit) {
                                units_unassigned[j][k] = units_unassigned[j][--num_units_unassigned[j]];
                                units_unassigned[j].pop_back();
                                break;
                            }
                        }
                    }
                }
            }

            // Else : Take from already assigned worker with lower priority.
            if (!unit) {
                // Take from lower priority only (i+1).
                for (int j = i + 1; j < MaxCosts && !unit; ++j) {
                    // Try to move worker from src_c to c
                    const int src_c = priority_resource[j];

                    // Don't complete with lower priority ones...
                    if (wanted[src_c] > wanted[c]
                            || (wanted[src_c] == wanted[c]
                                && num_units_assigned[src_c] <= num_units_assigned[c] + 1)) {
                        continue;
                    }

                    for (int k = num_units_assigned[src_c] - 1; k >= 0 && !unit; --k) {
                        unit = units_assigned[src_c][k];

                        Assert(unit->CurrentAction() == UnitActionResource);
                        COrder_Resource &order = *static_cast<COrder_Resource *>(unit->CurrentOrder());

                        if (order.IsGatheringFinished()) {
                            //worker returning with resource
                            continue;
                        }

                        // unit can't harvest : next one
                        if (!unit->Type->ResInfo[c] || !AiAssignHarvester(*unit, c)) {
                            unit = NULL;
                            continue;
                        }

                        // Remove from src_c
                        units_assigned[src_c][k] = units_assigned[src_c][--num_units_assigned[src_c]];
                        units_assigned[src_c].pop_back();

                        // j need one more
                        priority_needed[j]++;
                    }
                }
            }

            // We just moved an unit. Adjust priority & retry
            if (unit) {
                // i got a new unit.
                priority_needed[i]--;
                // Recompute priority now
                break;
            }
        }
    } while (unit);

    // Unassigned units there can't be assigned ( ie : they can't move to ressource )
    // IDEA : use transporter here.
}
Example #5
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;
}
Example #6
0
/**
**  Assign workers to collect resources.
**
**  If we have a shortage of a resource, let many workers collecting this.
**  If no shortage, split workers to all resources.
*/
static void AiCollectResources()
{
	std::vector<CUnit *> units_assigned[MaxCosts]; // Worker assigned to resource
	std::vector<CUnit *> units_unassigned[MaxCosts]; // Unassigned workers
	int num_units_with_resource[MaxCosts];
	int num_units_assigned[MaxCosts];
	int num_units_unassigned[MaxCosts];
	int percent[MaxCosts];
	int priority_resource[MaxCosts];
	int priority_needed[MaxCosts];
	int wanted[MaxCosts];
	int total_harvester = 0;

	memset(num_units_with_resource, 0, sizeof(num_units_with_resource));
	memset(num_units_unassigned, 0, sizeof(num_units_unassigned));
	memset(num_units_assigned, 0, sizeof(num_units_assigned));

	// Collect statistics about the current assignment
	const int n = AiPlayer->Player->GetUnitCount();
	for (int i = 0; i < n; ++i) {
		CUnit &unit = AiPlayer->Player->GetUnit(i);
		//Wyrmgus start
//		if (!unit.Type->BoolFlag[HARVESTER_INDEX].value) {
		if (!unit.Type->BoolFlag[HARVESTER_INDEX].value || !unit.Active) {
		//Wyrmgus end
			continue;
		}

		// See if it's assigned already
		if (unit.Orders.size() == 1 &&
			unit.CurrentAction() == UnitActionResource) {
			const COrder_Resource &order = *static_cast<COrder_Resource *>(unit.CurrentOrder());
			const int c = order.GetCurrentResource();
			units_assigned[c].push_back(&unit);
			num_units_assigned[c]++;
			total_harvester++;
			continue;
		}

		// Ignore busy units. ( building, fighting, ... )
		if (!unit.IsIdle()) {
			continue;
		}

		// Send workers with resources back home.
		if (unit.ResourcesHeld) {
			const int c = unit.CurrentResource;

			num_units_with_resource[c]++;
			CommandReturnGoods(unit, 0, FlushCommands);
			total_harvester++;
			continue;
		}

		// Look what the unit can do
		for (int c = 1; c < MaxCosts; ++c) {
			if (unit.Type->ResInfo[c]) {
				units_unassigned[c].push_back(&unit);
				num_units_unassigned[c]++;
			}
		}
		++total_harvester;
	}

	if (!total_harvester) {
		return;
	}

	memset(wanted, 0, sizeof(wanted));

	int percent_total = 100;
	for (int c = 1; c < MaxCosts; ++c) {
		percent[c] = AiPlayer->Collect[c];
		if ((AiPlayer->NeededMask & (1 << c))) { // Double percent if needed
			percent_total += percent[c];
			percent[c] <<= 1;
		}
	}

	// Turn percent values into harvester numbers.
	for (int c = 1; c < MaxCosts; ++c) {
		if (percent[c]) {
			// Wanted needs to be representative.
			if (total_harvester < 5) {
				wanted[c] = 1 + (percent[c] * 5) / percent_total;
			} else {
				wanted[c] = 1 + (percent[c] * total_harvester) / percent_total;
			}
		}
	}

	// Initialise priority & mapping
	for (int c = 0; c < MaxCosts; ++c) {
		priority_resource[c] = c;
		priority_needed[c] = wanted[c] - num_units_assigned[c] - num_units_with_resource[c];

		if (c && num_units_assigned[c] > 1) {
			//first should go workers with lower ResourcesHeld value
			std::sort(units_assigned[c].begin(), units_assigned[c].end(), CmpWorkers);
		}
	}
	CUnit *unit;
	do {
		// sort resources by priority
		for (int i = 0; i < MaxCosts; ++i) {
			for (int j = i + 1; j < MaxCosts; ++j) {
				if (priority_needed[j] > priority_needed[i]) {
					std::swap(priority_needed[i], priority_needed[j]);
					std::swap(priority_resource[i], priority_resource[j]);
				}
			}
		}
		unit = NULL;

		// Try to complete each resource in the priority order
		for (int i = 0; i < MaxCosts; ++i) {
			int c = priority_resource[i];

			// If there is a free worker for c, take it.
			if (num_units_unassigned[c]) {
				// Take the unit.
				while (0 < num_units_unassigned[c] && !AiAssignHarvester(*units_unassigned[c][0], c)) {
					// can't assign to c => remove from units_unassigned !
					units_unassigned[c][0] = units_unassigned[c][--num_units_unassigned[c]];
					units_unassigned[c].pop_back();
				}

				// unit is assigned
				if (0 < num_units_unassigned[c]) {
					unit = units_unassigned[c][0];
					units_unassigned[c][0] = units_unassigned[c][--num_units_unassigned[c]];
					units_unassigned[c].pop_back();

					// remove it from other ressources
					for (int j = 0; j < MaxCosts; ++j) {
						if (j == c || !unit->Type->ResInfo[j]) {
							continue;
						}
						for (int k = 0; k < num_units_unassigned[j]; ++k) {
							if (units_unassigned[j][k] == unit) {
								units_unassigned[j][k] = units_unassigned[j][--num_units_unassigned[j]];
								units_unassigned[j].pop_back();
								break;
							}
						}
					}
				}
			}

			// Else : Take from already assigned worker with lower priority.
			if (!unit) {
				// Take from lower priority only (i+1).
				for (int j = i + 1; j < MaxCosts && !unit; ++j) {
					// Try to move worker from src_c to c
					const int src_c = priority_resource[j];

					//Wyrmgus start
					//don't reassign workers from one resource to another, that is too expensive performance-wise (this could be re-implemented if the AI is altered to keep track of found resource spots
					break;
					//Wyrmgus end
					
					//Wyrmgus start
					// don't reassign if the src_c resource has no workers, or if the new resource has 0 "wanted"
					if (num_units_assigned[src_c] == 0 || !wanted[c]) {
						continue;
					}
					//Wyrmgus end

					// Don't complete with lower priority ones...
					//Wyrmgus start
					/*
					if (wanted[src_c] > wanted[c]
						|| (wanted[src_c] == wanted[c]
							&& num_units_assigned[src_c] <= num_units_assigned[c] + 1)) {
					*/
					if (wanted[src_c] && ((num_units_assigned[src_c] + 1) * 100 / wanted[src_c]) <= (num_units_assigned[c] * 100 / wanted[c])) { // what matters is the percent of "wanted" fulfilled, not the absolute quantity of needed workers for that resource; add one worker to num_units_assigned[src_c] so that you won't get one worker being shuffled back and forth
					//Wyrmgus end
						//Wyrmgus start
//						continue;
						if (num_units_assigned[c] != 0) { // if there are no workers for that resource, allow reshuffling regardless of proportion calculation, so that if the game starts with few workers (like two), the AI isn't stuck gathering only the first resource it finds
							continue;
						}
						//Wyrmgus end
					}
					
					//Wyrmgus start
					if (num_units_assigned[src_c] <= wanted[src_c]) { // don't reassign if the src_c resource already has less workers than desired
						if (num_units_assigned[c] != 0) {
							continue;
						}
					}
					//Wyrmgus end
					
					//Wyrmgus start
//					for (int k = num_units_assigned[src_c] - 1; k >= 0 && !unit; --k) {
					for (int k = num_units_assigned[src_c] - 1; k >= 0; --k) { // unit may be NULL now, continue instead of breaking loop if so
					//Wyrmgus end
						unit = units_assigned[src_c][k];
						//Wyrmgus start
						if (!unit) {
							continue;
						}
						//Wyrmgus end

						Assert(unit->CurrentAction() == UnitActionResource);
						COrder_Resource &order = *static_cast<COrder_Resource *>(unit->CurrentOrder());

						if (order.IsGatheringFinished()) {
							//worker returning with resource
							continue;
						}

						//Wyrmgus start
						if (unit->Removed || unit->CurrentAction() == UnitActionBuild) { //if unit is removed or is currently building something, it can't be told to harvest (do this here so that AiAssignHarvester returning false later on is only because of unit type not being able to harvest something)
							unit = NULL;
							continue;
						}
						//Wyrmgus end
						
						// unit can't harvest : next one
						if (!unit->Type->ResInfo[c] || !AiAssignHarvester(*unit, c)) {
							unit = NULL;
							continue;
						}

						// Remove from src_c
						units_assigned[src_c][k] = units_assigned[src_c][--num_units_assigned[src_c]];
						units_assigned[src_c].pop_back();

						// j need one more
						priority_needed[j]++;
						
						//Wyrmgus start
						break; //only reassign one worker per time
						//Wyrmgus end
					}
				}
			}

			// We just moved an unit. Adjust priority & retry
			if (unit) {
				// i got a new unit.
				priority_needed[i]--;
				// Recompute priority now
				break;
			}
		}
	} while (unit);

	// Unassigned units there can't be assigned ( ie : they can't move to ressource )
	// IDEA : use transporter here.
}