/** * Check if the given tile is a valid destination. In case of for example * a carry-all it checks if the unit carrying can be placed on destination. * In case of structures, it checks if you can walk into it. * * Stack: 1 - An encoded tile, indicating the destination. * * @param script The script engine to operate on. * @return ??. */ uint16 Script_Unit_IsValidDestination(ScriptEngine *script) { Unit *u; Unit *u2; uint16 encoded; uint16 index; u = g_scriptCurrentUnit; encoded = STACK_PEEK(1); index = Tools_Index_Decode(encoded); switch (Tools_Index_GetType(encoded)) { case IT_TILE: if (!Map_IsValidPosition(index)) return 1; if (u->o.linkedID == 0xFF) return 1; u2 = Unit_Get_ByIndex(u->o.linkedID); u2->o.position = Tools_Index_GetTile(encoded); if (!Unit_IsTileOccupied(u2)) return 0; u2->o.position.tile = 0xFFFFFFFF; return 1; case IT_STRUCTURE: { Structure *s; s = Structure_Get_ByIndex(index); if (s->o.houseID == Unit_GetHouseID(u)) return 0; if (u->o.linkedID == 0xFF) return 1; u2 = Unit_Get_ByIndex(u->o.linkedID); return Unit_IsValidMovementIntoStructure(u2, s) != 0 ? 1 : 0; } default: return 1; } }
/** * 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; }
/** * Remove fog in the radius around the given tile. * * @param tile The tile to remove fog around. * @param radius The radius to remove fog around. */ void Tile_RemoveFogInRadius(tile32 tile, uint16 radius) { uint16 packed; uint16 x, y; int16 i, j; packed = Tile_PackTile(tile); if (!Map_IsValidPosition(packed)) return; x = Tile_GetPackedX(packed); y = Tile_GetPackedY(packed); tile = Tile_MakeXY(x, y); for (i = -radius; i <= radius; i++) { for (j = -radius; j <= radius; j++) { tile32 t; if ((x + i) < 0 || (x + i) >= 64) continue; if ((y + j) < 0 || (y + j) >= 64) continue; packed = Tile_PackXY(x + i, y + j); t = Tile_MakeXY(x + i, y + j); if (Tile_GetDistanceRoundedUp(tile, t) > radius) continue; Map_UnveilTile(packed, g_playerHouseID); } } }
static void Scenario_Load_Unit(const char *key, char *settings) { uint8 houseType, unitType, actionType; int8 orientation; uint16 hitpoints; tile32 position; Unit *u; char *split; VARIABLE_NOT_USED(key); /* The value should have 6 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 Unit type */ unitType = Unit_StringToType(settings); if (unitType == UNIT_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); /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Fourth value is the position on the map */ position = Tile_UnpackTile(atoi(settings)); /* Find the next value in the ',' separated list */ settings = split + 1; split = strchr(settings, ','); if (split == NULL) return; *split = '\0'; /* Fifth value is orientation */ orientation = (int8)((uint8)atoi(settings)); /* Sixth value is the current state of the unit */ settings = split + 1; actionType = Unit_ActionStringToType(settings); if (actionType == ACTION_INVALID) return; u = Unit_Allocate(UNIT_INDEX_INVALID, unitType, houseType); if (u == NULL) return; u->o.flags.s.byScenario = true; u->o.hitpoints = hitpoints * g_table_unitInfo[unitType].o.hitpoints / 256; u->o.position = position; u->orientation[0].current = orientation; u->actionID = actionType; u->nextActionID = ACTION_INVALID; /* In case the above function failed and we are passed campaign 2, don't add the unit */ if (!Map_IsValidPosition(Tile_PackTile(u->o.position)) && g_campaignID > 2) { Unit_Free(u); return; } /* XXX -- There is no way this is ever possible, as the beingBuilt flag is unset by Unit_Allocate() */ if (!u->o.flags.s.isNotOnMap) Unit_SetAction(u, u->actionID); u->o.seenByHouses = 0x00; Unit_HouseUnitCount_Add(u, u->o.houseID); Unit_SetOrientation(u, u->orientation[0].current, true, 0); Unit_SetOrientation(u, u->orientation[0].current, true, 1); Unit_SetSpeed(u, 0); }
/** * Delivery of transport, either to structure or to a tile. * * Stack: *none*. * * @param script The script engine to operate on. * @return One if delivered, zero otherwise.. */ uint16 Script_Unit_TransportDeliver(ScriptEngine *script) { Unit *u; Unit *u2; VARIABLE_NOT_USED(script); u = g_scriptCurrentUnit; if (u->o.linkedID == 0xFF) return 0; if (Tools_Index_GetType(u->targetMove) == IT_UNIT) return 0; if (Tools_Index_GetType(u->targetMove) == IT_STRUCTURE) { const StructureInfo *si; Structure *s; s = Tools_Index_GetStructure(u->targetMove); si = &g_table_structureInfo[s->o.type]; if (s->o.type == STRUCTURE_STARPORT) { uint16 ret = 0; if (s->state == STRUCTURE_STATE_BUSY) { s->o.linkedID = u->o.linkedID; u->o.linkedID = 0xFF; u->o.flags.s.inTransport = false; u->amount = 0; Unit_UpdateMap(2, u); Voice_PlayAtTile(24, u->o.position); Structure_SetState(s, STRUCTURE_STATE_READY); ret = 1; } Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return ret; } if ((s->state == STRUCTURE_STATE_IDLE || (si->o.flags.busyStateIsIncoming && s->state == STRUCTURE_STATE_BUSY)) && s->o.linkedID == 0xFF) { Voice_PlayAtTile(24, u->o.position); Unit_EnterStructure(Unit_Get_ByIndex(u->o.linkedID), s); Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; u->o.linkedID = 0xFF; u->o.flags.s.inTransport = false; u->amount = 0; Unit_UpdateMap(2, u); return 1; } Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return 0; } if (!Map_IsValidPosition(Tile_PackTile(Tile_Center(u->o.position)))) return 0; u2 = Unit_Get_ByIndex(u->o.linkedID); if (!Unit_SetPosition(u2, Tile_Center(u->o.position))) return 0; if (u2->o.houseID == g_playerHouseID) { Voice_PlayAtTile(24, u->o.position); } Unit_SetOrientation(u2, u->orientation[0].current, true, 0); Unit_SetOrientation(u2, u->orientation[0].current, true, 1); Unit_SetSpeed(u2, 0); u->o.linkedID = u2->o.linkedID; u2->o.linkedID = 0xFF; if (u->o.linkedID != 0xFF) return 1; u->o.flags.s.inTransport = false; Object_Script_Variable4_Clear(&u->o); u->targetMove = 0; return 1; }
/** * Draw a single tile on the screen. * * @param packed The tile to draw. */ void GUI_Widget_Viewport_DrawTile(uint16 packed) { uint16 x; uint16 y; uint16 colour; uint16 spriteID; Tile *t; uint16 mapScale; colour = 12; spriteID = 0xFFFF; if (Tile_IsOutOfMap(packed) || !Map_IsValidPosition(packed)) return; x = Tile_GetPackedX(packed); y = Tile_GetPackedY(packed); mapScale = g_scenario.mapScale + 1; if (mapScale == 0 || BitArray_Test(g_displayedMinimap, packed)) return; t = &g_map[packed]; if ((t->isUnveiled && g_playerHouse->flags.radarActivated) || g_debugScenario) { uint16 type = Map_GetLandscapeType(packed); Unit *u; if (mapScale > 1) { spriteID = g_scenario.mapScale + g_table_landscapeInfo[type].spriteID - 1; } else { colour = g_table_landscapeInfo[type].radarColour; } if (g_table_landscapeInfo[type].radarColour == 0xFFFF) { if (mapScale > 1) { spriteID = mapScale + t->houseID * 2 + 29; } else { colour = g_table_houseInfo[t->houseID].minimapColor; } } u = Unit_Get_ByPackedTile(packed); if (u != NULL) { if (mapScale > 1) { if (u->o.type == UNIT_SANDWORM) { spriteID = mapScale + 53; } else { spriteID = mapScale + Unit_GetHouseID(u) * 2 + 29; } } else { if (u->o.type == UNIT_SANDWORM) { colour = 255; } else { colour = g_table_houseInfo[Unit_GetHouseID(u)].minimapColor; } } } } else { Structure *s; s = Structure_Get_ByPackedTile(packed); if (s != NULL && s->o.houseID == g_playerHouseID) { if (mapScale > 1) { spriteID = mapScale + s->o.houseID * 2 + 29; } else { colour = g_table_houseInfo[s->o.houseID].minimapColor; } } else { if (mapScale > 1) { spriteID = g_scenario.mapScale + g_table_landscapeInfo[LST_ENTIRELY_MOUNTAIN].spriteID - 1; } else { colour = 12; } } } x -= g_mapInfos[g_scenario.mapScale].minX; y -= g_mapInfos[g_scenario.mapScale].minY; if (spriteID != 0xFFFF) { x *= g_scenario.mapScale + 1; y *= g_scenario.mapScale + 1; GUI_DrawSprite(g_screenActiveID, g_sprites[spriteID], x, y, 3, 0x4000); } else { GFX_PutPixel(x + 256, y + 136, colour & 0xFF); } }