1
0
Fork 0

(svn r16531) [0.7] -Backport from trunk:

- Fix: [NoAI] StationIDs from oilrigs were not considered valid by the API (r16529)
- Fix: Draw PBS reservation as groundsprite resp. childsprite of foundation/bridgehead [FS#2959] (r16528)
- Fix: Missing guards in the NoAI API making it possible to hit an assert in OpenTTD [FS#2963] (r16524)
- Fix: [NoAI] Possible assert in AI debug window when an AI was stopped an a human company took its CompanyID [FS#2962] (r16522)
- Fix: [NoAI] Make sure AIBridge::BuildBridge returns what the documentation says it does (r16520)
release/0.7
rubidium 2009-06-07 15:26:33 +00:00
parent 253702529d
commit b1d2a8876b
11 changed files with 60 additions and 53 deletions

View File

@ -605,7 +605,7 @@ struct AIDebugWindow : public Window {
virtual void OnPaint() virtual void OnPaint()
{ {
/* Check if the currently selected company is still active. */ /* Check if the currently selected company is still active. */
if (ai_debug_company == INVALID_COMPANY || !IsValidCompanyID(ai_debug_company)) { if (ai_debug_company == INVALID_COMPANY || !IsValidCompanyID(ai_debug_company) || !GetCompany(ai_debug_company)->is_ai) {
if (ai_debug_company != INVALID_COMPANY) { if (ai_debug_company != INVALID_COMPANY) {
/* Raise and disable the widget for the previous selection. */ /* Raise and disable the widget for the previous selection. */
this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START); this->RaiseWidget(ai_debug_company + AID_WIDGET_COMPANY_BUTTON_START);

View File

@ -32,7 +32,6 @@
static void _DoCommandReturnBuildBridge2(class AIInstance *instance) static void _DoCommandReturnBuildBridge2(class AIInstance *instance)
{ {
if (!AIBridge::_BuildBridgeRoad2()) { if (!AIBridge::_BuildBridgeRoad2()) {
AIObject::SetLastCommandRes(false);
AIInstance::DoCommandReturn(instance); AIInstance::DoCommandReturn(instance);
return; return;
} }
@ -45,7 +44,6 @@ static void _DoCommandReturnBuildBridge2(class AIInstance *instance)
static void _DoCommandReturnBuildBridge1(class AIInstance *instance) static void _DoCommandReturnBuildBridge1(class AIInstance *instance)
{ {
if (!AIBridge::_BuildBridgeRoad1()) { if (!AIBridge::_BuildBridgeRoad1()) {
AIObject::SetLastCommandRes(false);
AIInstance::DoCommandReturn(instance); AIInstance::DoCommandReturn(instance);
return; return;
} }
@ -67,7 +65,7 @@ static void _DoCommandReturnBuildBridge1(class AIInstance *instance)
switch (vehicle_type) { switch (vehicle_type) {
case AIVehicle::VT_ROAD: case AIVehicle::VT_ROAD:
type |= (TRANSPORT_ROAD << 15); type |= (TRANSPORT_ROAD << 15);
type |= (RoadTypeToRoadTypes((::RoadType)AIObject::GetRoadType()) << 8); type |= (::RoadTypeToRoadTypes((::RoadType)AIObject::GetRoadType()) << 8);
break; break;
case AIVehicle::VT_RAIL: case AIVehicle::VT_RAIL:
type |= (TRANSPORT_RAIL << 15); type |= (TRANSPORT_RAIL << 15);
@ -86,10 +84,7 @@ static void _DoCommandReturnBuildBridge1(class AIInstance *instance)
AIObject::SetCallbackVariable(0, start); AIObject::SetCallbackVariable(0, start);
AIObject::SetCallbackVariable(1, end); AIObject::SetCallbackVariable(1, end);
if (!AIObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE, NULL, &_DoCommandReturnBuildBridge1)) return false; return AIObject::DoCommand(end, start, type | bridge_id, CMD_BUILD_BRIDGE, NULL, &_DoCommandReturnBuildBridge1);
/* In case of test-mode, test if we can build both road pieces */
return _BuildBridgeRoad1();
} }
/* static */ bool AIBridge::_BuildBridgeRoad1() /* static */ bool AIBridge::_BuildBridgeRoad1()
@ -101,10 +96,7 @@ static void _DoCommandReturnBuildBridge1(class AIInstance *instance)
DiagDirection dir_1 = (DiagDirection)((::TileX(start) == ::TileX(end)) ? (::TileY(start) < ::TileY(end) ? DIAGDIR_NW : DIAGDIR_SE) : (::TileX(start) < ::TileX(end) ? DIAGDIR_NE : DIAGDIR_SW)); DiagDirection dir_1 = (DiagDirection)((::TileX(start) == ::TileX(end)) ? (::TileY(start) < ::TileY(end) ? DIAGDIR_NW : DIAGDIR_SE) : (::TileX(start) < ::TileX(end) ? DIAGDIR_NE : DIAGDIR_SW));
DiagDirection dir_2 = ::ReverseDiagDir(dir_1); DiagDirection dir_2 = ::ReverseDiagDir(dir_1);
if (!AIObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &_DoCommandReturnBuildBridge2)) return false; return AIObject::DoCommand(start + ::TileOffsByDiagDir(dir_1), ::DiagDirToRoadBits(dir_2) | (AIObject::GetRoadType() << 4), 0, CMD_BUILD_ROAD, NULL, &_DoCommandReturnBuildBridge2);
/* In case of test-mode, test the other road piece too */
return _BuildBridgeRoad2();
} }
/* static */ bool AIBridge::_BuildBridgeRoad2() /* static */ bool AIBridge::_BuildBridgeRoad2()

View File

@ -17,7 +17,8 @@
/* static */ bool AIStation::IsValidStation(StationID station_id) /* static */ bool AIStation::IsValidStation(StationID station_id)
{ {
return ::IsValidStationID(station_id) && ::GetStation(station_id)->owner == _current_company; const Station *st = ::IsValidStationID(station_id) ? GetStation(station_id) : NULL;
return st != NULL && (st->owner == _current_company || st->owner == OWNER_NONE);
} }
/* static */ StationID AIStation::GetStationID(TileIndex tile) /* static */ StationID AIStation::GetStationID(TileIndex tile)

View File

@ -175,21 +175,21 @@
return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, UINT32_MAX)) != TRACKDIR_BIT_NONE; return ::TrackStatusToTrackdirBits(::GetTileTrackStatus(tile, (::TransportType)transport_type, UINT32_MAX)) != TRACKDIR_BIT_NONE;
} }
/* static */ int32 AITile::GetCargoAcceptance(TileIndex tile, CargoID cargo_type, uint width, uint height, uint radius) /* static */ int32 AITile::GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius)
{ {
if (!::IsValidTile(tile)) return false; if (!::IsValidTile(tile) || width <= 0 || height <= 0 || radius <= 0) return -1;
AcceptedCargo accepts; AcceptedCargo accepts;
::GetAcceptanceAroundTiles(accepts, tile, width, height, _settings_game.station.modified_catchment ? radius : (uint)CA_UNMODIFIED); ::GetAcceptanceAroundTiles(accepts, tile, width, height, _settings_game.station.modified_catchment ? radius : (int)CA_UNMODIFIED);
return accepts[cargo_type]; return accepts[cargo_type];
} }
/* static */ int32 AITile::GetCargoProduction(TileIndex tile, CargoID cargo_type, uint width, uint height, uint radius) /* static */ int32 AITile::GetCargoProduction(TileIndex tile, CargoID cargo_type, int width, int height, int radius)
{ {
if (!::IsValidTile(tile)) return false; if (!::IsValidTile(tile) || width <= 0 || height <= 0 || radius <= 0) return -1;
AcceptedCargo produced; AcceptedCargo produced;
::GetProductionAroundTiles(produced, tile, width, height, _settings_game.station.modified_catchment ? radius : (uint)CA_UNMODIFIED); ::GetProductionAroundTiles(produced, tile, width, height, _settings_game.station.modified_catchment ? radius : (int)CA_UNMODIFIED);
return produced[cargo_type]; return produced[cargo_type];
} }

View File

@ -303,9 +303,12 @@ public:
* @param height The height of the station. * @param height The height of the station.
* @param radius The radius of the station. * @param radius The radius of the station.
* @pre AIMap::IsValidTile(tile). * @pre AIMap::IsValidTile(tile).
* @pre width > 0.
* @pre height > 0.
* @pre radius > 0.
* @return Value below 8 means no acceptance; the more the better. * @return Value below 8 means no acceptance; the more the better.
*/ */
static int32 GetCargoAcceptance(TileIndex tile, CargoID cargo_type, uint width, uint height, uint radius); static int32 GetCargoAcceptance(TileIndex tile, CargoID cargo_type, int width, int height, int radius);
/** /**
* Checks how many tiles in the radius produces this cargo. * Checks how many tiles in the radius produces this cargo.
@ -317,10 +320,13 @@ public:
* @param height The height of the station. * @param height The height of the station.
* @param radius The radius of the station. * @param radius The radius of the station.
* @pre AIMap::IsValidTile(tile). * @pre AIMap::IsValidTile(tile).
* @pre width > 0.
* @pre height > 0.
* @pre radius > 0.
* @return The tiles that produce this cargo within radius of the tile. * @return The tiles that produce this cargo within radius of the tile.
* @note Town(houses) are not included in the value. * @note Town(houses) are not included in the value.
*/ */
static int32 GetCargoProduction(TileIndex tile, CargoID cargo_type, uint width, uint height, uint radius); static int32 GetCargoProduction(TileIndex tile, CargoID cargo_type, int width, int height, int radius);
/** /**
* Get the manhattan distance from the tile to the tile. * Get the manhattan distance from the tile to the tile.

View File

@ -68,9 +68,9 @@ void AITileList::RemoveTile(TileIndex tile)
this->RemoveItem(tile); this->RemoveItem(tile);
} }
AITileList_IndustryAccepting::AITileList_IndustryAccepting(IndustryID industry_id, uint radius) AITileList_IndustryAccepting::AITileList_IndustryAccepting(IndustryID industry_id, int radius)
{ {
if (!AIIndustry::IsValidIndustry(industry_id)) return; if (!AIIndustry::IsValidIndustry(industry_id) || radius <= 0) return;
const Industry *i = ::GetIndustry(industry_id); const Industry *i = ::GetIndustry(industry_id);
@ -106,9 +106,9 @@ AITileList_IndustryAccepting::AITileList_IndustryAccepting(IndustryID industry_i
} END_TILE_LOOP(cur_tile, i->width + radius * 2, i->height + radius * 2, i->xy - ::TileDiffXY(radius, radius)) } END_TILE_LOOP(cur_tile, i->width + radius * 2, i->height + radius * 2, i->xy - ::TileDiffXY(radius, radius))
} }
AITileList_IndustryProducing::AITileList_IndustryProducing(IndustryID industry_id, uint radius) AITileList_IndustryProducing::AITileList_IndustryProducing(IndustryID industry_id, int radius)
{ {
if (!AIIndustry::IsValidIndustry(industry_id)) return; if (!AIIndustry::IsValidIndustry(industry_id) || radius <= 0) return;
const Industry *i = ::GetIndustry(industry_id); const Industry *i = ::GetIndustry(industry_id);

View File

@ -71,8 +71,10 @@ public:
/** /**
* @param industry_id The industry to create the AITileList around. * @param industry_id The industry to create the AITileList around.
* @param radius The radius of the station you will be using. * @param radius The radius of the station you will be using.
* @pre AIIndustry::IsValidIndustry(industry_id).
* @pre radius > 0.
*/ */
AITileList_IndustryAccepting(IndustryID industry_id, uint radius); AITileList_IndustryAccepting(IndustryID industry_id, int radius);
}; };
/** /**
@ -87,8 +89,10 @@ public:
/** /**
* @param industry_id The industry to create the AITileList around. * @param industry_id The industry to create the AITileList around.
* @param radius The radius of the station you will be using. * @param radius The radius of the station you will be using.
* @pre AIIndustry::IsValidIndustry(industry_id).
* @pre radius > 0.
*/ */
AITileList_IndustryProducing(IndustryID industry_id, uint radius); AITileList_IndustryProducing(IndustryID industry_id, int radius);
}; };
/** /**

View File

@ -1791,7 +1791,8 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
/* PBS debugging, draw reserved tracks darker */ /* PBS debugging, draw reserved tracks darker */
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) { if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation) {
TrackBits pbs = GetTrackReservation(ti->tile); /* Get reservation, but mask track on halftile slope */
TrackBits pbs = GetTrackReservation(ti->tile) & track;
if (pbs & TRACK_BIT_X) { if (pbs & TRACK_BIT_X) {
if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) { if (ti->tileh == SLOPE_FLAT || ti->tileh == SLOPE_ELEVATED) {
DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH); DrawGroundSprite(rti->base_sprites.single_y, PALETTE_CRASH);
@ -1806,10 +1807,10 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH); DrawGroundSprite(_track_sloped_sprites[ti->tileh - 1] + rti->base_sprites.single_sloped - 20, PALETTE_CRASH);
} }
} }
if (pbs & TRACK_BIT_UPPER) AddSortableSpriteToDraw(rti->base_sprites.single_n, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_N ? 8 : 0)); if (pbs & TRACK_BIT_UPPER) DrawGroundSprite(rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_N ? -TILE_HEIGHT : 0);
if (pbs & TRACK_BIT_LOWER) AddSortableSpriteToDraw(rti->base_sprites.single_s, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_S ? 8 : 0)); if (pbs & TRACK_BIT_LOWER) DrawGroundSprite(rti->base_sprites.single_s, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_S ? -TILE_HEIGHT : 0);
if (pbs & TRACK_BIT_LEFT) AddSortableSpriteToDraw(rti->base_sprites.single_w, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_W ? 8 : 0)); if (pbs & TRACK_BIT_LEFT) DrawGroundSprite(rti->base_sprites.single_w, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_W ? -TILE_HEIGHT : 0);
if (pbs & TRACK_BIT_RIGHT) AddSortableSpriteToDraw(rti->base_sprites.single_e, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + (ti->tileh & SLOPE_E ? 8 : 0)); if (pbs & TRACK_BIT_RIGHT) DrawGroundSprite(rti->base_sprites.single_e, PALETTE_CRASH, NULL, 0, ti->tileh & SLOPE_E ? -TILE_HEIGHT : 0);
} }
if (IsValidCorner(halftile_corner)) { if (IsValidCorner(halftile_corner)) {
@ -1827,9 +1828,9 @@ static void DrawTrackBits(TileInfo *ti, TrackBits track)
} }
DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner])); DrawGroundSprite(image, pal, &(_halftile_sub_sprite[halftile_corner]));
if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && IsSteepSlope(ti->tileh) && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) { if (_game_mode != GM_MENU && _settings_client.gui.show_track_reservation && HasReservedTracks(ti->tile, CornerToTrackBits(halftile_corner))) {
static const byte _corner_to_track_sprite[] = {3, 1, 2, 0}; static const byte _corner_to_track_sprite[] = {3, 1, 2, 0};
AddSortableSpriteToDraw(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, ti->x, ti->y, 16, 16, 0, ti->z + 16); DrawGroundSprite(_corner_to_track_sprite[halftile_corner] + rti->base_sprites.single_n, PALETTE_CRASH, NULL, 0, -TILE_HEIGHT);
} }
} }
} }

