/** * Transform an MCV into Construction Yard. * * Stack: *none*. * * @param script The script engine to operate on. * @return 1 if and only if the transformation succeeded. */ uint16 Script_Unit_MCVDeploy(ScriptEngine *script) { Unit *u; Structure *s = NULL; uint16 i; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; Unit_UpdateMap(0, u); uint houseID = Unit_GetHouseID(u); uint tile = Tile_PackTile(u->o.position); for (i = 0; i < 4; i++) { static int8 offsets[4] = { 0, -1, -64, -65 }; s = Structure_Create(STRUCTURE_INDEX_INVALID, STRUCTURE_CONSTRUCTION_YARD, houseID, tile + offsets[i]); if (s != NULL) { Unit_Remove(u); return 1; } } if (houseID == g_playerHouseID) { GUI_DisplayText(String_Get_ByIndex(STR_UNIT_IS_UNABLE_TO_DEPLOY_HERE), 0); } Unit_UpdateMap(1, u); return 0; }
static void Skirmish_DivideIsland(HouseType houseID, int island, SkirmishData* sd) { int start = sd->island[island].start; const int len = sd->island[island].end - sd->island[island].start; BuildableTile* orig = (BuildableTile*)malloc(len * sizeof(orig[0])); memcpy(orig, sd->buildable + start, len * sizeof(orig[0])); for (int i = 0; i < len; i++) { const int area = Skirmish_FindBuildableArea(island, orig[i].x, orig[i].y, sd, sd->buildable + start); if (area >= 50) { sd->island = (Island*)realloc(sd->island, (sd->nislands + 1) * sizeof(sd->island[0])); assert(sd->island != NULL); sd->island[sd->nislands].start = start; sd->island[sd->nislands].end = start + area; sd->island[sd->nislands].used = false; start += area; sd->nislands++; sd->nislands_unused++; } else if (area > 0 && houseID != HOUSE_INVALID) { /* Fill enclosed areas with walls to prevent units getting trapped. */ if (Skirmish_IsIslandEnclosed(start, start + area, sd)) { g_validateStrictIfZero++; for (int j = start; j < start + area; j++) { Structure_Create(STRUCTURE_INDEX_INVALID, STRUCTURE_WALL, houseID, sd->buildable[j].packed); } g_validateStrictIfZero--; } } } sd->island[island].used = true; sd->nislands_unused--; free(orig); }
static void Scenario_Load_Structure(const char *key, char *settings) { uint8 index, houseType, structureType; uint16 hitpoints, position; char *split; /* 'GEN' marked keys are Slabs and Walls, where the number following indicates the position on the map */ if (strncasecmp(key, "GEN", 3) == 0) { /* Position on the map is in the key */ position = atoi(key + 3); /* The value should have two values separated by a ',' */ split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* First value is the House type */ houseType = House_StringToType(settings); if (houseType == HOUSE_INVALID) return; /* Second value is the Structure type */ settings = split + 1; structureType = Structure_StringToType(settings); if (structureType == STRUCTURE_INVALID) return; Structure_Create(STRUCTURE_INDEX_INVALID, structureType, houseType, position); return; } /* The key should start with 'ID', followed by the index */ index = atoi(key + 2); /* The value should have four values separated by a ',' */ split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* First value is the House type */ houseType = House_StringToType(settings); if (houseType == HOUSE_INVALID) return; /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Second value is the Structure type */ structureType = Structure_StringToType(settings); if (structureType == STRUCTURE_INVALID) return; /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Third value is the Hitpoints in percent (in base 256) */ hitpoints = atoi(settings); /* ENHANCEMENT -- Dune2 ignores the % hitpoints read from the scenario */ if (!g_dune2_enhanced) hitpoints = 256; /* Fourth value is the position of the structure */ settings = split + 1; position = atoi(settings); /* Ensure nothing is already on the tile */ /* XXX -- DUNE2 BUG? -- This only checks the top-left corner? Not really a safety, is it? */ if (Structure_Get_ByPackedTile(position) != NULL) return; { Structure *s; s = Structure_Create(index, structureType, houseType, position); if (s == NULL) return; s->o.hitpoints = hitpoints * g_table_structureInfo[s->o.type].o.hitpoints / 256; s->o.flags.s.degrades = false; s->state = STRUCTURE_STATE_IDLE; } }
static bool Skirmish_GenStructuresAI(HouseType houseID, SkirmishData* sd) { uint16 tech_level = 0; uint16 structure = 0; int structure_count = 0; int structure_threshold = 100; int cpu_count = 0; for (HouseType h = HOUSE_HARKONNEN; h < HOUSE_MAX; h++) { if (g_skirmish.brain[h] == BRAIN_CPU_ENEMY || g_skirmish.brain[h] == BRAIN_CPU_ALLY) cpu_count++; } assert(cpu_count != 0); const int max_structure_count = 60 / cpu_count; /* First pass finds out what to build. */ tech_level = 0; structure = 0; structure_count = 0; for (structure = 0; (structure < lengthof(buildorder)) && (tech_level <= g_techLevel); structure++) { if (buildorder[structure].type == STRUCTURE_INVALID) tech_level++; else if ((buildorder[structure].availableHouse & (1 << houseID)) != 0) structure_count++; } if (structure_count > max_structure_count) { structure_count = max_structure_count; SkirmishBuildOrder* bo = (SkirmishBuildOrder*)malloc(structure * sizeof(SkirmishBuildOrder)); assert(bo != NULL); memcpy(bo, buildorder, structure * sizeof(SkirmishBuildOrder)); qsort(bo, structure, sizeof(SkirmishBuildOrder), Skirmish_BuildOrder_Sorter); structure_threshold = bo[structure_count].priority; free(bo); } /* Second pass builds structures below the threshold priority. */ tech_level = 0; structure = 0; for (int attempts = 0; attempts < 100; attempts++) { int island = Skirmish_PickRandomIsland(sd); int range = 8; if (island < 0) return false; /* Re-flood-fill the island, using a new starting point. */ { const int r = Tools_RandomLCG_Range(sd->island[island].start, sd->island[island].end - 1); uint16 dist_ally, dist_enemy; Skirmish_FindClosestStructures(houseID, sd->buildable[r].packed, &dist_ally, &dist_enemy); if ((dist_ally > 16 && dist_ally != 0xFFFF) || (dist_enemy < 24)) continue; const int area = Skirmish_FindBuildableArea(island, sd->buildable[r].x, sd->buildable[r].y, sd, sd->buildable + sd->island[island].start); assert(area == sd->island[island].end - sd->island[island].start); UNUSED(area); for (int i = sd->island[island].start; i < sd->island[island].end; i++) sd->islandID[sd->buildable[i].packed] = island; } /* Use no-cheat-mode to verify land is buildable. */ g_validateStrictIfZero--; assert(g_validateStrictIfZero == 0); /* Place structures. */ while (structure_count > 0) { assert(structure < lengthof(buildorder)); if (buildorder[structure].type == STRUCTURE_INVALID) { tech_level++; structure++; continue; } if (buildorder[structure].priority >= structure_threshold) { structure++; continue; } const StructureType type = buildorder[structure].type; const StructureInfo* si = &g_table_structureInfo[type]; const int r = Tools_RandomLCG_Range(0, range - 1); const uint16 packed = sd->buildable[sd->island[island].start + r].packed; if (Structure_IsValidBuildLandscape(packed, type) != 0) { Structure* s = Structure_Create(STRUCTURE_INDEX_INVALID, type, houseID, packed); assert(s != NULL); s->o.hitpoints = si->o.hitpoints; s->o.flags.s.degrades = false; s->state = STRUCTURE_STATE_IDLE; if (House_AreAllied(g_playerHouseID, houseID)) s->o.seenByHouses = 0xFF; if (s->o.type == STRUCTURE_PALACE) s->countDown = g_table_houseInfo[houseID].specialCountDown; range = min(range + 4, sd->island[island].end - sd->island[island].start); structure++; structure_count--; } else { range++; if (range > sd->island[island].end - sd->island[island].start) break; } } /* Connect structures on this island with concrete slabs. */ for (range--; range > 0; range--) { const int self = sd->island[island].start + range; uint16 packed = sd->buildable[self].packed; const LandscapeType lst = (const LandscapeType)Map_GetLandscapeType(packed); if (lst != LST_STRUCTURE && lst != LST_CONCRETE_SLAB) continue; const int parent = sd->island[island].start + sd->buildable[self].parent; packed = sd->buildable[parent].packed; if (Structure_IsValidBuildLandscape(packed, STRUCTURE_SLAB_1x1) == 0) continue; g_validateStrictIfZero++; Structure_Create(STRUCTURE_INDEX_INVALID, STRUCTURE_SLAB_1x1, houseID, packed); g_validateStrictIfZero--; } /* Finished building on this island. Create sub-islands from * remaining buildable tiles. */ g_validateStrictIfZero++; Skirmish_DivideIsland(houseID, island, sd); if (structure_count <= 0) return true; } return false; }