/** ** 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; } }
/** ** Check if the unit can build ** ** @param unit Unit to check */ CUnit *COrder_Build::CheckCanBuild(CUnit &unit) { const Vec2i pos = this->goalPos; const CUnitType &type = this->GetUnitType(); // Check if the building could be built there. CUnit *ontop = CanBuildUnitType(&unit, type, pos, 1); if (ontop != NULL) { return ontop; } #if 0 /* * FIXME: rb - CheckAlreadyBuilding should be somehow * enabled/disable via game lua scripting */ CUnit *building = AlreadyBuildingFinder(unit, type).Find(Map.Field(pos)); if (building != NULL) { if (unit.CurrentOrder() == this) { DebugPrint("%d: Worker [%d] is helping build: %s [%d]\n" _C_ unit.Player->Index _C_ unit.Slot _C_ building->Type->Name.c_str() _C_ building->Slot); delete this; // Bad unit.Orders[0] = COrder::NewActionRepair(unit, *building); return NULL; } } #endif // Some tries to build the building. this->State++; // To keep the load low, retry each 10 cycles // NOTE: we can already inform the AI about this problem? unit.Wait = 10; return NULL; }
/** ** Find free building place. (flood fill version) ** ** @param worker Worker to build building. ** @param type Type of building. ** @param ox Original X position to try building ** @param oy Original Y position to try building ** @param dpos Pointer for position returned. ** ** @return True if place found, false if no found. */ static int AiFindBuildingPlace2(const CUnit &worker, const CUnitType &type, int ox, int oy, Vec2i *dpos) { const Vec2i offset[] = {{0, -1}, {-1, 0}, {1, 0}, {0, 1}, {-1, -1}, {1, -1}, {-1, 1}, {1, 1}}; Vec2i *points; int size; Vec2i pos = {ox, oy}; Vec2i rpos; int mask; int wp; int rp; int ep; unsigned char *m; Vec2i backupPos = {-1, -1}; bool backupok; // // Look if we can build at current place. // if (CanBuildUnitType(&worker, type, pos, 1) && !AiEnemyUnitsInDistance(worker.Player, NULL, pos, 8)) { if (AiCheckSurrounding(worker, type, pos.x, pos.y, backupok)) { *dpos = pos; return 1; } else if (backupok) { backupPos = pos; } } size = Map.Info.MapWidth * Map.Info.MapHeight / 4; points = new Vec2i[size]; // // Make movement matrix. // unsigned char *matrix = CreateMatrix(); const int w = Map.Info.MapWidth + 2; mask = worker.Type->MovementMask; // Ignore all possible mobile units. mask &= ~(MapFieldLandUnit | MapFieldAirUnit | MapFieldSeaUnit); points[0] = pos; // also use the bottom right if ((type.TileWidth > 1 || type.TileHeight > 1) && pos.x + type.TileWidth - 1 < Map.Info.MapWidth && pos.y + type.TileHeight - 1 < Map.Info.MapHeight) { points[1].x = pos.x + type.TileWidth - 1; points[1].y = pos.y + type.TileHeight - 1; ep = wp = 2; // start with two points } else { ep = wp = 1; // start with one point } matrix += w + w + 2; rp = 0; matrix[pos.x + pos.y * w] = 1; // mark start point // // Pop a point from stack, push all neighbours which could be entered. // for (;;) { while (rp != ep) { rpos = points[rp]; for (int i = 0; i < 8; ++i) { // mark all neighbors pos = rpos + offset[i]; m = matrix + pos.x + pos.y * w; if (*m) { // already checked continue; } // // Look if we can build here and no enemies nearby. // if (CanBuildUnitType(&worker, type, pos, 1) && !AiEnemyUnitsInDistance(worker.Player, NULL, pos, 8)) { if (AiCheckSurrounding(worker, type, pos.x, pos.y, backupok)) { *dpos = pos; delete[] points; return 1; } else if (backupok && backupPos.x == -1) { backupPos = pos; } } if (CanMoveToMask(pos, mask)) { // reachable *m = 1; points[wp] = pos; // push the point if (++wp >= size) { // round about wp = 0; } } else { // unreachable *m = 99; } } if (++rp >= size) { // round about rp = 0; } } // // Continue with next frame. // if (rp == wp) { // unreachable, no more points available break; } ep = wp; } delete[] points; if (backupPos.x != -1) { *dpos = backupPos; return 1; } return 0; }
//Wyrmgus start //static int AiAssignHarvesterFromUnit(CUnit &unit, int resource) static int AiAssignHarvesterFromUnit(CUnit &unit, int resource, int resource_range) //Wyrmgus end { // Try to find the nearest depot first. CUnit *depot = FindDeposit(unit, 1000, resource); // Find a resource to harvest from. //Wyrmgus start // CUnit *mine = UnitFindResource(unit, depot ? *depot : unit, 1000, resource, true); CUnit *mine = UnitFindResource(unit, depot ? *depot : unit, resource_range, resource, true, NULL, false); //Wyrmgus end if (mine) { //Wyrmgus start // CommandResource(unit, *mine, FlushCommands); // return 1; if (mine->Type->BoolFlag[CANHARVEST_INDEX].value) { CommandResource(unit, *mine, FlushCommands); return 1; } else { // if the resource isn't readily harvestable (but is a deposit), build a mine there const int n = AiHelpers.Refinery[resource - 1].size(); for (int i = 0; i < n; ++i) { CUnitType &type = *AiHelpers.Refinery[resource - 1][i]; if (CanBuildUnitType(&unit, type, mine->tilePos, 1, true, mine->MapLayer)) { CommandBuildBuilding(unit, mine->tilePos, type, FlushCommands, mine->MapLayer); return 1; } } } //Wyrmgus end } //Wyrmgus start /* int exploremask = 0; for (size_t i = 0; i != UnitTypes.size(); ++i) { const CUnitType *type = UnitTypes[i]; if (type && type->GivesResource == resource) { switch (type->UnitType) { case UnitTypeLand: exploremask |= MapFieldLandUnit; break; case UnitTypeFly: exploremask |= MapFieldAirUnit; break; //Wyrmgus start case UnitTypeFlyLow: exploremask |= MapFieldLandUnit; break; //Wyrmgus end case UnitTypeNaval: exploremask |= MapFieldSeaUnit; break; default: Assert(0); } } } // Ask the AI to explore AiExplore(unit.tilePos, exploremask); */ //Wyrmgus end // Failed. return 0; }
//Wyrmgus start //void EditorChangeTile(const Vec2i &pos, int tileIndex, int d) void EditorChangeTile(const Vec2i &pos, int tileIndex) //Wyrmgus end { //Wyrmgus start // Assert(Map.Info.IsPointOnMap(pos)); Assert(Map.Info.IsPointOnMap(pos, CurrentMapLayer)); //Wyrmgus end // Change the flags //Wyrmgus start // CMapField &mf = *Map.Field(pos); CMapField &mf = *Map.Field(pos, CurrentMapLayer); //Wyrmgus end int tile = tileIndex; if (TileToolRandom) { int n = 0; for (int i = 0; i < 16; ++i) { if (!Map.Tileset->tiles[tile + i].tile) { break; } else { ++n; } } n = MyRand() % n; int i = -1; do { while (++i < 16 && !Map.Tileset->tiles[tile + i].tile) { } } while (i < 16 && n--); Assert(i != 16); tile += i; } //Wyrmgus start mf.setTileIndex(*Map.Tileset, tile, 0); // mf.playerInfo.SeenTile = mf.getGraphicTile(); mf.UpdateSeenTile(); //Wyrmgus end //Wyrmgus start Map.CalculateTileTransitions(pos, false, CurrentMapLayer); Map.CalculateTileTransitions(pos, true, CurrentMapLayer); for (int x_offset = -1; x_offset <= 1; ++x_offset) { for (int y_offset = -1; y_offset <= 1; ++y_offset) { if (x_offset != 0 || y_offset != 0) { Vec2i adjacent_pos(pos.x + x_offset, pos.y + y_offset); if (Map.Info.IsPointOnMap(adjacent_pos, CurrentMapLayer)) { Map.CalculateTileTransitions(adjacent_pos, false, CurrentMapLayer); Map.CalculateTileTransitions(adjacent_pos, true, CurrentMapLayer); } } } } //Wyrmgus end //Wyrmgus start CUnitCache &unitcache = mf.UnitCache; std::vector<CUnit *> units_to_remove; for (CUnitCache::iterator it = unitcache.begin(); it != unitcache.end(); ++it) { CUnit *unit = *it; if (!CanBuildUnitType(unit, *unit->Type, pos, 1, true, CurrentMapLayer)) { units_to_remove.push_back(unit); } } for (size_t i = 0; i < units_to_remove.size(); ++i) { EditorActionRemoveUnit(*units_to_remove[i], false); } //Wyrmgus end UI.Minimap.UpdateSeenXY(pos); //Wyrmgus start // UI.Minimap.UpdateXY(pos); UI.Minimap.UpdateXY(pos, CurrentMapLayer); //Wyrmgus end //Wyrmgus start // EditorChangeSurrounding(pos, d); EditorChangeSurrounding(pos, tile); //Wyrmgus end }