View File

@ -993,8 +993,8 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
/* draw ramp */ /* draw ramp */
/* Draw Trambits as SpriteCombine */ /* Draw Trambits and PBS Reservation as SpriteCombine */
if (transport_type == TRANSPORT_ROAD) StartSpriteCombine(); if (transport_type == TRANSPORT_ROAD || transport_type == TRANSPORT_RAIL) StartSpriteCombine();
/* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on /* HACK set the height of the BB of a sloped ramp to 1 so a vehicle on
* it doesn't disappear behind it * it doesn't disappear behind it
@ -1028,6 +1028,7 @@ static void DrawTile_TunnelBridge(TileInfo *ti)
} }
EndSpriteCombine(); EndSpriteCombine();
} else if (transport_type == TRANSPORT_RAIL) { } else if (transport_type == TRANSPORT_RAIL) {
EndSpriteCombine();
if (HasCatenaryDrawn(GetRailType(ti->tile))) { if (HasCatenaryDrawn(GetRailType(ti->tile))) {
DrawCatenary(ti); DrawCatenary(ti);
} }

View File

@ -60,9 +60,8 @@ struct TileSpriteToDraw {
SpriteID image; SpriteID image;
SpriteID pal; SpriteID pal;
const SubSprite *sub; ///< only draw a rectangular part of the sprite const SubSprite *sub; ///< only draw a rectangular part of the sprite
int32 x; int32 x; ///< screen X coordinate of sprite
int32 y; int32 y; ///< screen Y coordinate of sprite
byte z;
}; };
struct ChildScreenSpriteToDraw { struct ChildScreenSpriteToDraw {
@ -456,13 +455,15 @@ void HandleZoomMessage(Window *w, const ViewPort *vp, byte widget_zoom_in, byte
* *
* @param image the image to draw. * @param image the image to draw.
* @param pal the provided palette. * @param pal the provided palette.
* @param x position x of the sprite. * @param x position x (world coordinates) of the sprite.
* @param y position y of the sprite. * @param y position y (world coordinates) of the sprite.
* @param z position z of the sprite. * @param z position z (world coordinates) of the sprite.
* @param sub Only draw a part of the sprite. * @param sub Only draw a part of the sprite.
* @param extra_offs_x Pixel X offset for the sprite position.
* @param extra_offs_y Pixel Y offset for the sprite position.
* *
*/ */
void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z, const SubSprite *sub) void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
{ {
assert((image & SPRITE_MASK) < MAX_SPRITES); assert((image & SPRITE_MASK) < MAX_SPRITES);
@ -470,9 +471,9 @@ void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z,
ts->image = image; ts->image = image;
ts->pal = pal; ts->pal = pal;
ts->sub = sub; ts->sub = sub;
ts->x = x; Point pt = RemapCoords(x, y, z);
ts->y = y; ts->x = pt.x + extra_offs_x;
ts->z = z; ts->y = pt.y + extra_offs_y;
} }
/** /**
@ -510,16 +511,18 @@ static void AddChildSpriteToFoundation(SpriteID image, SpriteID pal, const SubSp
* @param image the image to draw. * @param image the image to draw.
* @param pal the provided palette. * @param pal the provided palette.
* @param sub Only draw a part of the sprite. * @param sub Only draw a part of the sprite.
* @param extra_offs_x Pixel X offset for the sprite position.
* @param extra_offs_y Pixel Y offset for the sprite position.
*/ */
void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub) void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub, int extra_offs_x, int extra_offs_y)
{ {
/* Switch to first foundation part, if no foundation was drawn */ /* Switch to first foundation part, if no foundation was drawn */
if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL; if (_vd.foundation_part == FOUNDATION_PART_NONE) _vd.foundation_part = FOUNDATION_PART_NORMAL;
if (_vd.foundation[_vd.foundation_part] != -1) { if (_vd.foundation[_vd.foundation_part] != -1) {
AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, 0, 0); AddChildSpriteToFoundation(image, pal, sub, _vd.foundation_part, extra_offs_x, extra_offs_y);
} else { } else {
DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub); DrawGroundSpriteAt(image, pal, _cur_ti->x, _cur_ti->y, _cur_ti->z, sub, extra_offs_x, extra_offs_y);
} }
} }
@ -1300,8 +1303,7 @@ static void ViewportDrawTileSprites(const TileSpriteToDrawVector *tstdv)
{ {
const TileSpriteToDraw *tsend = tstdv->End(); const TileSpriteToDraw *tsend = tstdv->End();
for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) { for (const TileSpriteToDraw *ts = tstdv->Begin(); ts != tsend; ++ts) {
Point pt = RemapCoords(ts->x, ts->y, ts->z); DrawSprite(ts->image, ts->pal, ts->x, ts->y, ts->sub);
DrawSprite(ts->image, ts->pal, pt.x, pt.y, ts->sub);
} }
} }

