diff --git a/src/aircraft.h b/src/aircraft.h index cbb424423f..ab5a382245 100644 --- a/src/aircraft.h +++ b/src/aircraft.h @@ -94,7 +94,7 @@ struct Aircraft FINAL : public SpecializedVehicle { void UpdateDeltaXY(Direction direction); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; } bool IsPrimaryVehicle() const { return this->IsNormalAircraft(); } - SpriteID GetImage(Direction direction, EngineImageType image_type) const; + void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; int GetDisplaySpeed() const { return this->cur_speed; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } int GetSpeedOldUnits() const { return this->vcache.cached_max_speed * 10 / 128; } @@ -142,7 +142,7 @@ struct Aircraft FINAL : public SpecializedVehicle { */ #define FOR_ALL_AIRCRAFT(var) FOR_ALL_VEHICLES_OF_TYPE(Aircraft, var) -SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type); +void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result); Station *GetTargetAirportIfValid(const Aircraft *v); diff --git a/src/aircraft_cmd.cpp b/src/aircraft_cmd.cpp index 4a1bde888c..f4557851e1 100644 --- a/src/aircraft_cmd.cpp +++ b/src/aircraft_cmd.cpp @@ -158,64 +158,69 @@ static StationID FindNearestHangar(const Aircraft *v) return index; } -SpriteID Aircraft::GetImage(Direction direction, EngineImageType image_type) const +void Aircraft::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { - SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type); - if (sprite != 0) return sprite; + GetCustomVehicleSprite(this, direction, image_type, result); + if (result->IsValid()) return; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); - return direction + _aircraft_sprite[spritenum]; + result->Set(direction + _aircraft_sprite[spritenum]); } -SpriteID GetRotorImage(const Aircraft *v, EngineImageType image_type) +void GetRotorImage(const Aircraft *v, EngineImageType image_type, VehicleSpriteSeq *result) { assert(v->subtype == AIR_HELICOPTER); const Aircraft *w = v->Next()->Next(); if (is_custom_sprite(v->spritenum)) { - SpriteID sprite = GetCustomRotorSprite(v, false, image_type); - if (sprite != 0) return sprite; + GetCustomRotorSprite(v, false, image_type, result); + if (result->IsValid()) return; } /* Return standard rotor sprites if there are no custom sprites for this helicopter */ - return SPR_ROTOR_STOPPED + w->state; + result->Set(SPR_ROTOR_STOPPED + w->state); } -static SpriteID GetAircraftIcon(EngineID engine, EngineImageType image_type) +static void GetAircraftIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result) { const Engine *e = Engine::Get(engine); uint8 spritenum = e->u.air.image_index; if (is_custom_sprite(spritenum)) { - SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); - if (sprite != 0) return sprite; + GetCustomVehicleIcon(engine, DIR_W, image_type, result); + if (result->IsValid()) return; spritenum = e->original_image_index; } assert(IsValidImageIndex(spritenum)); - return DIR_W + _aircraft_sprite[spritenum]; + result->Set(DIR_W + _aircraft_sprite[spritenum]); } void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { - SpriteID sprite = GetAircraftIcon(engine, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + GetAircraftIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); preferred_x = Clamp(preferred_x, - left - UnScaleGUI(real_sprite->x_offs), - right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); - DrawSprite(sprite, pal, preferred_x, y); + left - UnScaleGUI(rect.left), + right - UnScaleGUI(rect.right)); + + seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH); if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) { - SpriteID rotor_sprite = GetCustomRotorIcon(engine, image_type); - if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; - DrawSprite(rotor_sprite, PAL_NONE, preferred_x, y - ScaleGUITrad(5)); + VehicleSpriteSeq rotor_seq; + GetCustomRotorIcon(engine, image_type, &rotor_seq); + if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED); + rotor_seq.Draw(preferred_x, y - ScaleGUITrad(5), PAL_NONE, false); } } @@ -230,12 +235,16 @@ void DrawAircraftEngine(int left, int right, int preferred_x, int y, EngineID en */ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { - const Sprite *spr = GetSprite(GetAircraftIcon(engine, image_type), ST_NORMAL); + VehicleSpriteSeq seq; + GetAircraftIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); - width = UnScaleGUI(spr->width); - height = UnScaleGUI(spr->height); - xoffs = UnScaleGUI(spr->x_offs); - yoffs = UnScaleGUI(spr->y_offs); + width = UnScaleGUI(rect.right - rect.left + 1); + height = UnScaleGUI(rect.bottom - rect.top + 1); + xoffs = UnScaleGUI(rect.left); + yoffs = UnScaleGUI(rect.top); } /** @@ -326,7 +335,8 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine * v->date_of_last_service = _date; v->build_year = u->build_year = _cur_year; - v->cur_image = u->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); + u->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); u->random_bits = VehicleRandomBits(); @@ -360,7 +370,7 @@ CommandCost CmdBuildAircraft(TileIndex tile, DoCommandFlag flags, const Engine * w->vehstatus = VS_HIDDEN | VS_UNCLICKABLE; w->spritenum = 0xFF; w->subtype = AIR_ROTOR; - w->cur_image = SPR_ROTOR_STOPPED; + w->sprite_seq.Set(SPR_ROTOR_STOPPED); w->random_bits = VehicleRandomBits(); /* Use rotor's air.state to store the rotor animation frame */ w->state = HRS_ROTOR_STOPPED; @@ -479,21 +489,21 @@ static void HelicopterTickHandler(Aircraft *v) int tick = ++u->tick_counter; int spd = u->cur_speed >> 4; - SpriteID img; + VehicleSpriteSeq seq; if (spd == 0) { u->state = HRS_ROTOR_STOPPED; - img = GetRotorImage(v, EIT_ON_MAP); - if (u->cur_image == img) return; + GetRotorImage(v, EIT_ON_MAP, &seq); + if (u->sprite_seq == seq) return; } else if (tick >= spd) { u->tick_counter = 0; u->state++; if (u->state > HRS_ROTOR_MOVING_3) u->state = HRS_ROTOR_MOVING_1; - img = GetRotorImage(v, EIT_ON_MAP); + GetRotorImage(v, EIT_ON_MAP, &seq); } else { return; } - u->cur_image = img; + u->sprite_seq = seq; u->UpdatePositionAndViewport(); } @@ -513,7 +523,9 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z) v->UpdatePosition(); v->UpdateViewport(true, false); - if (v->subtype == AIR_HELICOPTER) v->Next()->Next()->cur_image = GetRotorImage(v, EIT_ON_MAP); + if (v->subtype == AIR_HELICOPTER) { + GetRotorImage(v, EIT_ON_MAP, &v->Next()->Next()->sprite_seq); + } Aircraft *u = v->Next(); @@ -524,7 +536,7 @@ void SetAircraftPosition(Aircraft *v, int x, int y, int z) safe_y = Clamp(u->y_pos, 0, MapMaxY() * TILE_SIZE); u->z_pos = GetSlopePixelZ(safe_x, safe_y); - u->cur_image = v->cur_image; + u->sprite_seq.CopyWithoutPalette(v->sprite_seq); // the shadow is never coloured u->UpdatePositionAndViewport(); @@ -1295,7 +1307,9 @@ void Aircraft::MarkDirty() this->colourmap = PAL_NONE; this->cur_image_valid_dir = INVALID_DIR; this->UpdateViewport(true, false); - if (this->subtype == AIR_HELICOPTER) this->Next()->Next()->cur_image = GetRotorImage(this, EIT_ON_MAP); + if (this->subtype == AIR_HELICOPTER) { + GetRotorImage(this, EIT_ON_MAP, &this->Next()->Next()->sprite_seq); + } } diff --git a/src/aircraft_gui.cpp b/src/aircraft_gui.cpp index c3379d3951..20fca9fc5d 100644 --- a/src/aircraft_gui.cpp +++ b/src/aircraft_gui.cpp @@ -83,11 +83,14 @@ void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID s { bool rtl = _current_text_dir == TD_RTL; - SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq); - int width = UnScaleGUI(real_sprite->width); - int x_offs = UnScaleGUI(real_sprite->x_offs); + Rect rect; + seq.GetBounds(&rect); + + int width = UnScaleGUI(rect.right - rect.left + 1); + int x_offs = UnScaleGUI(rect.left); int x = rtl ? right - width - x_offs : left - x_offs; bool helicopter = v->subtype == AIR_HELICOPTER; @@ -95,17 +98,18 @@ void DrawAircraftImage(const Vehicle *v, int left, int right, int y, VehicleID s int heli_offs = 0; PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); - DrawSprite(sprite, pal, x, y + y_offs); + seq.Draw(x, y + y_offs, pal, v->vehstatus & VS_CRASHED); if (helicopter) { const Aircraft *a = Aircraft::From(v); - SpriteID rotor_sprite = GetCustomRotorSprite(a, true, image_type); - if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; + VehicleSpriteSeq rotor_seq; + GetCustomRotorSprite(a, true, image_type, &rotor_seq); + if (!rotor_seq.IsValid()) rotor_seq.Set(SPR_ROTOR_STOPPED); heli_offs = ScaleGUITrad(5); - DrawSprite(rotor_sprite, PAL_NONE, x, y + y_offs - heli_offs); + rotor_seq.Draw(x, y + y_offs - heli_offs, PAL_NONE, false); } if (v->index == selection) { x += x_offs; - y += UnScaleGUI(real_sprite->y_offs) + y_offs - heli_offs; - DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY); + y += UnScaleGUI(rect.top) + y_offs - heli_offs; + DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(rect.bottom - rect.top + 1) + heli_offs + 1, COLOUR_WHITE, FR_BORDERONLY); } } diff --git a/src/articulated_vehicles.cpp b/src/articulated_vehicles.cpp index 62ad79ccad..3995deca98 100644 --- a/src/articulated_vehicles.cpp +++ b/src/articulated_vehicles.cpp @@ -474,7 +474,7 @@ void AddArticulatedParts(Vehicle *first) v->max_age = 0; v->engine_type = engine_type; v->value = 0; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); if (flip_image) v->spritenum++; diff --git a/src/disaster_vehicle.cpp b/src/disaster_vehicle.cpp index 5fa20baed7..647fed51ce 100644 --- a/src/disaster_vehicle.cpp +++ b/src/disaster_vehicle.cpp @@ -112,7 +112,7 @@ void DisasterVehicle::UpdateImage() { SpriteID img = this->image_override; if (img == 0) img = _disaster_images[this->subtype][this->direction]; - this->cur_image = img; + this->sprite_seq.Set(img); } /** @@ -502,7 +502,8 @@ static bool DisasterTick_Helicopter_Rotors(DisasterVehicle *v) v->tick_counter++; if (HasBit(v->tick_counter, 0)) return true; - if (++v->cur_image > SPR_ROTOR_MOVING_3) v->cur_image = SPR_ROTOR_MOVING_1; + SpriteID &cur_image = v->sprite_seq.seq[0].sprite; + if (++cur_image > SPR_ROTOR_MOVING_3) cur_image = SPR_ROTOR_MOVING_1; v->UpdatePositionAndViewport(); diff --git a/src/effectvehicle.cpp b/src/effectvehicle.cpp index 209b78d2e9..5921cd190e 100644 --- a/src/effectvehicle.cpp +++ b/src/effectvehicle.cpp @@ -22,10 +22,26 @@ #include "safeguards.h" +/** + * Increment the sprite unless it has reached the end of the animation. + * @param v Vehicle to increment sprite of. + * @param last Last sprite of animation. + * @return true if the sprite was incremented, false if the end was reached. + */ +static bool IncrementSprite(EffectVehicle *v, SpriteID last) +{ + if (v->sprite_seq.seq[0].sprite != last) { + v->sprite_seq.seq[0].sprite++; + return true; + } else { + return false; + } +} + static void ChimneySmokeInit(EffectVehicle *v) { uint32 r = Random(); - v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3); + v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3)); v->progress = GB(r, 16, 3); } @@ -40,10 +56,8 @@ static bool ChimneySmokeTick(EffectVehicle *v) return false; } - if (v->cur_image != SPR_CHIMNEY_SMOKE_7) { - v->cur_image++; - } else { - v->cur_image = SPR_CHIMNEY_SMOKE_0; + if (!IncrementSprite(v, SPR_CHIMNEY_SMOKE_7)) { + v->sprite_seq.Set(SPR_CHIMNEY_SMOKE_0); } v->progress = 7; v->UpdatePositionAndViewport(); @@ -54,7 +68,7 @@ static bool ChimneySmokeTick(EffectVehicle *v) static void SteamSmokeInit(EffectVehicle *v) { - v->cur_image = SPR_STEAM_SMOKE_0; + v->sprite_seq.Set(SPR_STEAM_SMOKE_0); v->progress = 12; } @@ -70,9 +84,7 @@ static bool SteamSmokeTick(EffectVehicle *v) } if ((v->progress & 0xF) == 4) { - if (v->cur_image != SPR_STEAM_SMOKE_4) { - v->cur_image++; - } else { + if (!IncrementSprite(v, SPR_STEAM_SMOKE_4)) { delete v; return false; } @@ -86,7 +98,7 @@ static bool SteamSmokeTick(EffectVehicle *v) static void DieselSmokeInit(EffectVehicle *v) { - v->cur_image = SPR_DIESEL_SMOKE_0; + v->sprite_seq.Set(SPR_DIESEL_SMOKE_0); v->progress = 0; } @@ -98,13 +110,11 @@ static bool DieselSmokeTick(EffectVehicle *v) v->z_pos++; v->UpdatePositionAndViewport(); } else if ((v->progress & 7) == 1) { - if (v->cur_image != SPR_DIESEL_SMOKE_5) { - v->cur_image++; - v->UpdatePositionAndViewport(); - } else { + if (!IncrementSprite(v, SPR_DIESEL_SMOKE_5)) { delete v; return false; } + v->UpdatePositionAndViewport(); } return true; @@ -112,7 +122,7 @@ static bool DieselSmokeTick(EffectVehicle *v) static void ElectricSparkInit(EffectVehicle *v) { - v->cur_image = SPR_ELECTRIC_SPARK_0; + v->sprite_seq.Set(SPR_ELECTRIC_SPARK_0); v->progress = 1; } @@ -122,13 +132,12 @@ static bool ElectricSparkTick(EffectVehicle *v) v->progress++; } else { v->progress = 0; - if (v->cur_image != SPR_ELECTRIC_SPARK_5) { - v->cur_image++; - v->UpdatePositionAndViewport(); - } else { + + if (!IncrementSprite(v, SPR_ELECTRIC_SPARK_5)) { delete v; return false; } + v->UpdatePositionAndViewport(); } return true; @@ -136,7 +145,7 @@ static bool ElectricSparkTick(EffectVehicle *v) static void SmokeInit(EffectVehicle *v) { - v->cur_image = SPR_SMOKE_0; + v->sprite_seq.Set(SPR_SMOKE_0); v->progress = 12; } @@ -152,9 +161,7 @@ static bool SmokeTick(EffectVehicle *v) } if ((v->progress & 0xF) == 4) { - if (v->cur_image != SPR_SMOKE_4) { - v->cur_image++; - } else { + if (!IncrementSprite(v, SPR_SMOKE_4)) { delete v; return false; } @@ -168,7 +175,7 @@ static bool SmokeTick(EffectVehicle *v) static void ExplosionLargeInit(EffectVehicle *v) { - v->cur_image = SPR_EXPLOSION_LARGE_0; + v->sprite_seq.Set(SPR_EXPLOSION_LARGE_0); v->progress = 0; } @@ -176,13 +183,11 @@ static bool ExplosionLargeTick(EffectVehicle *v) { v->progress++; if ((v->progress & 3) == 0) { - if (v->cur_image != SPR_EXPLOSION_LARGE_F) { - v->cur_image++; - v->UpdatePositionAndViewport(); - } else { + if (!IncrementSprite(v, SPR_EXPLOSION_LARGE_F)) { delete v; return false; } + v->UpdatePositionAndViewport(); } return true; @@ -190,7 +195,7 @@ static bool ExplosionLargeTick(EffectVehicle *v) static void BreakdownSmokeInit(EffectVehicle *v) { - v->cur_image = SPR_BREAKDOWN_SMOKE_0; + v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0); v->progress = 0; } @@ -198,10 +203,8 @@ static bool BreakdownSmokeTick(EffectVehicle *v) { v->progress++; if ((v->progress & 7) == 0) { - if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) { - v->cur_image++; - } else { - v->cur_image = SPR_BREAKDOWN_SMOKE_0; + if (!IncrementSprite(v, SPR_BREAKDOWN_SMOKE_3)) { + v->sprite_seq.Set(SPR_BREAKDOWN_SMOKE_0); } v->UpdatePositionAndViewport(); } @@ -217,7 +220,7 @@ static bool BreakdownSmokeTick(EffectVehicle *v) static void ExplosionSmallInit(EffectVehicle *v) { - v->cur_image = SPR_EXPLOSION_SMALL_0; + v->sprite_seq.Set(SPR_EXPLOSION_SMALL_0); v->progress = 0; } @@ -225,13 +228,11 @@ static bool ExplosionSmallTick(EffectVehicle *v) { v->progress++; if ((v->progress & 3) == 0) { - if (v->cur_image != SPR_EXPLOSION_SMALL_B) { - v->cur_image++; - v->UpdatePositionAndViewport(); - } else { + if (!IncrementSprite(v, SPR_EXPLOSION_SMALL_B)) { delete v; return false; } + v->UpdatePositionAndViewport(); } return true; @@ -239,7 +240,7 @@ static bool ExplosionSmallTick(EffectVehicle *v) static void BulldozerInit(EffectVehicle *v) { - v->cur_image = SPR_BULLDOZER_NE; + v->sprite_seq.Set(SPR_BULLDOZER_NE); v->progress = 0; v->animation_state = 0; v->animation_substate = 0; @@ -290,7 +291,7 @@ static bool BulldozerTick(EffectVehicle *v) if ((v->progress & 7) == 0) { const BulldozerMovement *b = &_bulldozer_movement[v->animation_state]; - v->cur_image = SPR_BULLDOZER_NE + b->image; + v->sprite_seq.Set(SPR_BULLDOZER_NE + b->image); v->x_pos += _inc_by_dir[b->direction].x; v->y_pos += _inc_by_dir[b->direction].y; @@ -312,7 +313,7 @@ static bool BulldozerTick(EffectVehicle *v) static void BubbleInit(EffectVehicle *v) { - v->cur_image = SPR_BUBBLE_GENERATE_0; + v->sprite_seq.Set(SPR_BUBBLE_GENERATE_0); v->spritenum = 0; v->progress = 0; } @@ -475,8 +476,8 @@ static bool BubbleTick(EffectVehicle *v) if ((v->progress & 3) != 0) return true; if (v->spritenum == 0) { - v->cur_image++; - if (v->cur_image < SPR_BUBBLE_GENERATE_3) { + v->sprite_seq.seq[0].sprite++; + if (v->sprite_seq.seq[0].sprite < SPR_BUBBLE_GENERATE_3) { v->UpdatePositionAndViewport(); return true; } @@ -521,7 +522,7 @@ static bool BubbleTick(EffectVehicle *v) v->x_pos += b->x; v->y_pos += b->y; v->z_pos += b->z; - v->cur_image = SPR_BUBBLE_0 + b->image; + v->sprite_seq.Set(SPR_BUBBLE_0 + b->image); v->UpdatePositionAndViewport(); diff --git a/src/engine_type.h b/src/engine_type.h index aeebcb3522..8356fda8f8 100644 --- a/src/engine_type.h +++ b/src/engine_type.h @@ -158,6 +158,7 @@ enum EngineMiscFlags { EF_AUTO_REFIT = 4, ///< Automatic refitting is allowed EF_NO_DEFAULT_CARGO_MULTIPLIER = 5, ///< Use the new capacity algorithm. The default cargotype of the vehicle does not affect capacity multipliers. CB 15 is also called in purchase list. EF_NO_BREAKDOWN_SMOKE = 6, ///< Do not show black smoke during a breakdown. + EF_SPRITE_STACK = 7, ///< Draw vehicle by stacking multiple sprites. }; /** diff --git a/src/lang/thai.txt b/src/lang/thai.txt index 89f8e69113..86720059ae 100644 --- a/src/lang/thai.txt +++ b/src/lang/thai.txt @@ -250,6 +250,7 @@ STR_TOOLTIP_DEMOLISH_BUILDINGS_ETC :{BLACK}ทำ # Show engines button +STR_SHOW_HIDDEN_ENGINES_VEHICLE_AIRCRAFT_TOOLTIP :ถ้าได้อนุญาตที่ปุ่มนี้แล้ว อากาศยานที่ซ่อนจะถูกแสดงออกมา # Query window STR_BUTTON_DEFAULT :{BLACK}ค่าปกติ @@ -970,6 +971,7 @@ STR_GAME_OPTIONS_RESOLUTION :{BLACK}คว STR_GAME_OPTIONS_RESOLUTION_TOOLTIP :{BLACK}เลือกความละเอียดของหน้าจอที่จะใช้ STR_GAME_OPTIONS_RESOLUTION_OTHER :อื่นๆ +STR_GAME_OPTIONS_GUI_ZOOM_FRAME :{BLACK}ขนาดของแผงควบคุม STR_GAME_OPTIONS_BASE_GRF :{BLACK}ตั้งค่า Graphic พื้นฐาน @@ -1086,6 +1088,7 @@ STR_CONFIG_SETTING_TYPE_COMPANY_MENU :ตั้งค STR_CONFIG_SETTING_TYPE_COMPANY_INGAME :ตั้งค่าองค์กร (ถูกเก็บไว้ในการบันทึกเกม; มีผลเฉพาะเกมปัจจุบัน) STR_CONFIG_SETTING_RESTRICT_CATEGORY :{BLACK}หมวดหมู่: +STR_CONFIG_SETTING_RESTRICT_TYPE :{BLACK}ชนิด: STR_CONFIG_SETTING_RESTRICT_DROPDOWN_HELPTEXT :{BLACK}จำกัดรายการด้านล่างให้แสดงเฉพาะการตั้งค่าที่มีการเปลี่ยนแปลง STR_CONFIG_SETTING_RESTRICT_BASIC :ตั้งค่าพื้นฐาน STR_CONFIG_SETTING_RESTRICT_ADVANCED :ตั้งค่าขั้นสูง @@ -1270,6 +1273,7 @@ STR_CONFIG_SETTING_OIL_REF_EDGE_DISTANCE_HELPTEXT :โรงกล STR_CONFIG_SETTING_SNOWLINE_HEIGHT :ระดับความสูงแนวหิมะ: {STRING} STR_CONFIG_SETTING_SNOWLINE_HEIGHT_HELPTEXT :ควบคุมความสูงเริ่มต้นของหิมะบนพื้นภูมิทัศน์อาร์ติคย่อยๆ, หิมะยังมีผลการสร้างอุตสาหกรรม และการเติบโตของเมือง STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN :ความหยาบของพื้นที่ (เฉพาะ TerraGenesis): {STRING} +STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_HELPTEXT :(TerraGenesis only) Choose the frequency of hills: Smooth landscapes have fewer, more wide-spread hills. Rough landscapes have many hills, which may look repetitive STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_VERY_SMOOTH :ราบเรียบมาก STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_SMOOTH :ราบเรียบ STR_CONFIG_SETTING_ROUGHNESS_OF_TERRAIN_ROUGH :หยาบ @@ -1626,6 +1630,7 @@ STR_CONFIG_SETTING_SOUND :{ORANGE}เส STR_CONFIG_SETTING_INTERFACE :{ORANGE}ส่วนเชื่อมต่อผู้ใช้ STR_CONFIG_SETTING_INTERFACE_CONSTRUCTION :{ORANGE}การก่อสร้าง STR_CONFIG_SETTING_VEHICLES :{ORANGE}ยานพาหนะ +STR_CONFIG_SETTING_VEHICLES_PHYSICS :กายภาพ STR_CONFIG_SETTING_VEHICLES_ROUTING :{ORANGE}การค้นหาเส้นทางของพาหนะ STR_CONFIG_SETTING_ENVIRONMENT :{ORANGE}สิ่งแวดล้อม STR_CONFIG_SETTING_ENVIRONMENT_TOWNS :{ORANGE}เมือง @@ -1701,6 +1706,7 @@ STR_INTRO_TOOLTIP_TOYLAND_LANDSCAPE :{BLACK}เล STR_INTRO_TOOLTIP_GAME_OPTIONS :{BLACK}แสดงตัวเลือกเกม STR_INTRO_TOOLTIP_HIGHSCORE :{BLACK}แสดงตารางคะแนนสูงสุด +STR_INTRO_TOOLTIP_CONFIG_SETTINGS_TREE :{BLACK}การตั้งค่า หน้าจอ STR_INTRO_TOOLTIP_NEWGRF_SETTINGS :{BLACK}แสดงการกำหนดค่า NewGRF STR_INTRO_TOOLTIP_ONLINE_CONTENT :{BLACK}ตรวจสอบเนื้อหาใหม่และการปรับปรุงสำหรับดาวโหลด STR_INTRO_TOOLTIP_SCRIPT_SETTINGS :{BLACK}แสดงการตั้งค่า AI/Game script @@ -2663,6 +2669,7 @@ STR_MAPGEN_BY :{BLACK}* STR_MAPGEN_NUMBER_OF_TOWNS :{BLACK}จำนวนเมือง STR_MAPGEN_DATE :{BLACK}วันที่: STR_MAPGEN_NUMBER_OF_INDUSTRIES :{BLACK}จำนวนอุตสาหกรรม: +STR_MAPGEN_MAX_HEIGHTLEVEL :{BLACK}ขนาดความสูงของแผนที่สูงสุด: STR_MAPGEN_SNOW_LINE_HEIGHT :{BLACK}เส้นความสูงเขตหิมะ: STR_MAPGEN_SNOW_LINE_UP :{BLACK}ปรับเปลี่ยนความสูงของหิมะขึ้นไป 1 ระดับ STR_MAPGEN_SNOW_LINE_DOWN :{BLACK}ปรับเปลี่ยนความสูงของหิมะลงมา 1 ระดับ @@ -2773,6 +2780,7 @@ STR_NEWGRF_SETTINGS_DISABLED :{RED}ไม่ STR_NEWGRF_SETTINGS_INCOMPATIBLE :{RED}ไม่รองรับกับ OpenTTD เวอร์ชั่นนี้ # NewGRF save preset window +STR_SAVE_PRESET_SAVE_TOOLTIP :บันทึก ชุดการตั้งค่า ตามที่ได้เลือกไว้ # NewGRF parameters window STR_NEWGRF_PARAMETERS_CAPTION :{WHITE}เปลี่ยนแปลง NewGRF parameters @@ -3342,10 +3350,12 @@ STR_BUY_VEHICLE_ROAD_VEHICLE_RENAME_TOOLTIP :{BLACK}เป STR_BUY_VEHICLE_SHIP_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อชนิดของเรือ STR_BUY_VEHICLE_AIRCRAFT_RENAME_TOOLTIP :{BLACK}เปลี่ยนชื่อชนิดของเครื่องบิน +STR_BUY_VEHICLE_AIRCRAFT_HIDE_TOGGLE_BUTTON :ซ่อน STR_BUY_VEHICLE_TRAIN_SHOW_TOGGLE_BUTTON :{BLACK}การแสดงผล STR_BUY_VEHICLE_ROAD_VEHICLE_SHOW_TOGGLE_BUTTON :{BLACK}การแสดงผล +STR_BUY_VEHICLE_AIRCRAFT_HIDE_SHOW_TOGGLE_TOOLTIP :{BLACK}ปรับเปลี่ยน ซ่อน/แสดง ของชนิดเครื่องอากาศยาน STR_QUERY_RENAME_TRAIN_TYPE_CAPTION :{WHITE}เปลี่ยนชื่อชนิดของรถไฟ STR_QUERY_RENAME_ROAD_VEHICLE_TYPE_CAPTION :{WHITE}เปลี่ยนชื่อชนิดของรถ @@ -3451,6 +3461,7 @@ STR_REPLACE_VEHICLE_ROAD_VEHICLE :ยานพา STR_REPLACE_VEHICLE_SHIP :ยานพาหนะทางน้ำ STR_REPLACE_VEHICLE_AIRCRAFT :อากาศยาน +STR_REPLACE_VEHICLE_VEHICLES_IN_USE :{YELLOW}พาหนะถูกใช้งานอยู่ STR_REPLACE_HELP_LEFT_ARRAY :{BLACK}เลือกประเภทของรถจักรที่จะแทนที่ STR_REPLACE_HELP_RIGHT_ARRAY :{BLACK}เลือกประเภทของพาหนะที่จะแทนที่ทางซ้ายมือ diff --git a/src/music/cocoa_m.cpp b/src/music/cocoa_m.cpp index a201984ae1..925dc21ab5 100644 --- a/src/music/cocoa_m.cpp +++ b/src/music/cocoa_m.cpp @@ -30,6 +30,10 @@ #include "../safeguards.h" +#if !defined(HAVE_OSX_1011_SDK) +#define kMusicSequenceFile_AnyType 0 +#endif + static FMusicDriver_Cocoa iFMusicDriver_Cocoa; @@ -68,7 +72,7 @@ static void DoSetVolume() * risk compilation errors. The header AudioComponent.h * was introduced in 10.6 so use it to decide which * type definition to use. */ -#ifdef __AUDIOCOMPONENT_H__ +#if defined(__AUDIOCOMPONENT_H__) || defined(HAVE_OSX_107_SDK) AudioComponentDescription desc; #else ComponentDescription desc; @@ -159,7 +163,7 @@ void MusicDriver_Cocoa::PlaySong(const char *filename) #if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) if (MacOSVersionIsAtLeast(10, 5, 0)) { - if (MusicSequenceFileLoad(_sequence, url, 0, 0) != noErr) { + if (MusicSequenceFileLoad(_sequence, url, kMusicSequenceFile_AnyType, 0) != noErr) { DEBUG(driver, 0, "cocoa_m: Failed to load MIDI file"); CFRelease(url); return; diff --git a/src/music/win32_m.cpp b/src/music/win32_m.cpp index d3a7019a0f..fff0376a09 100644 --- a/src/music/win32_m.cpp +++ b/src/music/win32_m.cpp @@ -14,6 +14,7 @@ #include "win32_m.h" #include #include +#include "../os/windows/win32.h" #include "../safeguards.h" @@ -105,6 +106,8 @@ static bool MidiIntIsSongPlaying() static DWORD WINAPI MidiThread(LPVOID arg) { + SetWin32ThreadName(-1, "ottd:win-midi"); + do { char *s; int vol; diff --git a/src/newgrf_engine.cpp b/src/newgrf_engine.cpp index 99d8c8cc9d..cb6366ce5c 100644 --- a/src/newgrf_engine.cpp +++ b/src/newgrf_engine.cpp @@ -1029,17 +1029,29 @@ VehicleResolverObject::VehicleResolverObject(EngineID engine_type, const Vehicle -SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type) +void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) { - VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK, image_type); - const SpriteGroup *group = object.Resolve(); - if (group == NULL || group->GetNumResults() == 0) return 0; - - return group->GetResult() + (direction % group->GetNumResults()); + VehicleResolverObject object(engine, v, VehicleResolverObject::WO_CACHED, false, CBID_NO_CALLBACK); + result->Clear(); + + bool sprite_stack = HasBit(EngInfo(engine)->misc_flags, EF_SPRITE_STACK); + uint max_stack = sprite_stack ? lengthof(result->seq) : 1; + for (uint stack = 0; stack < max_stack; ++stack) { + object.ResetState(); + object.callback_param1 = image_type | (stack << 8); + const SpriteGroup *group = object.Resolve(); + uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0; + if (group != NULL && group->GetNumResults() != 0) { + result->seq[result->count].sprite = group->GetResult() + (direction % group->GetNumResults()); + result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring + result->count++; + } + if (!HasBit(reg100, 31)) break; + } } -SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_view, EngineImageType image_type) +void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type, VehicleSpriteSeq *result) { const Engine *e = Engine::Get(engine); @@ -1047,14 +1059,24 @@ SpriteID GetRotorOverrideSprite(EngineID engine, const Aircraft *v, bool info_vi assert(e->type == VEH_AIRCRAFT); assert(!(e->u.air.subtype & AIR_CTOL)); - VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK, image_type); - const SpriteGroup *group = object.Resolve(); - - if (group == NULL || group->GetNumResults() == 0) return 0; - - if (v == NULL || info_view) return group->GetResult(); - - return group->GetResult() + (v->Next()->Next()->state % group->GetNumResults()); + VehicleResolverObject object(engine, v, VehicleResolverObject::WO_SELF, info_view, CBID_NO_CALLBACK); + result->Clear(); + uint rotor_pos = v == NULL || info_view ? 0 : v->Next()->Next()->state; + + bool sprite_stack = HasBit(e->info.misc_flags, EF_SPRITE_STACK); + uint max_stack = sprite_stack ? lengthof(result->seq) : 1; + for (uint stack = 0; stack < max_stack; ++stack) { + object.ResetState(); + object.callback_param1 = image_type | (stack << 8); + const SpriteGroup *group = object.Resolve(); + uint32 reg100 = sprite_stack ? GetRegister(0x100) : 0; + if (group != NULL && group->GetNumResults() != 0) { + result->seq[result->count].sprite = group->GetResult() + (rotor_pos % group->GetNumResults()); + result->seq[result->count].pal = GB(reg100, 0, 16); // zero means default recolouring + result->count++; + } + if (!HasBit(reg100, 31)) break; + } } diff --git a/src/newgrf_engine.h b/src/newgrf_engine.h index 4a6f211c49..3c8108737c 100644 --- a/src/newgrf_engine.h +++ b/src/newgrf_engine.h @@ -64,13 +64,19 @@ static const uint TRAININFO_DEFAULT_VEHICLE_WIDTH = 29; static const uint ROADVEHINFO_DEFAULT_VEHICLE_WIDTH = 32; static const uint VEHICLEINFO_FULL_VEHICLE_WIDTH = 32; +struct VehicleSpriteSeq; + void SetWagonOverrideSprites(EngineID engine, CargoID cargo, const struct SpriteGroup *group, EngineID *train_id, uint trains); const SpriteGroup *GetWagonOverrideSpriteSet(EngineID engine, CargoID cargo, EngineID overriding_engine); void SetCustomEngineSprites(EngineID engine, byte cargo, const struct SpriteGroup *group); -SpriteID GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type); -SpriteID GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type); -#define GetCustomRotorSprite(v, i, image_type) GetRotorOverrideSprite(v->engine_type, v, i, image_type) -#define GetCustomRotorIcon(et, image_type) GetRotorOverrideSprite(et, NULL, true, image_type) + +void GetCustomEngineSprite(EngineID engine, const Vehicle *v, Direction direction, EngineImageType image_type, VehicleSpriteSeq *result); +#define GetCustomVehicleSprite(v, direction, image_type, result) GetCustomEngineSprite(v->engine_type, v, direction, image_type, result) +#define GetCustomVehicleIcon(et, direction, image_type, result) GetCustomEngineSprite(et, NULL, direction, image_type, result) + +void GetRotorOverrideSprite(EngineID engine, const struct Aircraft *v, bool info_view, EngineImageType image_type, VehicleSpriteSeq *result); +#define GetCustomRotorSprite(v, i, image_type, result) GetRotorOverrideSprite(v->engine_type, v, i, image_type, result) +#define GetCustomRotorIcon(et, image_type, result) GetRotorOverrideSprite(et, NULL, true, image_type, result) /* Forward declaration of GRFFile, to avoid unnecessary inclusion of newgrf.h * elsewhere... */ @@ -81,8 +87,6 @@ void SetEngineGRF(EngineID engine, const struct GRFFile *file); uint16 GetVehicleCallback(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v); uint16 GetVehicleCallbackParent(CallbackID callback, uint32 param1, uint32 param2, EngineID engine, const Vehicle *v, const Vehicle *parent); bool UsesWagonOverride(const Vehicle *v); -#define GetCustomVehicleSprite(v, direction, image_type) GetCustomEngineSprite(v->engine_type, v, direction, image_type) -#define GetCustomVehicleIcon(et, direction, image_type) GetCustomEngineSprite(et, NULL, direction, image_type) /* Handler to Evaluate callback 36. If the callback fails (i.e. most of the * time) orig_value is returned */ diff --git a/src/os/macosx/osx_stdafx.h b/src/os/macosx/osx_stdafx.h index 35b3f434a1..4e16b5e63b 100644 --- a/src/os/macosx/osx_stdafx.h +++ b/src/os/macosx/osx_stdafx.h @@ -13,6 +13,17 @@ #define MACOS_STDAFX_H +#include + +/* We assume if these macros are defined, the SDK is also at least this version or later. */ +#ifdef MAC_OS_X_VERSION_10_7 +#define HAVE_OSX_107_SDK +#endif + +#ifdef MAC_OS_X_VERSION_10_11 +#define HAVE_OSX_1011_SDK +#endif + /* It would seem that to ensure backward compability we have to ensure that we have defined MAC_OS_X_VERSION_10_x everywhere */ #ifndef MAC_OS_X_VERSION_10_3 #define MAC_OS_X_VERSION_10_3 1030 @@ -57,8 +68,6 @@ # error "Compiling 64 bits without _SQ64 set! (or vice versa)" #endif -#include - /* Name conflict */ #define Rect OTTDRect #define Point OTTDPoint diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp index 344d243143..3fd1777fa8 100644 --- a/src/os/windows/win32.cpp +++ b/src/os/windows/win32.cpp @@ -785,3 +785,36 @@ uint GetCPUCoreCount() GetSystemInfo(&info); return info.dwNumberOfProcessors; } + +#ifdef _MSC_VER +/* Code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */ +const DWORD MS_VC_EXCEPTION = 0x406D1388; +#pragma pack(push,8) +typedef struct { + DWORD dwType; ///< Must be 0x1000. + LPCSTR szName; ///< Pointer to name (in user addr space). + DWORD dwThreadID; ///< Thread ID (-1=caller thread). + DWORD dwFlags; ///< Reserved for future use, must be zero. +} THREADNAME_INFO; +#pragma pack(pop) + +/** + * Signal thread name to any attached debuggers. + */ +void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) +{ + THREADNAME_INFO info; + info.dwType = 0x1000; + info.szName = threadName; + info.dwThreadID = dwThreadID; + info.dwFlags = 0; + +#pragma warning(push) +#pragma warning(disable: 6320 6322) + __try { + RaiseException(MS_VC_EXCEPTION, 0, sizeof(info) / sizeof(ULONG_PTR), (ULONG_PTR*)&info); + } __except (EXCEPTION_EXECUTE_HANDLER) { + } +#pragma warning(pop) +} +#endif diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h index 4e53879cf0..16632f6e9a 100644 --- a/src/os/windows/win32.h +++ b/src/os/windows/win32.h @@ -39,4 +39,10 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR); #define SHGFP_TYPE_CURRENT 0 #endif /* __MINGW32__ */ +#ifdef _MSC_VER +void SetWin32ThreadName(DWORD dwThreadID, const char* threadName); +#else +static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {} +#endif + #endif /* WIN32_H */ diff --git a/src/roadveh.h b/src/roadveh.h index 500bdb8289..8a48c19837 100644 --- a/src/roadveh.h +++ b/src/roadveh.h @@ -108,7 +108,7 @@ struct RoadVehicle FINAL : public GroundVehicle { void UpdateDeltaXY(Direction direction); ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_ROADVEH_INC : EXPENSES_ROADVEH_RUN; } bool IsPrimaryVehicle() const { return this->IsFrontEngine(); } - SpriteID GetImage(Direction direction, EngineImageType image_type) const; + void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; int GetDisplaySpeed() const { return this->gcache.last_speed / 2; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; } Money GetRunningCost() const; diff --git a/src/roadveh_cmd.cpp b/src/roadveh_cmd.cpp index d1cd0f7444..abe0405e47 100644 --- a/src/roadveh_cmd.cpp +++ b/src/roadveh_cmd.cpp @@ -114,40 +114,39 @@ int RoadVehicle::GetDisplayImageWidth(Point *offset) const return ScaleGUITrad(this->gcache.cached_veh_length * reference_width / VEHICLE_LENGTH); } -static SpriteID GetRoadVehIcon(EngineID engine, EngineImageType image_type) +static void GetRoadVehIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result) { const Engine *e = Engine::Get(engine); uint8 spritenum = e->u.road.image_index; if (is_custom_sprite(spritenum)) { - SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); - if (sprite != 0) return sprite; + GetCustomVehicleIcon(engine, DIR_W, image_type, result); + if (result->IsValid()) return; spritenum = e->original_image_index; } assert(IsValidImageIndex(spritenum)); - return DIR_W + _roadveh_images[spritenum]; + result->Set(DIR_W + _roadveh_images[spritenum]); } -SpriteID RoadVehicle::GetImage(Direction direction, EngineImageType image_type) const +void RoadVehicle::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { uint8 spritenum = this->spritenum; - SpriteID sprite; if (is_custom_sprite(spritenum)) { - sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type); - if (sprite != 0) return sprite; + GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result); + if (result->IsValid()) return; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); - sprite = direction + _roadveh_images[spritenum]; + SpriteID sprite = direction + _roadveh_images[spritenum]; if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum]; - return sprite; + result->Set(sprite); } /** @@ -161,12 +160,16 @@ SpriteID RoadVehicle::GetImage(Direction direction, EngineImageType image_type) */ void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { - SpriteID sprite = GetRoadVehIcon(engine, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + GetRoadVehIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); preferred_x = Clamp(preferred_x, - left - UnScaleGUI(real_sprite->x_offs), - right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); - DrawSprite(sprite, pal, preferred_x, y); + left - UnScaleGUI(rect.left), + right - UnScaleGUI(rect.right)); + + seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH); } /** @@ -180,12 +183,16 @@ void DrawRoadVehEngine(int left, int right, int preferred_x, int y, EngineID eng */ void GetRoadVehSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { - const Sprite *spr = GetSprite(GetRoadVehIcon(engine, image_type), ST_NORMAL); + VehicleSpriteSeq seq; + GetRoadVehIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); - width = UnScaleGUI(spr->width); - height = UnScaleGUI(spr->height); - xoffs = UnScaleGUI(spr->x_offs); - yoffs = UnScaleGUI(spr->y_offs); + width = UnScaleGUI(rect.right - rect.left + 1); + height = UnScaleGUI(rect.bottom - rect.top + 1); + xoffs = UnScaleGUI(rect.left); + yoffs = UnScaleGUI(rect.top); } /** @@ -308,7 +315,7 @@ CommandCost CmdBuildRoadVehicle(TileIndex tile, DoCommandFlag flags, const Engin v->date_of_last_service = _date; v->build_year = _cur_year; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); v->SetFrontEngine(); diff --git a/src/roadveh_gui.cpp b/src/roadveh_gui.cpp index 46ff6cea78..c446db5109 100644 --- a/src/roadveh_gui.cpp +++ b/src/roadveh_gui.cpp @@ -149,7 +149,9 @@ void DrawRoadVehImage(const Vehicle *v, int left, int right, int y, VehicleID se if (rtl ? px + width > 0 : px - width < max_width) { PaletteID pal = (u->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(u); - DrawSprite(u->GetImage(dir, image_type), pal, px + (rtl ? -offset.x : offset.x), ScaleGUITrad(6) + offset.y); + VehicleSpriteSeq seq; + u->GetImage(dir, image_type, &seq); + seq.Draw(px + (rtl ? -offset.x : offset.x), ScaleGUITrad(6) + offset.y, pal, u->vehstatus & VS_CRASHED); } px += rtl ? -width : width; diff --git a/src/saveload/extended_ver_sl.cpp b/src/saveload/extended_ver_sl.cpp index ec1232db69..3a9ddca21d 100644 --- a/src/saveload/extended_ver_sl.cpp +++ b/src/saveload/extended_ver_sl.cpp @@ -68,11 +68,10 @@ const SlxiSubChunkInfo _sl_xv_sub_chunk_infos[] = { { XSLFI_REVERSE_AT_WAYPOINT, XSCF_NULL, 1, 1, "reverse_at_waypoint", NULL, NULL, NULL }, { XSLFI_VEH_LIFETIME_PROFIT, XSCF_NULL, 1, 1, "veh_lifetime_profit", NULL, NULL, NULL }, { XSLFI_LINKGRAPH_DAY_SCALE, XSCF_NULL, 1, 1, "linkgraph_day_scale", NULL, NULL, NULL }, - { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 1, 1, "template_replacement", NULL, NULL, "TRPL,TMPL" }, + { XSLFI_TEMPLATE_REPLACEMENT, XSCF_NULL, 2, 2, "template_replacement", NULL, NULL, "TRPL,TMPL" }, { XSLFI_MORE_RAIL_TYPES, XSCF_NULL, 1, 1, "more_rail_types", NULL, NULL, NULL }, { XSLFI_CARGO_TYPE_ORDERS, XSCF_NULL, 2, 2, "cargo_type_orders", NULL, NULL, "ORDX,VEOX" }, { XSLFI_EXTENDED_GAMELOG, XSCF_NULL, 1, 1, "extended_gamelog", NULL, NULL, NULL }, - { XSLFI_NULL, XSCF_NULL, 0, 0, NULL, NULL, NULL, NULL },// This is the end marker }; diff --git a/src/saveload/oldloader_sl.cpp b/src/saveload/oldloader_sl.cpp index 4afbe6033d..0c57166816 100644 --- a/src/saveload/oldloader_sl.cpp +++ b/src/saveload/oldloader_sl.cpp @@ -1165,7 +1165,7 @@ static const OldChunks vehicle_chunk[] = { OCL_SVAR( OC_UINT8, Vehicle, owner ), OCL_SVAR( OC_TILE, Vehicle, tile ), - OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, cur_image ), + OCL_SVAR( OC_FILE_U16 | OC_VAR_U32, Vehicle, sprite_seq.seq[0].sprite ), OCL_NULL( 8 ), ///< Vehicle sprite box, calculated automatically @@ -1258,7 +1258,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) if (v == NULL) continue; v->refit_cap = v->cargo_cap; - SpriteID sprite = v->cur_image; + SpriteID sprite = v->sprite_seq.seq[0].sprite; /* no need to override other sprites */ if (IsInsideMM(sprite, 1460, 1465)) { sprite += 580; // aircraft smoke puff @@ -1269,7 +1269,7 @@ bool LoadOldVehicle(LoadgameState *ls, int num) } else if (IsInsideMM(sprite, 2516, 2539)) { sprite += 1385; // rotor or disaster-related vehicles } - v->cur_image = sprite; + v->sprite_seq.seq[0].sprite = sprite; switch (v->type) { case VEH_TRAIN: { diff --git a/src/saveload/tbtr_template_veh_sl.cpp b/src/saveload/tbtr_template_veh_sl.cpp index 32dd9e104c..f17607401e 100644 --- a/src/saveload/tbtr_template_veh_sl.cpp +++ b/src/saveload/tbtr_template_veh_sl.cpp @@ -38,7 +38,9 @@ const SaveLoad* GTD() { SLE_VAR(TemplateVehicle, max_te, SLE_UINT32), SLE_VAR(TemplateVehicle, spritenum, SLE_UINT8), - SLE_VAR(TemplateVehicle, cur_image, SLE_UINT32), + SLE_CONDVAR_X(TemplateVehicle, sprite_seq.seq[0].sprite, SLE_UINT32, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 0, 1)), + SLE_CONDVAR_X(TemplateVehicle, sprite_seq.count, SLE_UINT32, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2)), + SLE_CONDARR_X(TemplateVehicle, sprite_seq.seq, SLE_UINT32, 8, 0, SL_MAX_VERSION, SlXvFeatureTest(XSLFTO_AND, XSLFI_TEMPLATE_REPLACEMENT, 2)), SLE_VAR(TemplateVehicle, image_width, SLE_UINT32), SLE_END() @@ -123,7 +125,7 @@ void AfterLoadTemplateVehiclesUpdateImage() Train *v = t; for (TemplateVehicle *u = tv; u != NULL; u = u->Next(), v = v->Next()) { u->spritenum = v->spritenum; - u->cur_image = v->GetImage(DIR_W, EIT_PURCHASE); + v->GetImage(DIR_W, EIT_PURCHASE, &u->sprite_seq); u->image_width = v->GetDisplayImageWidth(); } } diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index c6300a4ac5..b5239a0b2c 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -456,21 +456,21 @@ void AfterLoadVehicles(bool part_of_load) case VEH_TRAIN: case VEH_SHIP: - v->cur_image = v->GetImage(v->direction, EIT_ON_MAP); + v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq); break; case VEH_AIRCRAFT: if (Aircraft::From(v)->IsNormalAircraft()) { - v->cur_image = v->GetImage(v->direction, EIT_ON_MAP); + v->GetImage(v->direction, EIT_ON_MAP, &v->sprite_seq); - /* The plane's shadow will have the same image as the plane */ + /* The plane's shadow will have the same image as the plane, but no colour */ Vehicle *shadow = v->Next(); - shadow->cur_image = v->cur_image; + shadow->sprite_seq.CopyWithoutPalette(v->sprite_seq); /* In the case of a helicopter we will update the rotor sprites */ if (v->subtype == AIR_HELICOPTER) { Vehicle *rotor = shadow->Next(); - rotor->cur_image = GetRotorImage(Aircraft::From(v), EIT_ON_MAP); + GetRotorImage(Aircraft::From(v), EIT_ON_MAP, &rotor->sprite_seq); } UpdateAircraftCache(Aircraft::From(v), true); @@ -839,7 +839,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDVAR(Vehicle, z_pos, SLE_FILE_U8 | SLE_VAR_I32, 0, 163), SLE_CONDVAR(Vehicle, z_pos, SLE_INT32, 164, SL_MAX_VERSION), - SLE_VAR(Vehicle, cur_image, SLE_FILE_U16 | SLE_VAR_U32), + SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDNULL(5, 0, 57), SLE_VAR(Vehicle, progress, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), @@ -879,7 +879,7 @@ const SaveLoad *GetVehicleDescription(VehicleType vt) SLE_CONDVAR(Vehicle, current_order.dest, SLE_FILE_U8 | SLE_VAR_U16, 0, 4), SLE_CONDVAR(Vehicle, current_order.dest, SLE_UINT16, 5, SL_MAX_VERSION), - SLE_VAR(Vehicle, cur_image, SLE_FILE_U16 | SLE_VAR_U32), + SLE_VAR(Vehicle, sprite_seq.seq[0].sprite, SLE_FILE_U16 | SLE_VAR_U32), SLE_CONDVAR(Vehicle, age, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLE_CONDVAR(Vehicle, age, SLE_INT32, 31, SL_MAX_VERSION), SLE_VAR(Vehicle, tick_counter, SLE_UINT8), diff --git a/src/ship.h b/src/ship.h index 18f04c8faf..c94cbcddb7 100644 --- a/src/ship.h +++ b/src/ship.h @@ -34,7 +34,7 @@ struct Ship FINAL : public SpecializedVehicle { ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_SHIP_INC : EXPENSES_SHIP_RUN; } void PlayLeaveStationSound() const; bool IsPrimaryVehicle() const { return true; } - SpriteID GetImage(Direction direction, EngineImageType image_type) const; + void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; int GetDisplaySpeed() const { return this->cur_speed / 2; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed / 2; } int GetCurrentMaxSpeed() const { return min(this->vcache.cached_max_speed, this->current_order.GetMaxSpeed() * 2); } diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp index b77769b01a..92eeeea181 100644 --- a/src/ship_cmd.cpp +++ b/src/ship_cmd.cpp @@ -71,30 +71,34 @@ static inline TrackBits GetTileShipTrackStatus(TileIndex tile) return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); } -static SpriteID GetShipIcon(EngineID engine, EngineImageType image_type) +static void GetShipIcon(EngineID engine, EngineImageType image_type, VehicleSpriteSeq *result) { const Engine *e = Engine::Get(engine); uint8 spritenum = e->u.ship.image_index; if (is_custom_sprite(spritenum)) { - SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W, image_type); - if (sprite != 0) return sprite; + GetCustomVehicleIcon(engine, DIR_W, image_type, result); + if (result->IsValid()) return; spritenum = e->original_image_index; } assert(IsValidImageIndex(spritenum)); - return DIR_W + _ship_sprites[spritenum]; + result->Set(DIR_W + _ship_sprites[spritenum]); } void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) { - SpriteID sprite = GetShipIcon(engine, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + GetShipIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); preferred_x = Clamp(preferred_x, - left - UnScaleGUI(real_sprite->x_offs), - right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); - DrawSprite(sprite, pal, preferred_x, y); + left - UnScaleGUI(rect.left), + right - UnScaleGUI(rect.right)); + + seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH); } /** @@ -108,27 +112,31 @@ void DrawShipEngine(int left, int right, int preferred_x, int y, EngineID engine */ void GetShipSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, int &yoffs, EngineImageType image_type) { - const Sprite *spr = GetSprite(GetShipIcon(engine, image_type), ST_NORMAL); + VehicleSpriteSeq seq; + GetShipIcon(engine, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); - width = UnScaleGUI(spr->width); - height = UnScaleGUI(spr->height); - xoffs = UnScaleGUI(spr->x_offs); - yoffs = UnScaleGUI(spr->y_offs); + width = UnScaleGUI(rect.right - rect.left + 1); + height = UnScaleGUI(rect.bottom - rect.top + 1); + xoffs = UnScaleGUI(rect.left); + yoffs = UnScaleGUI(rect.top); } -SpriteID Ship::GetImage(Direction direction, EngineImageType image_type) const +void Ship::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { - SpriteID sprite = GetCustomVehicleSprite(this, direction, image_type); - if (sprite != 0) return sprite; + GetCustomVehicleSprite(this, direction, image_type, result); + if (result->IsValid()) return; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); - return _ship_sprites[spritenum] + direction; + result->Set(_ship_sprites[spritenum] + direction); } static const Depot *FindClosestShipDepot(const Vehicle *v, uint max_distance) @@ -769,7 +777,7 @@ CommandCost CmdBuildShip(TileIndex tile, DoCommandFlag flags, const Engine *e, u v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_ships); v->date_of_last_service = _date; v->build_year = _cur_year; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); v->UpdateCache(); diff --git a/src/ship_gui.cpp b/src/ship_gui.cpp index 7ad2e8473a..c6bf342d97 100644 --- a/src/ship_gui.cpp +++ b/src/ship_gui.cpp @@ -35,20 +35,23 @@ void DrawShipImage(const Vehicle *v, int left, int right, int y, VehicleID selec { bool rtl = _current_text_dir == TD_RTL; - SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq); - int width = UnScaleGUI(real_sprite->width); - int x_offs = UnScaleGUI(real_sprite->x_offs); + Rect rect; + seq.GetBounds(&rect); + + int width = UnScaleGUI(rect.right - rect.left + 1); + int x_offs = UnScaleGUI(rect.left); int x = rtl ? right - width - x_offs : left - x_offs; y += ScaleGUITrad(10); - DrawSprite(sprite, GetVehiclePalette(v), x, y); + seq.Draw(x, y, GetVehiclePalette(v), false); if (v->index == selection) { x += x_offs; - y += UnScaleGUI(real_sprite->y_offs); - DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(real_sprite->height) + 1, COLOUR_WHITE, FR_BORDERONLY); + y += UnScaleGUI(rect.top); + DrawFrameRect(x - 1, y - 1, x + width + 1, y + UnScaleGUI(rect.bottom - rect.top + 1) + 1, COLOUR_WHITE, FR_BORDERONLY); } } diff --git a/src/sound/win32_s.cpp b/src/sound/win32_s.cpp index 45f88172a9..c9c1a8afdc 100644 --- a/src/sound/win32_s.cpp +++ b/src/sound/win32_s.cpp @@ -19,6 +19,7 @@ #include "win32_s.h" #include #include +#include "../os/windows/win32.h" #include "../safeguards.h" @@ -41,6 +42,8 @@ static void PrepareHeader(WAVEHDR *hdr) static DWORD WINAPI SoundThread(LPVOID arg) { + SetWin32ThreadName(-1, "ottd:win-sound"); + do { for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) { if ((hdr->dwFlags & WHDR_INQUEUE) != 0) continue; diff --git a/src/tbtr_template_vehicle.cpp b/src/tbtr_template_vehicle.cpp index 001d36f8ad..d0310b0495 100644 --- a/src/tbtr_template_vehicle.cpp +++ b/src/tbtr_template_vehicle.cpp @@ -64,7 +64,7 @@ TemplateVehicle::TemplateVehicle(VehicleType ty, EngineID eid, byte subtypeflag, this->previous = 0x0; this->owner_b = _current_company; - this->cur_image = SPR_IMG_QUERY; + this->sprite_seq.Set(SPR_IMG_QUERY); this->owner = current_owner; diff --git a/src/tbtr_template_vehicle.h b/src/tbtr_template_vehicle.h index 82a655a676..760ef88ef8 100644 --- a/src/tbtr_template_vehicle.h +++ b/src/tbtr_template_vehicle.h @@ -90,7 +90,7 @@ public: uint32 max_te; byte spritenum; - SpriteID cur_image; + VehicleSpriteSeq sprite_seq; ///< Vehicle appearance. uint32 image_width; TemplateVehicle(VehicleType type = VEH_INVALID, EngineID e = INVALID_ENGINE, byte B = 0, Owner = _local_company); @@ -105,6 +105,7 @@ public: this->reuse_depot_vehicles = true; this->keep_remaining_vehicles = true; this->refit_as_template = true; + this->sprite_seq.count = 1; } ~TemplateVehicle(); diff --git a/src/tbtr_template_vehicle_func.cpp b/src/tbtr_template_vehicle_func.cpp index 43eb279663..c68d9be2e5 100644 --- a/src/tbtr_template_vehicle_func.cpp +++ b/src/tbtr_template_vehicle_func.cpp @@ -132,7 +132,7 @@ void DrawTemplate(const TemplateVehicle *tv, int left, int right, int y) while (t) { PaletteID pal = GetEnginePalette(t->engine_type, _current_company); - DrawSprite(t->cur_image, pal, offset + t->image_width / 2, ScaleGUITrad(11)); + t->sprite_seq.Draw(offset + t->image_width / 2, ScaleGUITrad(11), pal, false); offset += t->image_width; t = t->Next(); @@ -167,7 +167,7 @@ inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicl tmp->max_te = gcache->cached_max_te / 1000; tmp->spritenum = virt->spritenum; - tmp->cur_image = virt->GetImage(DIR_W, EIT_PURCHASE); + virt->GetImage(DIR_W, EIT_PURCHASE, &tmp->sprite_seq); Point *p = new Point(); tmp->image_width = virt->GetDisplayImageWidth(p); } diff --git a/src/thread/thread_win32.cpp b/src/thread/thread_win32.cpp index 5e158c2aca..446c1bafc7 100644 --- a/src/thread/thread_win32.cpp +++ b/src/thread/thread_win32.cpp @@ -16,6 +16,7 @@ #include #include #include +#include "../os/windows/win32.h" #include "../safeguards.h" @@ -29,17 +30,19 @@ private: OTTDThreadFunc proc; ///< External thread procedure. void *param; ///< Parameter for the external thread procedure. bool self_destruct; ///< Free ourselves when done? + const char *name; ///< Thread name. public: /** * Create a win32 thread and start it, calling proc(param). */ - ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct) : + ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) : thread(NULL), id(0), proc(proc), param(param), - self_destruct(self_destruct) + self_destruct(self_destruct), + name(name) { this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id); if (this->thread == NULL) return; @@ -85,6 +88,10 @@ private: */ void ThreadProc() { +#ifdef _MSC_VER + /* Set thread name for debuggers. Has to be done from the thread due to a race condition in older MS debuggers. */ + SetWin32ThreadName(-1, this->name); +#endif try { this->proc(this->param); } catch (OTTDThreadExitSignal) { @@ -98,7 +105,7 @@ private: /* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name) { - ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL); + ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL, name); if (thread != NULL) *thread = to; return true; } diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index ffbb0bc1f9..6c075ada23 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -1482,36 +1482,302 @@ class NWidgetMainToolbarContainer : public NWidgetToolbarContainer { { static const uint SMALLEST_ARRANGEMENT = 14; static const uint BIGGEST_ARRANGEMENT = 20; + + /* The number of buttons of each row of the toolbar should match the number of items which we want to be visible. + * The total number of buttons should be equal to arrangable_count * 2. + * No bad things happen, but we could see strange behaviours if we have buttons < (arrangable_count * 2) like a + * pause button appearing on the right of the lower toolbar and weird resizing of the widgets even if there is + * enough space. + */ static const byte arrange14[] = { - 0, 1, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 29, - 2, 3, 4, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_SETTINGS, + WID_TN_SAVE, + WID_TN_SMALL_MAP, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_GRAPHS, + WID_TN_INDUSTRIES, + WID_TN_MUSIC_SOUND, + WID_TN_MESSAGES, + WID_TN_HELP, + WID_TN_SWITCH_BAR, }; static const byte arrange15[] = { - 0, 1, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 2, 4, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SMALL_MAP, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_PAUSE, + WID_TN_SETTINGS, + WID_TN_SMALL_MAP, + WID_TN_SAVE, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_GRAPHS, + WID_TN_INDUSTRIES, + WID_TN_MUSIC_SOUND, + WID_TN_MESSAGES, + WID_TN_HELP, + WID_TN_SWITCH_BAR, }; static const byte arrange16[] = { - 0, 1, 2, 4, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 5, 6, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SETTINGS, + WID_TN_SMALL_MAP, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SAVE, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_GRAPHS, + WID_TN_INDUSTRIES, + WID_TN_MUSIC_SOUND, + WID_TN_MESSAGES, + WID_TN_HELP, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, }; static const byte arrange17[] = { - 0, 1, 2, 4, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 4, 6, 5, 7, 8, 9, 12, 14, 26, 27, 28, 19, 20, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SETTINGS, + WID_TN_SMALL_MAP, + WID_TN_SUBSIDIES, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SAVE, + WID_TN_SMALL_MAP, + WID_TN_SUBSIDIES, + WID_TN_TOWNS, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_GRAPHS, + WID_TN_INDUSTRIES, + WID_TN_MUSIC_SOUND, + WID_TN_MESSAGES, + WID_TN_HELP, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, }; static const byte arrange18[] = { - 0, 1, 2, 4, 5, 6, 7, 8, 9, 14, 21, 22, 23, 24, 25, 19, 20, 29, - 0, 1, 3, 4, 5, 6, 7, 12, 15, 16, 17, 18, 26, 27, 28, 19, 20, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SETTINGS, + WID_TN_SMALL_MAP, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_INDUSTRIES, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SAVE, + WID_TN_SMALL_MAP, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_STATIONS, + WID_TN_GRAPHS, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_MUSIC_SOUND, + WID_TN_MESSAGES, + WID_TN_HELP, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, }; static const byte arrange19[] = { - 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 19, 20, 29, - 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 28, 19, 20, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SETTINGS, + WID_TN_SMALL_MAP, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_MUSIC_SOUND, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SAVE, + WID_TN_SMALL_MAP, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_GRAPHS, + WID_TN_INDUSTRIES, + WID_TN_MESSAGES, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_HELP, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, }; static const byte arrange20[] = { - 0, 1, 2, 4, 5, 6, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26, 11, 19, 20, 29, - 0, 1, 3, 4, 7, 8, 9, 12, 14, 27, 21, 22, 23, 24, 25, 10, 28, 19, 20, 29, + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SETTINGS, + WID_TN_SMALL_MAP, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_MUSIC_SOUND, + WID_TN_GOAL, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, + // lower toolbar + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SAVE, + WID_TN_SMALL_MAP, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_GRAPHS, + WID_TN_INDUSTRIES, + WID_TN_MESSAGES, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_STORY, + WID_TN_HELP, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_SWITCH_BAR, }; static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28 + WID_TN_PAUSE, + WID_TN_FAST_FORWARD, + WID_TN_SETTINGS, + WID_TN_SAVE, + WID_TN_SMALL_MAP, + WID_TN_TOWNS, + WID_TN_SUBSIDIES, + WID_TN_STATIONS, + WID_TN_FINANCES, + WID_TN_COMPANIES, + WID_TN_STORY, + WID_TN_GOAL, + WID_TN_GRAPHS, + WID_TN_LEAGUE, + WID_TN_INDUSTRIES, + WID_TN_TRAINS, + WID_TN_ROADVEHS, + WID_TN_SHIPS, + WID_TN_AIRCRAFTS, + WID_TN_ZOOM_IN, + WID_TN_ZOOM_OUT, + WID_TN_RAILS, + WID_TN_ROADS, + WID_TN_WATER, + WID_TN_AIR, + WID_TN_LANDSCAPE, + WID_TN_MUSIC_SOUND, + WID_TN_MESSAGES, + WID_TN_HELP }; /* If at least BIGGEST_ARRANGEMENT fit, just spread all the buttons nicely */ @@ -1553,14 +1819,65 @@ class NWidgetScenarioToolbarContainer : public NWidgetToolbarContainer { /* virtual */ const byte *GetButtonArrangement(uint &width, uint &arrangable_count, uint &button_count, uint &spacer_count) const { static const byte arrange_all[] = { - 0, 1, 2, 3, 4, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, + WID_TE_PAUSE, + WID_TE_FAST_FORWARD, + WID_TE_SETTINGS, + WID_TE_SAVE, + WID_TE_SPACER, + WID_TE_DATE_PANEL, + WID_TE_SMALL_MAP, + WID_TE_ZOOM_IN, + WID_TE_ZOOM_OUT, + WID_TE_LAND_GENERATE, + WID_TE_TOWN_GENERATE, + WID_TE_INDUSTRY, + WID_TE_ROADS, + WID_TE_WATER, + WID_TE_TREES, + WID_TE_SIGNS, + WID_TE_MUSIC_SOUND, + WID_TE_HELP, }; static const byte arrange_nopanel[] = { - 0, 1, 2, 3, 18, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 26, 28, + WID_TE_PAUSE, + WID_TE_FAST_FORWARD, + WID_TE_SETTINGS, + WID_TE_SAVE, + WID_TE_DATE_PANEL, + WID_TE_SMALL_MAP, + WID_TE_ZOOM_IN, + WID_TE_ZOOM_OUT, + WID_TE_LAND_GENERATE, + WID_TE_TOWN_GENERATE, + WID_TE_INDUSTRY, + WID_TE_ROADS, + WID_TE_WATER, + WID_TE_TREES, + WID_TE_SIGNS, + WID_TE_MUSIC_SOUND, + WID_TE_HELP, }; static const byte arrange_switch[] = { - 18, 8, 11, 12, 13, 14, 15, 16, 17, 29, - 0, 1, 2, 3, 18, 9, 10, 26, 28, 29, + WID_TE_DATE_PANEL, + WID_TE_SMALL_MAP, + WID_TE_LAND_GENERATE, + WID_TE_TOWN_GENERATE, + WID_TE_INDUSTRY, + WID_TE_ROADS, + WID_TE_WATER, + WID_TE_TREES, + WID_TE_SIGNS, + WID_TE_SWITCH_BAR, + // lower toolbar + WID_TE_PAUSE, + WID_TE_FAST_FORWARD, + WID_TE_SETTINGS, + WID_TE_SAVE, + WID_TE_DATE_PANEL, + WID_TE_ZOOM_IN, + WID_TE_ZOOM_OUT, + WID_TE_MUSIC_SOUND, + WID_TE_HELP, WID_TE_SWITCH_BAR, }; /* If we can place all buttons *and* the panels, show them. */ @@ -1917,7 +2234,14 @@ static NWidgetBase *MakeMainToolbar(int *biggest_index) NWidgetMainToolbarContainer *hor = new NWidgetMainToolbarContainer(); for (uint i = 0; i < WID_TN_END; i++) { switch (i) { - case 4: case 8: case 15: case 19: case 21: case 26: hor->Add(new NWidgetSpacer(0, 0)); break; + case WID_TN_SMALL_MAP: + case WID_TN_FINANCES: + case WID_TN_VEHICLE_START: + case WID_TN_ZOOM_IN: + case WID_TN_BUILDING_TOOLS_START: + case WID_TN_MUSIC_SOUND: + hor->Add(new NWidgetSpacer(0, 0)); + break; } hor->Add(new NWidgetLeaf(i == WID_TN_SAVE ? WWT_IMGBTN_2 : WWT_IMGBTN, COLOUR_GREY, i, toolbar_button_sprites[i], STR_TOOLBAR_TOOLTIP_PAUSE_GAME + i)); } diff --git a/src/train.h b/src/train.h index aca0f89190..3173b03567 100644 --- a/src/train.h +++ b/src/train.h @@ -128,7 +128,7 @@ struct Train FINAL : public GroundVehicle { ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_TRAIN_INC : EXPENSES_TRAIN_RUN; } void PlayLeaveStationSound() const; bool IsPrimaryVehicle() const { return this->IsFrontEngine(); } - SpriteID GetImage(Direction direction, EngineImageType image_type) const; + void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const; int GetDisplaySpeed() const { return this->gcache.last_speed; } int GetDisplayMaxSpeed() const { return this->vcache.cached_max_speed; } Money GetRunningCost() const; diff --git a/src/train_cmd.cpp b/src/train_cmd.cpp index ebc9144687..08aacae246 100644 --- a/src/train_cmd.cpp +++ b/src/train_cmd.cpp @@ -545,41 +545,40 @@ static SpriteID GetDefaultTrainSprite(uint8 spritenum, Direction direction) * @param image_type Visualisation context. * @return Sprite to display. */ -SpriteID Train::GetImage(Direction direction, EngineImageType image_type) const +void Train::GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { uint8 spritenum = this->spritenum; - SpriteID sprite; if (HasBit(this->flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction); if (is_custom_sprite(spritenum)) { - sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type); - if (sprite != 0) return sprite; + GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum)), image_type, result); + if (result->IsValid()) return; spritenum = this->GetEngine()->original_image_index; } assert(IsValidImageIndex(spritenum)); - sprite = GetDefaultTrainSprite(spritenum, direction); + SpriteID sprite = GetDefaultTrainSprite(spritenum, direction); if (this->cargo.StoredCount() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum]; - return sprite; + result->Set(sprite); } -static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type) +static void GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImageType image_type, VehicleSpriteSeq *result) { const Engine *e = Engine::Get(engine); Direction dir = rear_head ? DIR_E : DIR_W; uint8 spritenum = e->u.rail.image_index; if (is_custom_sprite(spritenum)) { - SpriteID sprite = GetCustomVehicleIcon(engine, dir, image_type); - if (sprite != 0) { + GetCustomVehicleIcon(engine, dir, image_type, result); + if (result->IsValid()) { if (e->GetGRF() != NULL) { y += ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch); } - return sprite; + return; } spritenum = Engine::Get(engine)->original_image_index; @@ -587,7 +586,7 @@ static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y, EngineImage if (rear_head) spritenum++; - return GetDefaultTrainSprite(spritenum, DIR_W); + result->Set(GetDefaultTrainSprite(spritenum, DIR_W)); } void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engine, PaletteID pal, EngineImageType image_type) @@ -596,24 +595,31 @@ void DrawTrainEngine(int left, int right, int preferred_x, int y, EngineID engin int yf = y; int yr = y; - SpriteID spritef = GetRailIcon(engine, false, yf, image_type); - SpriteID spriter = GetRailIcon(engine, true, yr, image_type); - const Sprite *real_spritef = GetSprite(spritef, ST_NORMAL); - const Sprite *real_spriter = GetSprite(spriter, ST_NORMAL); + VehicleSpriteSeq seqf, seqr; + GetRailIcon(engine, false, yf, image_type, &seqf); + GetRailIcon(engine, true, yr, image_type, &seqr); + + Rect rectf, rectr; + seqf.GetBounds(&rectf); + seqr.GetBounds(&rectr); preferred_x = SoftClamp(preferred_x, - left - UnScaleGUI(real_spritef->x_offs) + ScaleGUITrad(14), - right - UnScaleGUI(real_spriter->width) - UnScaleGUI(real_spriter->x_offs) - ScaleGUITrad(15)); + left - UnScaleGUI(rectf.left) + ScaleGUITrad(14), + right - UnScaleGUI(rectr.right) - ScaleGUITrad(15)); - DrawSprite(spritef, pal, preferred_x - ScaleGUITrad(14), yf); - DrawSprite(spriter, pal, preferred_x + ScaleGUITrad(15), yr); + seqf.Draw(preferred_x - ScaleGUITrad(14), yf, pal, pal == PALETTE_CRASH); + seqr.Draw(preferred_x + ScaleGUITrad(15), yr, pal, pal == PALETTE_CRASH); } else { - SpriteID sprite = GetRailIcon(engine, false, y, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + GetRailIcon(engine, false, y, image_type, &seq); + + Rect rect; + seq.GetBounds(&rect); preferred_x = Clamp(preferred_x, - left - UnScaleGUI(real_sprite->x_offs), - right - UnScaleGUI(real_sprite->width) - UnScaleGUI(real_sprite->x_offs)); - DrawSprite(sprite, pal, preferred_x, y); + left - UnScaleGUI(rect.left), + right - UnScaleGUI(rect.right)); + + seq.Draw(preferred_x, y, pal, pal == PALETTE_CRASH); } } @@ -630,23 +636,26 @@ void GetTrainSpriteSize(EngineID engine, uint &width, uint &height, int &xoffs, { int y = 0; - SpriteID sprite = GetRailIcon(engine, false, y, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); + VehicleSpriteSeq seq; + GetRailIcon(engine, false, y, image_type, &seq); - width = UnScaleGUI(real_sprite->width); - height = UnScaleGUI(real_sprite->height); - xoffs = UnScaleGUI(real_sprite->x_offs); - yoffs = UnScaleGUI(real_sprite->y_offs); + Rect rect; + seq.GetBounds(&rect); + + width = UnScaleGUI(rect.right - rect.left + 1); + height = UnScaleGUI(rect.bottom - rect.top + 1); + xoffs = UnScaleGUI(rect.left); + yoffs = UnScaleGUI(rect.top); if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) { - sprite = GetRailIcon(engine, true, y, image_type); - real_sprite = GetSprite(sprite, ST_NORMAL); + GetRailIcon(engine, true, y, image_type, &seq); + seq.GetBounds(&rect); /* Calculate values relative to an imaginary center between the two sprites. */ - width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(real_sprite->width) + UnScaleGUI(real_sprite->x_offs) - xoffs; - height = max(height, UnScaleGUI(real_sprite->height)); + width = ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) + UnScaleGUI(rect.right) - xoffs; + height = max(height, UnScaleGUI(rect.bottom - rect.top + 1)); xoffs = xoffs - ScaleGUITrad(TRAININFO_DEFAULT_VEHICLE_WIDTH) / 2; - yoffs = min(yoffs, UnScaleGUI(real_sprite->y_offs)); + yoffs = min(yoffs, UnScaleGUI(rect.top)); } } @@ -702,7 +711,7 @@ static CommandCost CmdBuildRailWagon(TileIndex tile, DoCommandFlag flags, const v->date_of_last_service = _date; v->build_year = _cur_year; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); v->group_id = DEFAULT_GROUP; @@ -774,7 +783,7 @@ static void AddRearEngineToMultiheadedTrain(Train *v) u->reliability_spd_dec = v->reliability_spd_dec; u->date_of_last_service = v->date_of_last_service; u->build_year = v->build_year; - u->cur_image = SPR_IMG_QUERY; + u->sprite_seq.Set(SPR_IMG_QUERY); u->random_bits = VehicleRandomBits(); v->SetMultiheaded(); u->SetMultiheaded(); @@ -841,7 +850,7 @@ CommandCost CmdBuildRailVehicle(TileIndex tile, DoCommandFlag flags, const Engin v->SetServiceInterval(Company::Get(_current_company)->settings.vehicle.servint_trains); v->date_of_last_service = _date; v->build_year = _cur_year; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); if (e->flags & ENGINE_EXCLUSIVE_PREVIEW) SetBit(v->vehicle_flags, VF_BUILT_AS_PROTOTYPE); @@ -4095,14 +4104,14 @@ static void ChangeTrainDirRandomly(Train *v) /* We don't need to twist around vehicles if they're not visible */ if (!(v->vehstatus & VS_HIDDEN)) { v->direction = ChangeDir(v->direction, delta[GB(Random(), 0, 2)]); - v->UpdateDeltaXY(v->direction); - v->cur_image = v->GetImage(v->direction, EIT_ON_MAP); /* Refrain from updating the z position of the vehicle when on * a bridge, because UpdateInclination() will put the vehicle under * the bridge in that case */ if (v->track != TRACK_BIT_WORMHOLE) { v->UpdatePosition(); - v->UpdateInclination(false, false); + v->UpdateInclination(false, true); + } else { + v->UpdateViewport(false, true); } } } while ((v = v->Next()) != NULL); @@ -4719,7 +4728,7 @@ Train* CmdBuildVirtualRailWagon(const Engine *e) v->railtype = rvi->railtype; v->build_year = _cur_year; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); v->group_id = DEFAULT_GROUP; @@ -4795,7 +4804,7 @@ Train* CmdBuildVirtualRailVehicle(EngineID eid, bool lax_engine_check, StringID v->railtype = rvi->railtype; _new_vehicle_id = v->index; - v->cur_image = SPR_IMG_QUERY; + v->sprite_seq.Set(SPR_IMG_QUERY); v->random_bits = VehicleRandomBits(); v->group_id = DEFAULT_GROUP; diff --git a/src/train_gui.cpp b/src/train_gui.cpp index bafaf0296b..64bd8f156d 100644 --- a/src/train_gui.cpp +++ b/src/train_gui.cpp @@ -126,7 +126,9 @@ void DrawTrainImage(const Train *v, int left, int right, int y, VehicleID select if (rtl ? px + width > 0 : px - width < max_width) { PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); - DrawSprite(v->GetImage(dir, image_type), pal, px + (rtl ? -offset.x : offset.x), height / 2 + offset.y); + VehicleSpriteSeq seq; + v->GetImage(dir, image_type, &seq); + seq.Draw(px + (rtl ? -offset.x : offset.x), height / 2 + offset.y, pal, v->vehstatus & VS_CRASHED); } if (!v->IsArticulatedPart()) sel_articulated = false; @@ -440,7 +442,9 @@ void DrawTrainDetails(const Train *v, int left, int right, int y, int vscroll_po pitch = ScaleGUITrad(e->GetGRF()->traininfo_vehicle_pitch); } PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); - DrawSprite(u->GetImage(dir, EIT_IN_DETAILS), pal, px + (rtl ? -offset.x : offset.x), y - line_height * vscroll_pos + sprite_y_offset + pitch); + VehicleSpriteSeq seq; + u->GetImage(dir, EIT_IN_DETAILS, &seq); + seq.Draw(px + (rtl ? -offset.x : offset.x), y - line_height * vscroll_pos + sprite_y_offset + pitch, pal, v->vehstatus & VS_CRASHED); } px += rtl ? -width : width; dx += width; diff --git a/src/vehicle.cpp b/src/vehicle.cpp index 9dc4ba1e48..cd84eb3034 100644 --- a/src/vehicle.cpp +++ b/src/vehicle.cpp @@ -75,6 +75,47 @@ uint16 _returned_mail_refit_capacity; ///< Stores the mail capacity after a refi VehiclePool _vehicle_pool("Vehicle"); INSTANTIATE_POOL_METHODS(Vehicle) + +/** + * Determine shared bounds of all sprites. + * @param [out] bounds Shared bounds. + */ +void VehicleSpriteSeq::GetBounds(Rect *bounds) const +{ + bounds->left = bounds->top = bounds->right = bounds->bottom = 0; + for (uint i = 0; i < this->count; ++i) { + const Sprite *spr = GetSprite(this->seq[i].sprite, ST_NORMAL); + if (i == 0) { + bounds->left = spr->x_offs; + bounds->top = spr->y_offs; + bounds->right = spr->width + spr->x_offs - 1; + bounds->bottom = spr->height + spr->y_offs - 1; + } else { + if (spr->x_offs < bounds->left) bounds->left = spr->x_offs; + if (spr->y_offs < bounds->top) bounds->top = spr->y_offs; + int right = spr->width + spr->x_offs - 1; + int bottom = spr->height + spr->y_offs - 1; + if (right > bounds->right) bounds->right = right; + if (bottom > bounds->bottom) bounds->bottom = bottom; + } + } +} + +/** + * Draw the sprite sequence. + * @param x X position + * @param y Y position + * @param default_pal Vehicle palette + * @param force_pal Whether to ignore individual palettes, and draw everything with \a default_pal. + */ +void VehicleSpriteSeq::Draw(int x, int y, PaletteID default_pal, bool force_pal) const +{ + for (uint i = 0; i < this->count; ++i) { + PaletteID pal = force_pal || !this->seq[i].pal ? default_pal : this->seq[i].pal; + DrawSprite(this->seq[i].sprite, pal, x, y); + } +} + /** * Function to tell if a vehicle needs to be autorenewed * @param *c The vehicle owner @@ -1162,7 +1203,6 @@ void CallVehicleTicks() */ static void DoDrawVehicle(const Vehicle *v) { - SpriteID image = v->cur_image; PaletteID pal = PAL_NONE; if (v->vehstatus & VS_DEFPAL) pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); @@ -1177,8 +1217,14 @@ static void DoDrawVehicle(const Vehicle *v) if (to != TO_INVALID && (IsTransparencySet(to) || IsInvisibilitySet(to))) return; } - AddSortableSpriteToDraw(image, pal, v->x_pos + v->x_offs, v->y_pos + v->y_offs, - v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs); + StartSpriteCombine(); + for (uint i = 0; i < v->sprite_seq.count; ++i) { + PaletteID pal2 = v->sprite_seq.seq[i].pal; + if (!pal2 || (v->vehstatus & VS_CRASHED)) pal2 = pal; + AddSortableSpriteToDraw(v->sprite_seq.seq[i].sprite, pal2, v->x_pos + v->x_offs, v->y_pos + v->y_offs, + v->x_extent, v->y_extent, v->z_extent, v->z_pos, shadowed, v->x_bb_offs, v->y_bb_offs); + } + EndSpriteCombine(); } /** @@ -1899,20 +1945,19 @@ void Vehicle::UpdatePosition() */ void Vehicle::UpdateViewport(bool dirty) { - int img = this->cur_image; - Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos); - const Sprite *spr = GetSprite(img, ST_NORMAL); + Rect new_coord; + this->sprite_seq.GetBounds(&new_coord); - pt.x += spr->x_offs; - pt.y += spr->y_offs; + Point pt = RemapCoords(this->x_pos + this->x_offs, this->y_pos + this->y_offs, this->z_pos); + new_coord.left += pt.x; + new_coord.top += pt.y; + new_coord.right += pt.x + 2 * ZOOM_LVL_BASE; + new_coord.bottom += pt.y + 2 * ZOOM_LVL_BASE; - UpdateVehicleViewportHash(this, pt.x, pt.y); + UpdateVehicleViewportHash(this, new_coord.left, new_coord.top); Rect old_coord = this->coord; - this->coord.left = pt.x; - this->coord.top = pt.y; - this->coord.right = pt.x + spr->width + 2 * ZOOM_LVL_BASE; - this->coord.bottom = pt.y + spr->height + 2 * ZOOM_LVL_BASE; + this->coord = new_coord; if (dirty) { if (old_coord.left == INVALID_COORD) { diff --git a/src/vehicle_base.h b/src/vehicle_base.h index fbe29794f7..29f5620e2d 100644 --- a/src/vehicle_base.h +++ b/src/vehicle_base.h @@ -137,6 +137,63 @@ struct VehicleCache { byte cached_vis_effect; ///< Visual effect to show (see #VisualEffect) }; +/** Sprite sequence for a vehicle part. */ +struct VehicleSpriteSeq { + PalSpriteID seq[4]; + uint count; + + bool operator==(const VehicleSpriteSeq &other) const + { + return this->count == other.count && MemCmpT(this->seq, other.seq, this->count) == 0; + } + + bool operator!=(const VehicleSpriteSeq &other) const + { + return !this->operator==(other); + } + + /** + * Check whether the sequence contains any sprites. + */ + bool IsValid() const + { + return this->count != 0; + } + + /** + * Clear all information. + */ + void Clear() + { + this->count = 0; + } + + /** + * Assign a single sprite to the sequence. + */ + void Set(SpriteID sprite) + { + this->count = 1; + this->seq[0].sprite = sprite; + this->seq[0].pal = 0; + } + + /** + * Copy data from another sprite sequence, while dropping all recolouring information. + */ + void CopyWithoutPalette(const VehicleSpriteSeq &src) + { + this->count = src.count; + for (uint i = 0; i < src.count; ++i) { + this->seq[i].sprite = src.seq[i].sprite; + this->seq[i].pal = 0; + } + } + + void GetBounds(Rect *bounds) const; + void Draw(int x, int y, PaletteID default_pal, bool force_pal) const; +}; + /** A vehicle pool for a little over 1 million vehicles. */ typedef Pool VehiclePool; extern VehiclePool _vehicle_pool; @@ -230,7 +287,7 @@ public: * 0xff == reserved for another custom sprite */ byte spritenum; - SpriteID cur_image; ///< sprite number for this vehicle + VehicleSpriteSeq sprite_seq; ///< Vehicle appearance. byte x_extent; ///< x-extent of vehicle bounding box byte y_extent; ///< y-extent of vehicle bounding box byte z_extent; ///< z-extent of vehicle bounding box @@ -394,9 +451,9 @@ public: /** * Gets the sprite to show for the given direction * @param direction the direction the vehicle is facing - * @return the sprite for the given vehicle in the given direction + * @param [out] result Vehicle sprite sequence. */ - virtual SpriteID GetImage(Direction direction, EngineImageType image_type) const { return 0; } + virtual void GetImage(Direction direction, EngineImageType image_type, VehicleSpriteSeq *result) const { result->Clear(); } const GRFFile *GetGRF() const; uint32 GetGRFID() const; @@ -1012,7 +1069,10 @@ struct SpecializedVehicle : public Vehicle { /** * Set vehicle type correctly */ - inline SpecializedVehicle() : Vehicle(Type) { } + inline SpecializedVehicle() : Vehicle(Type) + { + this->sprite_seq.count = 1; + } /** * Get the first vehicle in the chain @@ -1154,15 +1214,20 @@ struct SpecializedVehicle : public Vehicle { /* Explicitly choose method to call to prevent vtable dereference - * it gives ~3% runtime improvements in games with many vehicles */ if (update_delta) ((T *)this)->T::UpdateDeltaXY(this->direction); - SpriteID old_image = this->cur_image; if (this->cur_image_valid_dir != this->direction) { _sprite_group_resolve_check_veh_check = true; _sprite_group_resolve_check_veh_type = EXPECTED_TYPE; - this->cur_image = ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP); + VehicleSpriteSeq seq; + ((T *)this)->T::GetImage(this->direction, EIT_ON_MAP, &seq); this->cur_image_valid_dir = _sprite_group_resolve_check_veh_check ? this->direction : INVALID_DIR; _sprite_group_resolve_check_veh_check = false; + if (force_update || this->sprite_seq != seq) { + this->sprite_seq = seq; + this->Vehicle::UpdateViewport(true); + } + } else if (force_update) { + this->Vehicle::UpdateViewport(true); } - if (force_update || this->cur_image != old_image) this->Vehicle::UpdateViewport(true); } }; diff --git a/src/vehicle_cmd.cpp b/src/vehicle_cmd.cpp index e20770dc52..fbf17639d4 100644 --- a/src/vehicle_cmd.cpp +++ b/src/vehicle_cmd.cpp @@ -850,7 +850,7 @@ inline void SetupTemplateVehicleFromVirtual(TemplateVehicle *tmp, TemplateVehicl tmp->max_te = gcache->cached_max_te / 1000; tmp->spritenum = virt->spritenum; - tmp->cur_image = virt->GetImage(DIR_W, EIT_PURCHASE); + virt->GetImage(DIR_W, EIT_PURCHASE, &tmp->sprite_seq); tmp->image_width = virt->GetDisplayImageWidth(); } diff --git a/src/vehicle_gui.cpp b/src/vehicle_gui.cpp index 7c9a9d0d2f..da16986513 100644 --- a/src/vehicle_gui.cpp +++ b/src/vehicle_gui.cpp @@ -2384,9 +2384,7 @@ struct VehicleDetailsWindow : Window { case WID_VD_MIDDLE_DETAILS: { /* For other vehicles, at the place of the matrix. */ bool rtl = _current_text_dir == TD_RTL; - uint sprite_width = UnScaleGUI( - max(GetSprite(v->GetImage(rtl ? DIR_E : DIR_W, EIT_IN_DETAILS), ST_NORMAL)->width, 70U)) + - WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; + uint sprite_width = GetSingleVehicleWidth(v, EIT_IN_DETAILS) + WD_FRAMERECT_LEFT + WD_FRAMERECT_RIGHT; uint text_left = r.left + (rtl ? 0 : sprite_width); uint text_right = r.right - (rtl ? sprite_width : 0); @@ -2672,8 +2670,8 @@ static const uint32 _vehicle_command_translation_table[][4] = { }; /** - * This is the Callback method after the cloning attempt of a vehicle - * @param result the result of the cloning command + * This is the Callback method after attempting to start/stop a vehicle + * @param result the result of the start/stop command * @param tile unused * @param p1 vehicle ID * @param p2 unused @@ -3201,9 +3199,11 @@ int GetSingleVehicleWidth(const Vehicle *v, EngineImageType image_type) default: bool rtl = _current_text_dir == TD_RTL; - SpriteID sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); - const Sprite *real_sprite = GetSprite(sprite, ST_NORMAL); - return UnScaleGUI(real_sprite->width); + VehicleSpriteSeq seq; + v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq); + Rect rec; + seq.GetBounds(&rec); + return UnScaleGUI(rec.right - rec.left + 1); } } @@ -3237,16 +3237,24 @@ void SetMouseCursorVehicle(const Vehicle *v, EngineImageType image_type) _cursor.sprite_count = 0; int total_width = 0; for (; v != NULL; v = v->HasArticulatedPart() ? v->GetNextArticulatedPart() : NULL) { - if (_cursor.sprite_count == lengthof(_cursor.sprite_seq)) break; if (total_width >= 2 * (int)VEHICLEINFO_FULL_VEHICLE_WIDTH) break; - _cursor.sprite_seq[_cursor.sprite_count].sprite = v->GetImage(rtl ? DIR_E : DIR_W, image_type); - _cursor.sprite_seq[_cursor.sprite_count].pal = GetVehiclePalette(v); - _cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width; - _cursor.sprite_pos[_cursor.sprite_count].y = 0; + PaletteID pal = (v->vehstatus & VS_CRASHED) ? PALETTE_CRASH : GetVehiclePalette(v); + VehicleSpriteSeq seq; + v->GetImage(rtl ? DIR_E : DIR_W, image_type, &seq); + + if (_cursor.sprite_count + seq.count > lengthof(_cursor.sprite_seq)) break; + + for (uint i = 0; i < seq.count; ++i) { + PaletteID pal2 = (v->vehstatus & VS_CRASHED) || !seq.seq[i].pal ? pal : seq.seq[i].pal; + _cursor.sprite_seq[_cursor.sprite_count].sprite = seq.seq[i].sprite; + _cursor.sprite_seq[_cursor.sprite_count].pal = pal2; + _cursor.sprite_pos[_cursor.sprite_count].x = rtl ? -total_width : total_width; + _cursor.sprite_pos[_cursor.sprite_count].y = 0; + _cursor.sprite_count++; + } total_width += GetSingleVehicleWidth(v, image_type); - _cursor.sprite_count++; } int offs = ((int)VEHICLEINFO_FULL_VEHICLE_WIDTH - total_width) / 2; diff --git a/src/video/cocoa/wnd_quartz.mm b/src/video/cocoa/wnd_quartz.mm index c93a1f6fb3..795a311bc6 100644 --- a/src/video/cocoa/wnd_quartz.mm +++ b/src/video/cocoa/wnd_quartz.mm @@ -110,15 +110,23 @@ static CGColorSpaceRef QZ_GetCorrectColorSpace() static CGColorSpaceRef colorSpace = NULL; if (colorSpace == NULL) { - CMProfileRef sysProfile; - - if (CMGetSystemProfile(&sysProfile) == noErr) { - colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysProfile); - CMCloseProfile(sysProfile); - } else { - colorSpace = CGColorSpaceCreateDeviceRGB(); +#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5) + if (MacOSVersionIsAtLeast(10, 5, 0)) { + colorSpace = CGDisplayCopyColorSpace(CGMainDisplayID()); + } else +#endif + { +#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5) && !defined(HAVE_OSX_1011_SDK) + CMProfileRef sysProfile; + if (CMGetSystemProfile(&sysProfile) == noErr) { + colorSpace = CGColorSpaceCreateWithPlatformColorSpace(sysProfile); + CMCloseProfile(sysProfile); + } +#endif } + if (colorSpace == NULL) colorSpace = CGColorSpaceCreateDeviceRGB(); + if (colorSpace == NULL) error("Could not get system colour space. You might need to recalibrate your monitor."); } diff --git a/src/video/dedicated_v.cpp b/src/video/dedicated_v.cpp index e038df9751..5e2be481c9 100644 --- a/src/video/dedicated_v.cpp +++ b/src/video/dedicated_v.cpp @@ -84,6 +84,7 @@ static void DedicatedSignalHandler(int sig) # endif # include # include +# include "../os/windows/win32.h" static HANDLE _hInputReady, _hWaitForInputHandling; static HANDLE _hThread; // Thread to close static char _win_console_thread_buffer[200]; @@ -95,6 +96,8 @@ static void WINAPI CheckForConsoleInput() /* WinCE doesn't support console stuff */ return; #else + SetWin32ThreadName(-1, "ottd:win-console"); + DWORD nb; HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE); for (;;) { diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 4dcc9eb703..c37ebd7dd6 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -1199,7 +1199,7 @@ void VideoDriver_Win32::MainLoop() _draw_threaded = false; } else { _draw_continue = true; - _draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread); + _draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread, "ottd:draw-win32"); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { diff --git a/src/widgets/toolbar_widget.h b/src/widgets/toolbar_widget.h index 6ede3ad634..434a238acc 100644 --- a/src/widgets/toolbar_widget.h +++ b/src/widgets/toolbar_widget.h @@ -36,7 +36,8 @@ enum ToolbarNormalWidgets { WID_TN_AIRCRAFTS, ///< Aircraft menu. WID_TN_ZOOM_IN, ///< Zoom in the main viewport. WID_TN_ZOOM_OUT, ///< Zoom out the main viewport. - WID_TN_RAILS, ///< Rail building menu. + WID_TN_BUILDING_TOOLS_START, ///< Helper for the offset of the building tools + WID_TN_RAILS = WID_TN_BUILDING_TOOLS_START, ///< Rail building menu. WID_TN_ROADS, ///< Road building menu. WID_TN_WATER, ///< Water building toolbar. WID_TN_AIR, ///< Airport building toolbar.