/** * Play a voice. Volume is based on distance to position. * @param voiceID Which voice to play. * @param position Which position to play it on. */ void Voice_PlayAtTile(int16 voiceID, tile32 position) { uint16 index; uint16 volume; if (voiceID < 0 || voiceID >= 120) return; if (!g_gameConfig.sounds) return; volume = 255; if (position.x != 0 || position.y != 0) { volume = Tile_GetDistancePacked(g_minimapPosition, Tile_PackTile(position)); if (volume > 64) volume = 64; volume = 255 - (volume * 255 / 80); } index = g_table_voiceMapping[voiceID]; if (g_enableVoices != 0 && index != 0xFFFF && g_voiceData[index] != NULL && g_table_voices[index].priority >= s_currentVoicePriority) { s_currentVoicePriority = g_table_voices[index].priority; memmove(g_readBuffer, g_voiceData[index], g_voiceDataSize[index]); Driver_Voice_Play(g_readBuffer, s_currentVoicePriority); } else { Driver_Sound_Play(voiceID, volume); } }
/** * Play a voice. Volume is based on distance to position. * @param voiceID Which voice to play. * @param position Which position to play it on. */ void Voice_PlayAtTile(int16 voiceID, tile32 position) { uint16 index; uint16 volume; if (voiceID < 0 || voiceID >= 120) return; if (!g_gameConfig.sounds) return; volume = 255; if (position.tile != 0) { volume = Tile_GetDistancePacked(g_minimapPosition, Tile_PackTile(position)); if (volume > 64) volume = 64; volume = 255 - (volume * 255 / 80); } index = g_table_voiceMapping[voiceID]; if (g_enableVoices != 0 && index != 0xFFFF && g_variable_3E54[index] != NULL && g_table_voices[index].variable_04 >= s_variable_4060) { s_variable_4060 = g_table_voices[index].variable_04; memmove(g_readBuffer, g_variable_3E54[index], g_variable_3E54_size[index]); Driver_Voice_Play(g_readBuffer, s_variable_4060); } else { Driver_Sound_Play(voiceID, volume); } }
/** * Get a tile in the direction of a destination, randomized a bit. * * @param packed_from The origin. * @param packed_to The destination. * @return A packed tile. */ uint16 Tile_GetTileInDirectionOf(uint16 packed_from, uint16 packed_to) { int16 distance; uint8 direction; uint8 i; if (packed_from == 0 || packed_to == 0) return 0; distance = Tile_GetDistancePacked(packed_from, packed_to); direction = Tile_GetDirectionPacked(packed_to, packed_from); if (distance <= 10) return 0; for (i = 0; i < 4; i++) { int16 dir; tile32 position; uint16 packed; dir = 29 + (Tools_Random_256() & 0x3F); if ((Tools_Random_256() & 1) != 0) dir = -dir; position = Tile_UnpackTile(packed_to); position = Tile_MoveByDirection(position, direction + dir, min(distance, 20) << 8); packed = Tile_PackTile(position); if (Map_IsValidPosition(packed)) return packed; } return 0; }
/** * Calculate the route to a tile. * * Stack: 1 - An encoded tile to calculate the route to. * * @param script The script engine to operate on. * @return 0 if we arrived on location, 1 otherwise. */ uint16 Script_Unit_CalculateRoute(ScriptEngine *script) { Unit *u; uint16 encoded; uint16 packedSrc; uint16 packedDst; u = g_scriptCurrentUnit; encoded = STACK_PEEK(1); if (u->currentDestination.tile != 0 || !Tools_Index_IsValid(encoded)) return 1; packedSrc = Tile_PackTile(u->o.position); packedDst = Tools_Index_GetPackedTile(encoded); if (packedDst == packedSrc) { u->route[0] = 0xFF; u->targetMove = 0; return 0; } if (u->route[0] == 0xFF) { Pathfinder_Data res; uint8 buffer[42]; res = Script_Unit_Pathfinder(packedSrc, packedDst, buffer, 40); memcpy(u->route, res.buffer, min(res.routeSize, 14)); if (u->route[0] == 0xFF) { u->targetMove = 0; if (u->o.type == UNIT_SANDWORM) { script->delay = 720; } } } else { uint16 distance; distance = Tile_GetDistancePacked(packedDst, packedSrc); if (distance < 14) u->route[distance] = 0xFF; } if (u->route[0] == 0xFF) return 1; if (u->orientation[0].current != (int8)(u->route[0] * 32)) { Unit_SetOrientation(u, (int8)(u->route[0] * 32), false, 0); return 1; } if (!Unit_StartMovement(u)) { u->route[0] = 0xFF; return 0; } memmove(&u->route[0], &u->route[1], 13); u->route[13] = 0xFF; return 1; }
/** * Gets the average distance between current team members, and set the * position of the team to the average position. * * Stack: *none*. * * @param script The script engine to operate on. * @return The average distance. */ uint16 Script_Team_GetAverageDistance(ScriptEngine *script) { uint16 averageX = 0; uint16 averageY = 0; uint16 count = 0; uint16 distance = 0; Team *t; PoolFindStruct find; VARIABLE_NOT_USED(script); t = g_scriptCurrentTeam; find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; u = Unit_Find(&find); if (u == NULL) break; if (t->index != u->team - 1) continue; count++; averageX += (u->o.position.x >> 8) & 0x3f; averageY += (u->o.position.y >> 8) & 0x3f; } if (count == 0) return 0; averageX /= count; averageY /= count; t->position = Tile_MakeXY(averageX, averageY); find.houseID = t->houseID; find.index = 0xFFFF; find.type = 0xFFFF; while (true) { Unit *u; u = Unit_Find(&find); if (u == NULL) break; if (t->index != u->team - 1) continue; distance += Tile_GetDistanceRoundedUp(u->o.position, t->position); } distance /= count; if (t->target == 0 || t->targetTile == 0) return distance; if (Tile_GetDistancePacked(Tile_PackXY(averageX, averageY), Tools_Index_GetPackedTile(t->target)) <= 10) t->targetTile = 2; return distance; }
static void Skirmish_FindClosestStructures(HouseType houseID, uint16 packed, uint16* dist_ally, uint16* dist_enemy) { PoolFindStruct find; Structure* s; find.houseID = HOUSE_INVALID; find.type = 0xFFFF; find.index = STRUCTURE_INDEX_INVALID; *dist_ally = 0xFFFF; *dist_enemy = 0xFFFF; while ((s = Structure_Find(&find)) != NULL) { if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL) continue; const uint16 dist = Tile_GetDistancePacked(Tile_PackTile(s->o.position), packed); if (House_AreAllied(houseID, s->o.houseID)) *dist_ally = min(dist, *dist_ally); else *dist_enemy = min(dist, *dist_enemy); } }
static bool Skirmish_GenUnitsHuman(HouseType houseID, SkirmishData* sd) { const int delta[7] = { 0, -4, 4, -MAP_SIZE_MAX * 3 - 2, -MAP_SIZE_MAX * 3 + 2, MAP_SIZE_MAX * 3 - 2, MAP_SIZE_MAX * 3 + 2, }; const MapInfo* mi = &g_mapInfos[0]; /* Pick a tile that is not too close to the edge, and not too * close to the enemy. */ int r; for (int attempts = 0; attempts < 100; attempts++) { const int island = Skirmish_PickRandomIsland(sd); if (island < 0) return false; r = Tools_RandomLCG_Range(sd->island[island].start, sd->island[island].end - 1); if (!(mi->minX + 4 <= sd->buildable[r].x && sd->buildable[r].x < mi->minX + mi->sizeX - 4)) continue; if (!(mi->minY + 3 <= sd->buildable[r].y && sd->buildable[r].y < mi->minY + mi->sizeY - 3)) continue; PoolFindStruct find; find.houseID = HOUSE_INVALID; find.type = 0xFFFF; find.index = STRUCTURE_INDEX_INVALID; Structure* s = Structure_Find(&find); for (; s != NULL; s = Structure_Find(&find)) { if (s->o.type == STRUCTURE_SLAB_1x1 || s->o.type == STRUCTURE_SLAB_2x2 || s->o.type == STRUCTURE_WALL) continue; if (House_AreAllied(g_playerHouseID, s->o.houseID)) continue; const uint16 dist = Tile_GetDistancePacked(Tile_PackTile(s->o.position), sd->buildable[r].packed); if (dist < 24) break; } if (s == NULL) { break; } else { r = -1; } } if (r < 0) return false; bool mcvPlaced = false; for (int i = 0; i < 7; i++) { const uint16 packed = sd->buildable[r].packed + delta[i]; const tile32 position = Tile_UnpackTile(packed); UnitType type; if (!mcvPlaced) type = UNIT_MCV; else if (i >= 0 && i < 3) type = UNIT_SIEGE_TANK; else if (i >= 3 && i < 4) type = House_GetIXVehicle(houseID); else if (i >= 4 && i < 5) type = House_GetMediumVehicle(houseID); else if (i >= 5 && i < 6) type = UNIT_QUAD; else if (i >= 6) type = House_GetInfantrySquad(houseID); const LandscapeType lst = (const LandscapeType)Map_GetLandscapeType(packed); /* If there's a structure or a bloom here, tough luck. */ if (lst == LST_STRUCTURE || lst == LST_BLOOM_FIELD) continue; /* If there's a mountain here, build infantry instead. */ if (lst == LST_ENTIRELY_MOUNTAIN || lst == LST_PARTIAL_MOUNTAIN) type = House_GetInfantrySquad(houseID); Scenario_Create_Unit(houseID, type, 256, position, 127, (UnitActionType)g_table_unitInfo[type].o.actionsPlayer[3]); if (type == UNIT_MCV) mcvPlaced = true; } return true; }