View File

@ -33,8 +33,8 @@ static inline void MaxZoomInOut(int how, Window *w)
void OffsetGroundSprite(int x, int y); void OffsetGroundSprite(int x, int y);
void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub = NULL); void DrawGroundSprite(SpriteID image, SpriteID pal, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0);
void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z, const SubSprite *sub = NULL); void DrawGroundSpriteAt(SpriteID image, SpriteID pal, int32 x, int32 y, byte z, const SubSprite *sub = NULL, int extra_offs_x = 0, int extra_offs_y = 0);
void AddSortableSpriteToDraw(SpriteID image, SpriteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = NULL); void AddSortableSpriteToDraw(SpriteID image, SpriteID pal, int x, int y, int w, int h, int dz, int z, bool transparent = false, int bb_offset_x = 0, int bb_offset_y = 0, int bb_offset_z = 0, const SubSprite *sub = NULL);
void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, uint16 colour = 0, uint16 width = 0); void AddStringToDraw(int x, int y, StringID string, uint64 params_1, uint64 params_2, uint16 colour = 0, uint16 width = 0);
void AddChildSpriteScreen(SpriteID image, SpriteID pal, int x, int y, bool transparent = false, const SubSprite *sub = NULL); void AddChildSpriteScreen(SpriteID image, SpriteID pal, int x, int y, bool transparent = false, const SubSprite *sub = NULL);