# HG changeset patch # User glx # Date 1208812550 0 # Node ID 7798ae816af8a9163934161e8ec502351ada1a18 # Parent 7856e972f8aa35d1db85946cdd750b685ec8d21d (svn r12826) [NoAI] -Sync: with trunk r12780:12824 diff -r 7856e972f8aa -r 7798ae816af8 projects/openttd_vs80.sln --- a/projects/openttd_vs80.sln Mon Apr 21 20:52:54 2008 +0000 +++ b/projects/openttd_vs80.sln Mon Apr 21 21:15:50 2008 +0000 @@ -1,5 +1,5 @@ Microsoft Visual Studio Solution File, Format Version 9.00 -# Visual Studio 2005 +# Visual C++ Express 2005 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openttd", "openttd_vs80.vcproj", "{668328A0-B40E-4CDB-BD72-D0064424414A}" ProjectSection(ProjectDependencies) = postProject {0F066B23-18DF-4284-8265-F4A5E7E3B966} = {0F066B23-18DF-4284-8265-F4A5E7E3B966} @@ -23,12 +23,10 @@ GlobalSection(ProjectConfigurationPlatforms) = postSolution {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.ActiveCfg = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|Win32.Build.0 = Debug|Win32 - {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|x64 - {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.Build.0 = Debug|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Debug|x64.ActiveCfg = Debug|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.ActiveCfg = Release|Win32 {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|Win32.Build.0 = Release|Win32 - {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|x64 - {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.Build.0 = Release|x64 + {668328A0-B40E-4CDB-BD72-D0064424414A}.Release|x64.ActiveCfg = Release|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.ActiveCfg = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|Win32.Build.0 = Debug|Win32 {A133A442-BD0A-4ADE-B117-AD7545E4BDD1}.Debug|x64.ActiveCfg = Debug|Win32 diff -r 7856e972f8aa -r 7798ae816af8 projects/openttd_vs80.vcproj --- a/projects/openttd_vs80.vcproj Mon Apr 21 20:52:54 2008 +0000 +++ b/projects/openttd_vs80.vcproj Mon Apr 21 21:15:50 2008 +0000 @@ -460,6 +460,10 @@ > + + @@ -544,6 +548,10 @@ > + + @@ -816,6 +824,10 @@ > + + @@ -964,6 +976,14 @@ > + + + + diff -r 7856e972f8aa -r 7798ae816af8 projects/openttd_vs90.vcproj --- a/projects/openttd_vs90.vcproj Mon Apr 21 20:52:54 2008 +0000 +++ b/projects/openttd_vs90.vcproj Mon Apr 21 21:15:50 2008 +0000 @@ -457,6 +457,10 @@ > + + @@ -541,6 +545,10 @@ > + + @@ -813,6 +821,10 @@ > + + @@ -961,6 +973,14 @@ > + + + + diff -r 7856e972f8aa -r 7798ae816af8 source.list --- a/source.list Mon Apr 21 20:52:54 2008 +0000 +++ b/source.list Mon Apr 21 21:15:50 2008 +0000 @@ -1,6 +1,7 @@ # Source Files airport.cpp core/alloc_func.cpp +animated_tile.cpp articulated_vehicles.cpp autoreplace_cmd.cpp aystar.cpp @@ -22,6 +23,7 @@ driver.cpp widgets/dropdown.cpp economy.cpp +effectvehicle.cpp elrail.cpp engine.cpp fileio.cpp @@ -125,6 +127,7 @@ airport_movement.h core/alloc_func.hpp core/alloc_type.hpp +animated_tile_func.h articulated_vehicles.h autoreplace_base.h autoreplace_func.h @@ -162,6 +165,8 @@ widgets/dropdown_type.h economy_func.h economy_type.h +effectvehicle_func.h +effectvehicle_base.h core/endian_func.hpp engine_func.h engine_type.h diff -r 7856e972f8aa -r 7798ae816af8 src/aircraft.h --- a/src/aircraft.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/aircraft.h Mon Apr 21 21:15:50 2008 +0000 @@ -119,7 +119,7 @@ ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_AIRCRAFT_INC : EXPENSES_AIRCRAFT_RUN; } WindowClass GetVehicleListWindowClass() const { return WC_AIRCRAFT_LIST; } bool IsPrimaryVehicle() const { return IsNormalAircraft(this); } - int GetImage(Direction direction) const; + SpriteID GetImage(Direction direction) const; int GetDisplaySpeed() const { return this->cur_speed * 10 / 16; } int GetDisplayMaxSpeed() const { return this->max_speed * 10 / 16; } Money GetRunningCost() const { return AircraftVehInfo(this->engine_type)->running_cost * _price.aircraft_running; } diff -r 7856e972f8aa -r 7798ae816af8 src/aircraft_cmd.cpp --- a/src/aircraft_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/aircraft_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -37,6 +37,7 @@ #include "player_func.h" #include "settings_type.h" #include "order_func.h" +#include "effectvehicle_func.h" #include "table/strings.h" #include "table/sprites.h" @@ -160,16 +161,17 @@ } #endif -int Aircraft::GetImage(Direction direction) const +SpriteID Aircraft::GetImage(Direction direction) const { - int spritenum = this->spritenum; + uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { - int sprite = GetCustomVehicleSprite(this, direction); + SpriteID sprite = GetCustomVehicleSprite(this, direction); + if (sprite != 0) return sprite; - if (sprite != 0) return sprite; spritenum = _orig_aircraft_vehicle_info[this->engine_type - AIRCRAFT_ENGINES_INDEX].image_index; } + return direction + _aircraft_sprite[spritenum]; } @@ -179,31 +181,33 @@ const Vehicle *w = v->Next()->Next(); if (is_custom_sprite(v->spritenum)) { - SpriteID spritenum = GetCustomRotorSprite(v, false); - if (spritenum != 0) return spritenum; + SpriteID sprite = GetCustomRotorSprite(v, false); + if (sprite != 0) return sprite; } /* Return standard rotor sprites if there are no custom sprites for this helicopter */ return SPR_ROTOR_STOPPED + w->u.air.state; } -void DrawAircraftEngine(int x, int y, EngineID engine, SpriteID pal) +static SpriteID GetAircraftIcon(EngineID engine) { - const AircraftVehicleInfo* avi = AircraftVehInfo(engine); - int spritenum = avi->image_index; - SpriteID sprite = (6 + _aircraft_sprite[spritenum]); + uint8 spritenum = AircraftVehInfo(engine)->image_index; if (is_custom_sprite(spritenum)) { - sprite = GetCustomVehicleIcon(engine, DIR_W); - if (sprite == 0) { - spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index; - sprite = (6 + _aircraft_sprite[spritenum]); - } + SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W); + if (sprite != 0) return sprite; + + spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index; } - DrawSprite(sprite, pal, x, y); + return 6 + _aircraft_sprite[spritenum]; +} - if (!(avi->subtype & AIR_CTOL)) { +void DrawAircraftEngine(int x, int y, EngineID engine, SpriteID pal) +{ + DrawSprite(GetAircraftIcon(engine), pal, x, y); + + if (!(AircraftVehInfo(engine)->subtype & AIR_CTOL)) { SpriteID rotor_sprite = GetCustomRotorIcon(engine); if (rotor_sprite == 0) rotor_sprite = SPR_ROTOR_STOPPED; DrawSprite(rotor_sprite, PAL_NONE, x, y - 5); @@ -217,21 +221,9 @@ */ void GetAircraftSpriteSize(EngineID engine, uint &width, uint &height) { - const AircraftVehicleInfo* avi = AircraftVehInfo(engine); - int spritenum = avi->image_index; - SpriteID sprite = (6 + _aircraft_sprite[spritenum]); + const Sprite *spr = GetSprite(GetAircraftIcon(engine)); - if (is_custom_sprite(spritenum)) { - sprite = GetCustomVehicleIcon(engine, DIR_W); - if (sprite == 0) { - spritenum = _orig_aircraft_vehicle_info[engine - AIRCRAFT_ENGINES_INDEX].image_index; - sprite = (6 + _aircraft_sprite[spritenum]); - } - } - - const Sprite *spr = GetSprite(sprite); - - width = spr->width ; + width = spr->width; height = spr->height; } @@ -528,7 +520,7 @@ /* Check if this aircraft can be started/stopped. The callback will fail or * return 0xFF if it can. */ uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); - if (callback != CALLBACK_FAILED && callback != 0xFF) { + if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) { StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback); return_cmd_error(error); } @@ -2089,7 +2081,7 @@ if (v->breakdown_ctr <= 2) { HandleBrokenAircraft(v); } else { - v->breakdown_ctr--; + if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } } diff -r 7856e972f8aa -r 7798ae816af8 src/animated_tile.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/animated_tile.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -0,0 +1,135 @@ +/* $Id$ */ + +/** @file animated_tile.cpp Everything related to animated tiles. */ + +#include "stdafx.h" +#include "openttd.h" +#include "saveload.h" +#include "landscape.h" +#include "core/alloc_func.hpp" +#include "functions.h" + +/** The table/list with animated tiles. */ +TileIndex *_animated_tile_list = NULL; +/** The number of animated tiles in the current state. */ +uint _animated_tile_count = 0; +/** The number of slots for animated tiles allocated currently. */ +static uint _animated_tile_allocated = 0; + +/** + * Removes the given tile from the animated tile table. + * @param tile the tile to remove + */ +void DeleteAnimatedTile(TileIndex tile) +{ + for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { + if (tile == *ti) { + /* Remove the hole + * The order of the remaining elements must stay the same, otherwise the animation loop + * may miss a tile; that's why we must use memmove instead of just moving the last element. + */ + memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti)); + _animated_tile_count--; + MarkTileDirtyByTile(tile); + return; + } + } +} + +/** + * Add the given tile to the animated tile table (if it does not exist + * on that table yet). Also increases the size of the table if necessary. + * @param tile the tile to make animated + */ +void AddAnimatedTile(TileIndex tile) +{ + MarkTileDirtyByTile(tile); + + for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { + if (tile == *ti) return; + } + + /* Table not large enough, so make it larger */ + if (_animated_tile_count == _animated_tile_allocated) { + _animated_tile_allocated *= 2; + _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); + } + + _animated_tile_list[_animated_tile_count] = tile; + _animated_tile_count++; +} + +/** + * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. + */ +void AnimateAnimatedTiles() +{ + const TileIndex *ti = _animated_tile_list; + while (ti < _animated_tile_list + _animated_tile_count) { + const TileIndex curr = *ti; + AnimateTile(curr); + /* During the AnimateTile call, DeleteAnimatedTile could have been called, + * deleting an element we've already processed and pushing the rest one + * slot to the left. We can detect this by checking whether the index + * in the current slot has changed - if it has, an element has been deleted, + * and we should process the current slot again instead of going forward. + * NOTE: this will still break if more than one animated tile is being + * deleted during the same AnimateTile call, but no code seems to + * be doing this anyway. + */ + if (*ti == curr) ++ti; + } +} + +/** + * Initialize all animated tile variables to some known begin point + */ +void InitializeAnimatedTiles() +{ + _animated_tile_list = ReallocT(_animated_tile_list, 256); + _animated_tile_count = 0; + _animated_tile_allocated = 256; +} + +/** + * Save the ANIT chunk. + */ +static void Save_ANIT() +{ + SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); + SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); +} + +/** + * Load the ANIT chunk; the chunk containing the animated tiles. + */ +static void Load_ANIT() +{ + /* Before version 80 we did NOT have a variable length animated tile table */ + if (CheckSavegameVersion(80)) { + /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ + SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); + + for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { + if (_animated_tile_list[_animated_tile_count] == 0) break; + } + return; + } + + _animated_tile_count = SlGetFieldLength() / sizeof(*_animated_tile_list); + + /* Determine a nice rounded size for the amount of allocated tiles */ + _animated_tile_allocated = 256; + while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; + + _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); + SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); +} + +/** + * "Definition" imported by the saveload code to be able to load and save + * the animated tile table. + */ +extern const ChunkHandler _animated_tile_chunk_handlers[] = { + { 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST}, +}; diff -r 7856e972f8aa -r 7798ae816af8 src/animated_tile_func.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/animated_tile_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -0,0 +1,15 @@ +/* $Id$ */ + +/** @file animated_tile.h Tile animation! */ + +#ifndef ANIMATED_TILE_H +#define ANIMATED_TILE_H + +#include "tile_type.h" + +void AddAnimatedTile(TileIndex tile); +void DeleteAnimatedTile(TileIndex tile); +void AnimateAnimatedTiles(); +void InitializeAnimatedTiles(); + +#endif /* ANIMATED_TILE_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/articulated_vehicles.cpp --- a/src/articulated_vehicles.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/articulated_vehicles.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -25,7 +25,7 @@ uint i; for (i = 1; i < MAX_UVALUE(EngineID); i++) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, v); - if (callback == CALLBACK_FAILED || callback == 0xFF) break; + if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break; } delete v; @@ -52,7 +52,7 @@ for (uint i = 1; i < MAX_UVALUE(EngineID); i++) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine, NULL); - if (callback == CALLBACK_FAILED || callback == 0xFF) break; + if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) break; EngineID artic_engine = GetFirstEngineOfType(type) + GB(callback, 0, 7); @@ -78,7 +78,7 @@ for (uint i = 1; i < MAX_UVALUE(EngineID); i++) { uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, v->engine_type, v); - if (callback == CALLBACK_FAILED || callback == 0xFF) return; + if (callback == CALLBACK_FAILED || GB(callback, 0, 8) == 0xFF) return; /* Attempt to use pre-allocated vehicles until they run out. This can happen * if the callback returns different values depending on the cargo type. */ diff -r 7856e972f8aa -r 7798ae816af8 src/autoreplace_cmd.cpp --- a/src/autoreplace_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/autoreplace_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -1,5 +1,7 @@ /* $Id$ */ +/** @file autoreplace_cmd.cpp Deals with autoreplace execution but not the setup */ + #include "stdafx.h" #include "openttd.h" #include "roadveh.h" @@ -117,31 +119,26 @@ return CT_NO_REFIT; // We failed to find a cargo type on the old vehicle and we will not refit the new one } -/* Replaces a vehicle (used to be called autorenew) +/** Replaces a vehicle (used to be called autorenew) * This function is only called from MaybeReplaceVehicle() * Must be called with _current_player set to the owner of the vehicle * @param w Vehicle to replace * @param flags is the flags to use when calling DoCommand(). Mainly DC_EXEC counts + * @param p The vehicle owner (faster than refinding the pointer) + * @param new_engine_type The EngineID to replace to * @return value is cost of the replacement or CMD_ERROR */ -static CommandCost ReplaceVehicle(Vehicle **w, byte flags, Money total_cost) +static CommandCost ReplaceVehicle(Vehicle **w, byte flags, Money total_cost, const Player *p, EngineID new_engine_type) { CommandCost cost; CommandCost sell_value; Vehicle *old_v = *w; - const Player *p = GetPlayer(old_v->owner); - EngineID new_engine_type; const UnitID cached_unitnumber = old_v->unitnumber; bool new_front = false; Vehicle *new_v = NULL; char *vehicle_name = NULL; CargoID replacement_cargo_type; - /* Check if there is a autoreplacement set for the vehicle */ - new_engine_type = EngineReplacementForPlayer(p, old_v->engine_type, old_v->group_id); - /* if not, just renew to the same type */ - if (new_engine_type == INVALID_ENGINE) new_engine_type = old_v->engine_type; - replacement_cargo_type = GetNewCargoTypeForReplace(old_v, new_engine_type); /* check if we can't refit to the needed type, so no replace takes place to prevent the vehicle from altering cargo type */ @@ -292,21 +289,103 @@ return cost; } +/** Removes wagons from a train until it get a certain length + * @param v The vehicle + * @param old_total_length The wanted max length + * @return The profit from selling the wagons + */ +static CommandCost WagonRemoval(Vehicle *v, uint16 old_total_length) +{ + if (v->type != VEH_TRAIN) return CommandCost(); + Vehicle *front = v; + + CommandCost cost = CommandCost(); + + while (front->u.rail.cached_total_length > old_total_length) { + /* the train is too long. We will remove cars one by one from the start of the train until it's short enough */ + while (v != NULL && RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON) { + /* We move backwards in the train until we find a wagon */ + v = GetNextVehicle(v); + } + + if (v == NULL) { + /* We sold all the wagons and the train is still not short enough */ + SetDParam(0, front->unitnumber); + AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, front->index, 0); + return cost; + } + + /* We found a wagon we can sell */ + Vehicle *temp = v; + v = GetNextVehicle(v); + DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); // remove the wagon from the train + MoveVehicleCargo(front, temp); // move the cargo back on the train + cost.AddCost(DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON)); // sell the wagon + } + return cost; +} + +/** Get the EngineID of the replacement for a vehicle + * @param v The vehicle to find a replacement for + * @param p The vehicle's owner (it's faster to forward the pointer than refinding it) + * @return the EngineID of the replacement. INVALID_ENGINE if no buildable replacement is found + */ +static EngineID GetNewEngineType(const Vehicle *v, const Player *p) +{ + if (v->type == VEH_TRAIN && IsRearDualheaded(v)) { + /* we build the rear ends of multiheaded trains with the front ones */ + return INVALID_ENGINE; + } + + EngineID e = EngineReplacementForPlayer(p, v->engine_type, v->group_id); + + if (e != INVALID_ENGINE && IsEngineBuildable(e, v->type, _current_player)) { + return e; + } + + if (v->NeedsAutorenewing(p) && // replace if engine is too old + IsEngineBuildable(v->engine_type, v->type, _current_player)) { // engine can still be build + return v->engine_type; + } + + return INVALID_ENGINE; +} + /** replaces a vehicle if it's set for autoreplace or is too old * (used to be called autorenew) * @param v The vehicle to replace * if the vehicle is a train, v needs to be the front engine - * @param check Checks if the replace is valid. No action is done at all - * @param display_costs If set, a cost animation is shown (only if check is false) - * @return CMD_ERROR if something went wrong. Otherwise the price of the replace + * @param flags + * @param display_costs If set, a cost animation is shown (only if DC_EXEC is set) + * This bool also takes autorenew money into consideration + * @return the costs, the success bool and sometimes an error message */ -CommandCost MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs) +CommandCost MaybeReplaceVehicle(Vehicle *v, uint32 flags, bool display_costs) { Vehicle *w; const Player *p = GetPlayer(v->owner); - byte flags = 0; - CommandCost cost, temp_cost; - bool stopped; + CommandCost cost; + bool stopped = false; + + /* We only want "real" vehicle types. */ + assert(IsPlayerBuildableVehicleType(v)); + + /* Ensure that this bool is cleared. */ + assert(!v->leave_depot_instantly); + + /* We can't sell if the current player don't own the vehicle. */ + assert(v->owner == _current_player); + + if (!v->IsInDepot()) { + /* The vehicle should be inside the depot */ + switch (v->type) { + default: NOT_REACHED(); + case VEH_TRAIN: return_cmd_error(STR_881A_TRAINS_CAN_ONLY_BE_ALTERED); break; + case VEH_ROAD: return_cmd_error(STR_9013_MUST_BE_STOPPED_INSIDE); break; + case VEH_SHIP: return_cmd_error(STR_980B_SHIP_MUST_BE_STOPPED_IN); break; + case VEH_AIRCRAFT: return_cmd_error(STR_A01B_AIRCRAFT_MUST_BE_STOPPED); break; + } + } /* Remember the length in case we need to trim train later on * If it's not a train, the value is unused @@ -317,38 +396,22 @@ -1 ); - - _current_player = v->owner; - - assert(IsPlayerBuildableVehicleType(v)); - - assert(v->vehstatus & VS_STOPPED); // the vehicle should have been stopped in VehicleEnteredDepotThisTick() if needed + if (!(v->vehstatus & VS_STOPPED)) { + /* The vehicle is moving so we better stop it before we might alter consist or sell it */ + v->vehstatus |= VS_STOPPED; + /* Remember that we stopped the vehicle */ + stopped = true; + } - /* Remember the flag v->leave_depot_instantly because if we replace the vehicle, the vehicle holding this flag will be sold - * If it is set, then we only stopped the vehicle to replace it (if needed) and we will need to start it again. - * We also need to reset the flag since it should remain false except from when the vehicle enters a depot until autoreplace is handled in the same tick */ - stopped = v->leave_depot_instantly; - v->leave_depot_instantly = false; - - for (;;) { + { cost = CommandCost(EXPENSES_NEW_VEHICLES); w = v; do { - if (w->type == VEH_TRAIN && IsRearDualheaded(w)) { - /* we build the rear ends of multiheaded trains with the front ones */ - continue; - } - - // check if the vehicle should be replaced - if (!w->NeedsAutorenewing(p) || // replace if engine is too old - w->max_age == 0) { // rail cars got a max age of 0 - if (!EngineHasReplacementForPlayer(p, w->engine_type, w->group_id)) continue; - } + EngineID new_engine = GetNewEngineType(w, p); + if (new_engine == INVALID_ENGINE) continue; /* Now replace the vehicle */ - temp_cost = ReplaceVehicle(&w, flags, cost.GetCost()); - - if (CmdFailed(temp_cost)) break; // replace failed for some reason. Leave the vehicle alone + cost.AddCost(ReplaceVehicle(&w, flags, cost.GetCost(), p, new_engine)); if (flags & DC_EXEC && (w->type != VEH_TRAIN || w->u.rail.first_engine == INVALID_ENGINE)) { @@ -358,11 +421,26 @@ */ v = w; } - cost.AddCost(temp_cost); } while (w->type == VEH_TRAIN && (w = GetNextVehicle(w)) != NULL); - if (!(flags & DC_EXEC) && (p->player_money < (cost.GetCost() + p->engine_renew_money) || cost.GetCost() == 0)) { - if (!check && p->player_money < (cost.GetCost() + p->engine_renew_money) && ( _local_player == v->owner ) && cost.GetCost() != 0) { + if (flags & DC_QUERY_COST || cost.GetCost() == 0) { + /* We didn't do anything during the replace so we will just exit here */ + if (stopped) v->vehstatus &= ~VS_STOPPED; + return cost; + } + + if (display_costs && !(flags & DC_EXEC)) { + /* We want to ensure that we will not get below p->engine_renew_money. + * We will not actually pay this amount. It's for display and checks only. */ + cost.AddCost((Money)p->engine_renew_money); + if (CmdSucceeded(cost) && GetAvailableMoneyForCommand() < cost.GetCost()) { + /* We don't have enough money so we will set cost to failed */ + cost.AddCost(CMD_ERROR); + } + } + + if (display_costs && CmdFailed(cost)) { + if (GetAvailableMoneyForCommand() < cost.GetCost() && IsLocalPlayer()) { StringID message; SetDParam(0, v->unitnumber); switch (v->type) { @@ -376,50 +454,22 @@ AddNewsItem(message, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0); } - if (stopped) v->vehstatus &= ~VS_STOPPED; - if (display_costs) _current_player = OWNER_NONE; - return CMD_ERROR; - } - - if (flags & DC_EXEC) { - break; // we are done replacing since the loop ran once with DC_EXEC - } else if (check) { - /* It's a test only and we know that we can do this - * NOTE: payment for wagon removal is NOT included in this price */ - return cost; - } - // now we redo the loop, but this time we actually do stuff since we know that we can do it - flags |= DC_EXEC; - } - - /* If setting is on to try not to exceed the old length of the train with the replacement */ - if (v->type == VEH_TRAIN && p->renew_keep_length) { - Vehicle *temp; - w = v; - - while (v->u.rail.cached_total_length > old_total_length) { - // the train is too long. We will remove cars one by one from the start of the train until it's short enough - while (w != NULL && RailVehInfo(w->engine_type)->railveh_type != RAILVEH_WAGON) { - w = GetNextVehicle(w); - } - if (w == NULL) { - // we failed to make the train short enough - SetDParam(0, v->unitnumber); - AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0); - break; - } - temp = w; - w = GetNextVehicle(w); - DoCommand(0, (INVALID_VEHICLE << 16) | temp->index, 0, DC_EXEC, CMD_MOVE_RAIL_VEHICLE); - MoveVehicleCargo(v, temp); - cost.AddCost(DoCommand(0, temp->index, 0, DC_EXEC, CMD_SELL_RAIL_WAGON)); } } + if (flags & DC_EXEC && CmdSucceeded(cost)) { + if (v->type == VEH_TRAIN && p->renew_keep_length) { + /* Remove wagons until the wanted length is reached */ + cost.AddCost(WagonRemoval(v, old_total_length)); + } + + if (display_costs && IsLocalPlayer()) { + ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost()); + } + } + + /* Start the vehicle if we stopped it earlier */ if (stopped) v->vehstatus &= ~VS_STOPPED; - if (display_costs) { - if (IsLocalPlayer()) ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost()); - _current_player = OWNER_NONE; - } + return cost; } diff -r 7856e972f8aa -r 7798ae816af8 src/cargopacket.h --- a/src/cargopacket.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/cargopacket.h Mon Apr 21 21:15:50 2008 +0000 @@ -22,13 +22,13 @@ * Container for cargo from the same location and time */ struct CargoPacket : PoolItem { - StationID source; ///< The station where the cargo came from first + Money feeder_share; ///< Value of feeder pickup to be paid for on delivery of cargo TileIndex source_xy; ///< The origin of the cargo (first station in feeder chain) TileIndex loaded_at_xy; ///< Location where this cargo has been loaded into the vehicle + StationID source; ///< The station where the cargo came from first uint16 count; ///< The amount of cargo in this packet byte days_in_transit; ///< Amount of days this packet has been in transit - Money feeder_share; ///< Value of feeder pickup to be paid for on delivery of cargo bool paid_for; ///< Have we been paid for this cargo packet? /** diff -r 7856e972f8aa -r 7798ae816af8 src/disaster_cmd.cpp --- a/src/disaster_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/disaster_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -39,6 +39,7 @@ #include "vehicle_func.h" #include "vehicle_base.h" #include "sound_func.h" +#include "effectvehicle_func.h" #include "table/strings.h" #include "table/sprites.h" diff -r 7856e972f8aa -r 7798ae816af8 src/economy.cpp --- a/src/economy.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/economy.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -26,6 +26,7 @@ #include "newgrf_callbacks.h" #include "newgrf_industries.h" #include "newgrf_industrytiles.h" +#include "newgrf_station.h" #include "unmovable.h" #include "cargotype.h" #include "player_face.h" @@ -1597,7 +1598,7 @@ byte load_amount = EngInfo(v->engine_type)->load_amount; if (_patches.gradual_loading && HasBit(EngInfo(v->engine_type)->callbackmask, CBM_VEHICLE_LOAD_AMOUNT)) { uint16 cb_load_amount = GetVehicleCallback(CBID_VEHICLE_LOAD_AMOUNT, 0, 0, v->engine_type, v); - if (cb_load_amount != CALLBACK_FAILED && cb_load_amount != 0) load_amount = cb_load_amount & 0xFF; + if (cb_load_amount != CALLBACK_FAILED && GB(cb_load_amount, 0, 8) != 0) load_amount = GB(cb_load_amount, 0, 8); } GoodsEntry *ge = &st->goods[v->cargo_type]; @@ -1694,6 +1695,8 @@ st->time_since_load = 0; st->last_vehicle_type = v->type; + StationAnimationTrigger(st, st->xy, STAT_ANIM_CARGO_TAKEN, v->cargo_type); + unloading_time += cap; result |= 2; diff -r 7856e972f8aa -r 7798ae816af8 src/effectvehicle.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/effectvehicle.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -0,0 +1,663 @@ +/* $Id$ */ + +/** @file vehicle.cpp */ + +#include "stdafx.h" +#include "openttd.h" +#include "road_map.h" +#include "roadveh.h" +#include "ship.h" +#include "spritecache.h" +#include "tile_cmd.h" +#include "landscape.h" +#include "timetable.h" +#include "viewport_func.h" +#include "gfx_func.h" +#include "news_func.h" +#include "command_func.h" +#include "saveload.h" +#include "player_func.h" +#include "debug.h" +#include "vehicle_gui.h" +#include "rail_type.h" +#include "train.h" +#include "aircraft.h" +#include "industry_map.h" +#include "station_map.h" +#include "water_map.h" +#include "network/network.h" +#include "yapf/yapf.h" +#include "newgrf_callbacks.h" +#include "newgrf_engine.h" +#include "newgrf_sound.h" +#include "group.h" +#include "order_func.h" +#include "strings_func.h" +#include "zoom_func.h" +#include "functions.h" +#include "date_func.h" +#include "window_func.h" +#include "vehicle_func.h" +#include "signal_func.h" +#include "sound_func.h" +#include "variables.h" +#include "autoreplace_func.h" +#include "autoreplace_gui.h" +#include "string_func.h" +#include "settings_type.h" +#include "oldpool_func.h" +#include "depot_map.h" +#include "animated_tile_func.h" +#include "effectvehicle_base.h" +#include "effectvehicle_func.h" + +#include "table/sprites.h" +#include "table/strings.h" + +static void ChimneySmokeInit(Vehicle *v) +{ + uint32 r = Random(); + v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3); + v->progress = GB(r, 16, 3); +} + +static void ChimneySmokeTick(Vehicle *v) +{ + if (v->progress > 0) { + v->progress--; + } else { + BeginVehicleMove(v); + + TileIndex tile = TileVirtXY(v->x_pos, v->y_pos); + if (!IsTileType(tile, MP_INDUSTRY)) { + EndVehicleMove(v); + delete v; + return; + } + + if (v->cur_image != SPR_CHIMNEY_SMOKE_7) { + v->cur_image++; + } else { + v->cur_image = SPR_CHIMNEY_SMOKE_0; + } + v->progress = 7; + VehiclePositionChanged(v); + EndVehicleMove(v); + } +} + +static void SteamSmokeInit(Vehicle *v) +{ + v->cur_image = SPR_STEAM_SMOKE_0; + v->progress = 12; +} + +static void SteamSmokeTick(Vehicle *v) +{ + bool moved = false; + + BeginVehicleMove(v); + + v->progress++; + + if ((v->progress & 7) == 0) { + v->z_pos++; + moved = true; + } + + if ((v->progress & 0xF) == 4) { + if (v->cur_image != SPR_STEAM_SMOKE_4) { + v->cur_image++; + } else { + EndVehicleMove(v); + delete v; + return; + } + moved = true; + } + + if (moved) { + VehiclePositionChanged(v); + EndVehicleMove(v); + } +} + +static void DieselSmokeInit(Vehicle *v) +{ + v->cur_image = SPR_DIESEL_SMOKE_0; + v->progress = 0; +} + +static void DieselSmokeTick(Vehicle *v) +{ + v->progress++; + + if ((v->progress & 3) == 0) { + BeginVehicleMove(v); + v->z_pos++; + VehiclePositionChanged(v); + EndVehicleMove(v); + } else if ((v->progress & 7) == 1) { + BeginVehicleMove(v); + if (v->cur_image != SPR_DIESEL_SMOKE_5) { + v->cur_image++; + VehiclePositionChanged(v); + EndVehicleMove(v); + } else { + EndVehicleMove(v); + delete v; + } + } +} + +static void ElectricSparkInit(Vehicle *v) +{ + v->cur_image = SPR_ELECTRIC_SPARK_0; + v->progress = 1; +} + +static void ElectricSparkTick(Vehicle *v) +{ + if (v->progress < 2) { + v->progress++; + } else { + v->progress = 0; + BeginVehicleMove(v); + if (v->cur_image != SPR_ELECTRIC_SPARK_5) { + v->cur_image++; + VehiclePositionChanged(v); + EndVehicleMove(v); + } else { + EndVehicleMove(v); + delete v; + } + } +} + +static void SmokeInit(Vehicle *v) +{ + v->cur_image = SPR_SMOKE_0; + v->progress = 12; +} + +static void SmokeTick(Vehicle *v) +{ + bool moved = false; + + BeginVehicleMove(v); + + v->progress++; + + if ((v->progress & 3) == 0) { + v->z_pos++; + moved = true; + } + + if ((v->progress & 0xF) == 4) { + if (v->cur_image != SPR_SMOKE_4) { + v->cur_image++; + } else { + EndVehicleMove(v); + delete v; + return; + } + moved = true; + } + + if (moved) { + VehiclePositionChanged(v); + EndVehicleMove(v); + } +} + +static void ExplosionLargeInit(Vehicle *v) +{ + v->cur_image = SPR_EXPLOSION_LARGE_0; + v->progress = 0; +} + +static void ExplosionLargeTick(Vehicle *v) +{ + v->progress++; + if ((v->progress & 3) == 0) { + BeginVehicleMove(v); + if (v->cur_image != SPR_EXPLOSION_LARGE_F) { + v->cur_image++; + VehiclePositionChanged(v); + EndVehicleMove(v); + } else { + EndVehicleMove(v); + delete v; + } + } +} + +static void BreakdownSmokeInit(Vehicle *v) +{ + v->cur_image = SPR_BREAKDOWN_SMOKE_0; + v->progress = 0; +} + +static void BreakdownSmokeTick(Vehicle *v) +{ + v->progress++; + if ((v->progress & 7) == 0) { + BeginVehicleMove(v); + if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) { + v->cur_image++; + } else { + v->cur_image = SPR_BREAKDOWN_SMOKE_0; + } + VehiclePositionChanged(v); + EndVehicleMove(v); + } + + v->u.effect.animation_state--; + if (v->u.effect.animation_state == 0) { + BeginVehicleMove(v); + EndVehicleMove(v); + delete v; + } +} + +static void ExplosionSmallInit(Vehicle *v) +{ + v->cur_image = SPR_EXPLOSION_SMALL_0; + v->progress = 0; +} + +static void ExplosionSmallTick(Vehicle *v) +{ + v->progress++; + if ((v->progress & 3) == 0) { + BeginVehicleMove(v); + if (v->cur_image != SPR_EXPLOSION_SMALL_B) { + v->cur_image++; + VehiclePositionChanged(v); + EndVehicleMove(v); + } else { + EndVehicleMove(v); + delete v; + } + } +} + +static void BulldozerInit(Vehicle *v) +{ + v->cur_image = SPR_BULLDOZER_NE; + v->progress = 0; + v->u.effect.animation_state = 0; + v->u.effect.animation_substate = 0; +} + +struct BulldozerMovement { + byte direction:2; + byte image:2; + byte duration:3; +}; + +static const BulldozerMovement _bulldozer_movement[] = { + { 0, 0, 4 }, + { 3, 3, 4 }, + { 2, 2, 7 }, + { 0, 2, 7 }, + { 1, 1, 3 }, + { 2, 2, 7 }, + { 0, 2, 7 }, + { 1, 1, 3 }, + { 2, 2, 7 }, + { 0, 2, 7 }, + { 3, 3, 6 }, + { 2, 2, 6 }, + { 1, 1, 7 }, + { 3, 1, 7 }, + { 0, 0, 3 }, + { 1, 1, 7 }, + { 3, 1, 7 }, + { 0, 0, 3 }, + { 1, 1, 7 }, + { 3, 1, 7 } +}; + +static const struct { + int8 x; + int8 y; +} _inc_by_dir[] = { + { -1, 0 }, + { 0, 1 }, + { 1, 0 }, + { 0, -1 } +}; + +static void BulldozerTick(Vehicle *v) +{ + v->progress++; + if ((v->progress & 7) == 0) { + const BulldozerMovement* b = &_bulldozer_movement[v->u.effect.animation_state]; + + BeginVehicleMove(v); + + v->cur_image = SPR_BULLDOZER_NE + b->image; + + v->x_pos += _inc_by_dir[b->direction].x; + v->y_pos += _inc_by_dir[b->direction].y; + + v->u.effect.animation_substate++; + if (v->u.effect.animation_substate >= b->duration) { + v->u.effect.animation_substate = 0; + v->u.effect.animation_state++; + if (v->u.effect.animation_state == lengthof(_bulldozer_movement)) { + EndVehicleMove(v); + delete v; + return; + } + } + VehiclePositionChanged(v); + EndVehicleMove(v); + } +} + +static void BubbleInit(Vehicle *v) +{ + v->cur_image = SPR_BUBBLE_GENERATE_0; + v->spritenum = 0; + v->progress = 0; +} + +struct BubbleMovement { + int8 x:4; + int8 y:4; + int8 z:4; + byte image:4; +}; + +#define MK(x, y, z, i) { x, y, z, i } +#define ME(i) { i, 4, 0, 0 } + +static const BubbleMovement _bubble_float_sw[] = { + MK(0, 0, 1, 0), + MK(1, 0, 1, 1), + MK(0, 0, 1, 0), + MK(1, 0, 1, 2), + ME(1) +}; + + +static const BubbleMovement _bubble_float_ne[] = { + MK( 0, 0, 1, 0), + MK(-1, 0, 1, 1), + MK( 0, 0, 1, 0), + MK(-1, 0, 1, 2), + ME(1) +}; + +static const BubbleMovement _bubble_float_se[] = { + MK(0, 0, 1, 0), + MK(0, 1, 1, 1), + MK(0, 0, 1, 0), + MK(0, 1, 1, 2), + ME(1) +}; + +static const BubbleMovement _bubble_float_nw[] = { + MK(0, 0, 1, 0), + MK(0, -1, 1, 1), + MK(0, 0, 1, 0), + MK(0, -1, 1, 2), + ME(1) +}; + +static const BubbleMovement _bubble_burst[] = { + MK(0, 0, 1, 2), + MK(0, 0, 1, 7), + MK(0, 0, 1, 8), + MK(0, 0, 1, 9), + ME(0) +}; + +static const BubbleMovement _bubble_absorb[] = { + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(0, 0, 1, 0), + MK(0, 0, 1, 2), + MK(0, 0, 1, 0), + MK(0, 0, 1, 1), + MK(2, 1, 3, 0), + MK(1, 1, 3, 1), + MK(2, 1, 3, 0), + MK(1, 1, 3, 2), + MK(2, 1, 3, 0), + MK(1, 1, 3, 1), + MK(2, 1, 3, 0), + MK(1, 0, 1, 2), + MK(0, 0, 1, 0), + MK(1, 0, 1, 1), + MK(0, 0, 1, 0), + MK(1, 0, 1, 2), + MK(0, 0, 1, 0), + MK(1, 0, 1, 1), + MK(0, 0, 1, 0), + MK(1, 0, 1, 2), + ME(2), + MK(0, 0, 0, 0xA), + MK(0, 0, 0, 0xB), + MK(0, 0, 0, 0xC), + MK(0, 0, 0, 0xD), + MK(0, 0, 0, 0xE), + ME(0) +}; +#undef ME +#undef MK + +static const BubbleMovement * const _bubble_movement[] = { + _bubble_float_sw, + _bubble_float_ne, + _bubble_float_se, + _bubble_float_nw, + _bubble_burst, + _bubble_absorb, +}; + +static void BubbleTick(Vehicle *v) +{ + /* + * Warning: those effects can NOT use Random(), and have to use + * InteractiveRandom(), because somehow someone forgot to save + * spritenum to the savegame, and so it will cause desyncs in + * multiplayer!! (that is: in ToyLand) + */ + uint et; + + v->progress++; + if ((v->progress & 3) != 0) return; + + BeginVehicleMove(v); + + if (v->spritenum == 0) { + v->cur_image++; + if (v->cur_image < SPR_BUBBLE_GENERATE_3) { + VehiclePositionChanged(v); + EndVehicleMove(v); + return; + } + if (v->u.effect.animation_substate != 0) { + v->spritenum = GB(InteractiveRandom(), 0, 2) + 1; + } else { + v->spritenum = 6; + } + et = 0; + } else { + et = v->engine_type + 1; + } + + const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][et]; + + if (b->y == 4 && b->x == 0) { + EndVehicleMove(v); + delete v; + return; + } + + if (b->y == 4 && b->x == 1) { + if (v->z_pos > 180 || Chance16I(1, 96, InteractiveRandom())) { + v->spritenum = 5; + SndPlayVehicleFx(SND_2F_POP, v); + } + et = 0; + } + + if (b->y == 4 && b->x == 2) { + TileIndex tile; + + et++; + SndPlayVehicleFx(SND_31_EXTRACT, v); + + tile = TileVirtXY(v->x_pos, v->y_pos); + if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile); + } + + v->engine_type = et; + b = &_bubble_movement[v->spritenum - 1][et]; + + v->x_pos += b->x; + v->y_pos += b->y; + v->z_pos += b->z; + v->cur_image = SPR_BUBBLE_0 + b->image; + + VehiclePositionChanged(v); + EndVehicleMove(v); +} + + +typedef void EffectInitProc(Vehicle *v); +typedef void EffectTickProc(Vehicle *v); + +static EffectInitProc * const _effect_init_procs[] = { + ChimneySmokeInit, + SteamSmokeInit, + DieselSmokeInit, + ElectricSparkInit, + SmokeInit, + ExplosionLargeInit, + BreakdownSmokeInit, + ExplosionSmallInit, + BulldozerInit, + BubbleInit, +}; + +static EffectTickProc * const _effect_tick_procs[] = { + ChimneySmokeTick, + SteamSmokeTick, + DieselSmokeTick, + ElectricSparkTick, + SmokeTick, + ExplosionLargeTick, + BreakdownSmokeTick, + ExplosionSmallTick, + BulldozerTick, + BubbleTick, +}; + + +Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type) +{ + Vehicle *v = new EffectVehicle(); + if (v != NULL) { + v->subtype = type; + v->x_pos = x; + v->y_pos = y; + v->z_pos = z; + v->tile = 0; + v->UpdateDeltaXY(INVALID_DIR); + v->vehstatus = VS_UNCLICKABLE; + + _effect_init_procs[type](v); + + VehiclePositionChanged(v); + BeginVehicleMove(v); + EndVehicleMove(v); + } + return v; +} + +Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type) +{ + int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); + int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE); + return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type); +} + +Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type) +{ + return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type); +} + +void EffectVehicle::Tick() +{ + _effect_tick_procs[this->subtype](this); +} + +void EffectVehicle::UpdateDeltaXY(Direction direction) +{ + this->x_offs = 0; + this->y_offs = 0; + this->x_extent = 1; + this->y_extent = 1; + this->z_extent = 1; +} diff -r 7856e972f8aa -r 7798ae816af8 src/effectvehicle_base.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/effectvehicle_base.h Mon Apr 21 21:15:50 2008 +0000 @@ -0,0 +1,37 @@ +/* $Id$ */ + +/** @file effectvehicle_base.h Base class for all effect vehicles. */ + +#ifndef EFFECTVEHICLE_BASE_H +#define EFFECTVEHICLE_BASE_H + +#include "vehicle_base.h" + +/** + * This class 'wraps' Vehicle; you do not actually instantiate this class. + * You create a Vehicle using AllocateVehicle, so it is added to the pool + * and you reinitialize that to a Train using: + * v = new (v) Train(); + * + * As side-effect the vehicle type is set correctly. + * + * A special vehicle is one of the following: + * - smoke + * - electric sparks for trains + * - explosions + * - bulldozer (road works) + * - bubbles (industry) + */ +struct EffectVehicle : public Vehicle { + /** Initializes the Vehicle to a special vehicle */ + EffectVehicle() { this->type = VEH_EFFECT; } + + /** We want to 'destruct' the right class. */ + virtual ~EffectVehicle() {} + + const char *GetTypeString() const { return "special vehicle"; } + void UpdateDeltaXY(Direction direction); + void Tick(); +}; + +#endif /* EFFECTVEHICLE_BASE_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/effectvehicle_func.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/effectvehicle_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -0,0 +1,28 @@ +/* $Id$ */ + +/** @file effectvehicle.h Functions related to effect vehicles. */ + +#ifndef EFFECTVEHICLE_FUNC_H +#define EFFECTVEHICLE_FUNC_H + +#include "vehicle_type.h" + +/** Effect vehicle types */ +enum EffectVehicleType { + EV_CHIMNEY_SMOKE = 0, + EV_STEAM_SMOKE = 1, + EV_DIESEL_SMOKE = 2, + EV_ELECTRIC_SPARK = 3, + EV_SMOKE = 4, + EV_EXPLOSION_LARGE = 5, + EV_BREAKDOWN_SMOKE = 6, + EV_EXPLOSION_SMALL = 7, + EV_BULLDOZER = 8, + EV_BUBBLE = 9 +}; + +Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicleType type); +Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicleType type); +Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicleType type); + +#endif /* EFFECTVEHICLE_FUNC_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/engine_func.h --- a/src/engine_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/engine_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -1,6 +1,6 @@ /* $Id$ */ -/** @file engine.h */ +/** @file engine_func.h */ #ifndef ENGINE_H #define ENGINE_H diff -r 7856e972f8aa -r 7798ae816af8 src/functions.h --- a/src/functions.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/functions.h Mon Apr 21 21:15:50 2008 +0000 @@ -23,21 +23,11 @@ bool CheckOwnership(Owner owner); bool CheckTileOwnership(TileIndex tile); -/* texteff.cpp */ -void AddAnimatedTile(TileIndex tile); -void DeleteAnimatedTile(TileIndex tile); -void AnimateAnimatedTiles(); -void InitializeAnimatedTiles(); - /* misc_cmd.cpp */ void PlaceTreesRandomly(); void InitializeLandscapeVariables(bool only_constants); -/* misc.cpp */ -bool IsCustomName(StringID id); -char *CopyFromOldName(StringID id); - /* misc functions */ /** * Mark a tile given by its coordinate dirty for repaint. @@ -69,14 +59,10 @@ void RedrawAutosave(); -StringID RemapOldStringID(StringID s); - void UpdateViewportSignPos(ViewportSign *sign, int left, int top, StringID str); - /* callback from drivers that is called if the game size changes dynamically */ void GameSizeChanged(); -const char *GetCurrentLocale(const char *param); int ttd_main(int argc, char* argv[]); void HandleExitGameRequest(); diff -r 7856e972f8aa -r 7798ae816af8 src/industry_cmd.cpp --- a/src/industry_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/industry_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -39,6 +39,8 @@ #include "sound_func.h" #include "station_base.h" #include "oldpool_func.h" +#include "animated_tile_func.h" +#include "effectvehicle_func.h" #include "table/strings.h" #include "table/sprites.h" @@ -620,7 +622,7 @@ } } -static void CreateIndustryEffectSmoke(TileIndex tile) +static void CreateChimneySmoke(TileIndex tile) { uint x = TileX(tile) * TILE_SIZE; uint y = TileY(tile) * TILE_SIZE; @@ -657,7 +659,7 @@ switch (gfx) { case GFX_POWERPLANT_CHIMNEY: - CreateIndustryEffectSmoke(tile); + CreateChimneySmoke(tile); break; case GFX_OILRIG_1: @@ -684,10 +686,10 @@ { int dir; Vehicle *v; - static const int8 _tileloop_ind_case_161[12] = { - 11, 0, -4, -14, - -4, -10, -4, 1, - 49, 59, 60, 65, + static const int8 _bubble_spawn_location[3][4] = { + { 11, 0, -4, -14 }, + { -4, -10, -4, 1 }, + { 49, 59, 60, 65 }, }; SndPlayTileFx(SND_2E_EXTRACT_AND_POP, tile); @@ -695,13 +697,13 @@ dir = Random() & 3; v = CreateEffectVehicleAbove( - TileX(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 0], - TileY(tile) * TILE_SIZE + _tileloop_ind_case_161[dir + 4], - _tileloop_ind_case_161[dir + 8], + TileX(tile) * TILE_SIZE + _bubble_spawn_location[0][dir], + TileY(tile) * TILE_SIZE + _bubble_spawn_location[1][dir], + _bubble_spawn_location[2][dir], EV_BUBBLE ); - if (v != NULL) v->u.special.animation_substate = dir; + if (v != NULL) v->u.effect.animation_substate = dir; } static void TileLoop_Industry(TileIndex tile) diff -r 7856e972f8aa -r 7798ae816af8 src/industry_gui.cpp --- a/src/industry_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/industry_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -78,8 +78,8 @@ { if (HasBit(indspec->callback_flags, CBM_IND_CARGO_SUFFIX)) { bool fund = ind == NULL; - uint8 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, ((!fund) ? 1 << 8 : 0) | cargo, ind, ind_type, (!fund) ? ind->xy : INVALID_TILE); - if (callback != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback); + uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, ((!fund) ? 1 << 8 : 0) | cargo, ind, ind_type, (!fund) ? ind->xy : INVALID_TILE); + if (GB(callback, 0, 8) != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback); } return STR_EMPTY; } @@ -631,7 +631,7 @@ WP(w, indview_d).editbox_line = 0; WP(w, indview_d).clicked_line = 0; WP(w, indview_d).clicked_button = 0; - AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY); + InitializeWindowViewport(w, 3, 17, 254, 86, GetIndustry(w->window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY); } } diff -r 7856e972f8aa -r 7798ae816af8 src/landscape.cpp --- a/src/landscape.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/landscape.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -24,6 +24,7 @@ #include "vehicle_func.h" #include "settings_type.h" #include "water.h" +#include "effectvehicle_func.h" #include "table/sprites.h" diff -r 7856e972f8aa -r 7798ae816af8 src/lang/english.txt --- a/src/lang/english.txt Mon Apr 21 20:52:54 2008 +0000 +++ b/src/lang/english.txt Mon Apr 21 21:15:50 2008 +0000 @@ -1066,7 +1066,7 @@ STR_CONFIG_PATCHES_WARN_INCOME_LESS :{LTBLUE}Warn if a train's income is negative: {ORANGE}{STRING1} STR_CONFIG_PATCHES_NEVER_EXPIRE_VEHICLES :{LTBLUE}Vehicles never expire: {ORANGE}{STRING1} STR_CONFIG_PATCHES_AUTORENEW_VEHICLE :{LTBLUE}Autorenew vehicle when it gets old -STR_CONFIG_PATCHES_AUTORENEW_MONTHS :{LTBLUE}Autorenew when vehice is {ORANGE}{STRING1}{LTBLUE} months before/after max age +STR_CONFIG_PATCHES_AUTORENEW_MONTHS :{LTBLUE}Autorenew when vehicle is {ORANGE}{STRING1}{LTBLUE} months before/after max age STR_CONFIG_PATCHES_AUTORENEW_MONEY :{LTBLUE}Autorenew minimum needed money for renew: {ORANGE}{STRING1} STR_CONFIG_PATCHES_ERRMSG_DURATION :{LTBLUE}Duration of error message: {ORANGE}{STRING1} STR_CONFIG_PATCHES_POPULATION_IN_LABEL :{LTBLUE}Show town population in the town name label: {ORANGE}{STRING1} diff -r 7856e972f8aa -r 7798ae816af8 src/main_gui.cpp --- a/src/main_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/main_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -413,7 +413,7 @@ int height = _screen.height; Window *w = AllocateWindow(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL); - AssignWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT); + InitializeWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT); /* XXX: these are not done */ switch (_game_mode) { diff -r 7856e972f8aa -r 7798ae816af8 src/misc.cpp --- a/src/misc.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/misc.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -23,15 +23,14 @@ #include "date_func.h" #include "vehicle_func.h" #include "texteff.hpp" -#include "string_func.h" #include "gfx_func.h" #include "core/alloc_type.hpp" +#include "animated_tile_func.h" #include "settings_type.h" #include "table/strings.h" #include "table/sprites.h" -char _name_array[512][32]; extern TileIndex _cur_tileloop_tile; void InitializeVehicles(); @@ -50,10 +49,10 @@ void InitializeSigns(); void InitializeStations(); void InitializeCargoPackets(); -static void InitializeNameMgr(); void InitializePlayers(); void InitializeCheats(); void InitializeNPF(); +void InitializeOldNames(); void InitializeGame(int mode, uint size_x, uint size_y) { @@ -94,7 +93,7 @@ InitializeIndustries(); InitializeBuildingCounts(); - InitializeNameMgr(); + InitializeOldNames(); InitializeVehiclesGuiList(); InitializeTrains(); InitializeNPF(); @@ -112,60 +111,6 @@ ResetObjectToPlace(); } -bool IsCustomName(StringID id) -{ - return GB(id, 11, 5) == 15; -} - - -static void InitializeNameMgr() -{ - memset(_name_array, 0, sizeof(_name_array)); -} - -/* Copy and convert old custom names to UTF-8 */ -char *CopyFromOldName(StringID id) -{ - if (!IsCustomName(id)) return NULL; - - if (CheckSavegameVersion(37)) { - /* Old names were 32 characters long, so 128 characters should be - * plenty to allow for expansion when converted to UTF-8. */ - char tmp[128]; - const char *strfrom = _name_array[GB(id, 0, 9)]; - char *strto = tmp; - - for (; *strfrom != '\0'; strfrom++) { - WChar c = (byte)*strfrom; - - /* Map from non-ISO8859-15 characters to UTF-8. */ - switch (c) { - case 0xA4: c = 0x20AC; break; // Euro - case 0xA6: c = 0x0160; break; // S with caron - case 0xA8: c = 0x0161; break; // s with caron - case 0xB4: c = 0x017D; break; // Z with caron - case 0xB8: c = 0x017E; break; // z with caron - case 0xBC: c = 0x0152; break; // OE ligature - case 0xBD: c = 0x0153; break; // oe ligature - case 0xBE: c = 0x0178; break; // Y with diaresis - default: break; - } - - /* Check character will fit into our buffer. */ - if (strto + Utf8CharLen(c) > lastof(tmp)) break; - - strto += Utf8Encode(strto, c); - } - - /* Terminate the new string and copy it back to the name array */ - *strto = '\0'; - - return strdup(tmp); - } else { - /* Name will already be in UTF-8. */ - return strdup(_name_array[GB(id, 0, 9)]); - } -} /* Calculate constants that depend on the landscape type. */ void InitializeLandscapeVariables(bool only_constants) @@ -178,15 +123,6 @@ } } -static void Load_NAME() -{ - int index; - - while ((index = SlIterateArray()) != -1) { - SlArray(_name_array[index], SlGetFieldLength(), SLE_UINT8); - } -} - static const SaveLoadGlobVarList _date_desc[] = { SLEG_CONDVAR(_date, SLE_FILE_U16 | SLE_VAR_I32, 0, 30), SLEG_CONDVAR(_date, SLE_INT32, 31, SL_MAX_VERSION), @@ -470,7 +406,6 @@ { 'MAPE', Save_MAP6, Load_MAP6, CH_RIFF }, { 'MAP7', Save_MAP7, Load_MAP7, CH_RIFF }, - { 'NAME', NULL, Load_NAME, CH_ARRAY}, { 'DATE', SaveLoad_DATE, SaveLoad_DATE, CH_RIFF}, { 'VIEW', SaveLoad_VIEW, SaveLoad_VIEW, CH_RIFF | CH_LAST}, }; diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf.cpp --- a/src/newgrf.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -1120,19 +1120,17 @@ statspec->blocked = grf_load_byte(&buf); break; - case 0x16: // @todo Animation info - grf_load_word(&buf); - ret = true; - break; - - case 0x17: // @todo Animation speed - grf_load_byte(&buf); - ret = true; - break; - - case 0x18: // @todo Animation triggers - grf_load_word(&buf); - ret = true; + case 0x16: // Animation info + statspec->anim_frames = grf_load_byte(&buf); + statspec->anim_status = grf_load_byte(&buf); + break; + + case 0x17: // Animation speed + statspec->anim_speed = grf_load_byte(&buf); + break; + + case 0x18: // Animation triggers + statspec->anim_triggers = grf_load_word(&buf); break; default: diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_callbacks.h --- a/src/newgrf_callbacks.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_callbacks.h Mon Apr 21 21:15:50 2008 +0000 @@ -28,193 +28,188 @@ /** Powered wagons, if the result is lower as 0x40 then the wagon is powered * @todo : interpret the rest of the result, aka "visual effects". */ - CBID_TRAIN_WAGON_POWER = 0x10, + CBID_TRAIN_WAGON_POWER = 0x10, // 8 bit callback /** Vehicle length, returns the amount of 1/8's the vehicle is shorter for trains and RVs. */ CBID_VEHICLE_LENGTH = 0x11, /** Determine the amount of cargo to load per unit of time when using gradual loading. */ - CBID_VEHICLE_LOAD_AMOUNT = 0x12, + CBID_VEHICLE_LOAD_AMOUNT = 0x12, // 8 bit callback /** Determine whether a newstation should be made available to build. */ - CBID_STATION_AVAILABILITY = 0x13, + CBID_STATION_AVAILABILITY = 0x13, // 8 bit callback /** Choose a sprite layout to draw, instead of the standard 0-7 range. */ CBID_STATION_SPRITE_LAYOUT = 0x14, /** Refit capacity, the passed vehicle needs to have its ->cargo_type set to * the cargo we are refitting to, returns the new cargo capacity. */ - CBID_VEHICLE_REFIT_CAPACITY = 0x15, + CBID_VEHICLE_REFIT_CAPACITY = 0x15, // 15 bit callback /** Builds articulated engines for trains and RVs. */ - CBID_VEHICLE_ARTIC_ENGINE = 0x16, + CBID_VEHICLE_ARTIC_ENGINE = 0x16, // 8 bit callback /** Determine whether the house can be built on the specified tile. */ - CBID_HOUSE_ALLOW_CONSTRUCTION = 0x17, + CBID_HOUSE_ALLOW_CONSTRUCTION = 0x17, // 8 bit callback /** AI construction/purchase selection */ - CBID_GENERIC_AI_PURCHASE_SELECTION = 0x18, // not implemented + CBID_GENERIC_AI_PURCHASE_SELECTION = 0x18, // 8 bit callback, not implemented /** Determine the cargo "suffixes" for each refit possibility of a cargo. */ CBID_VEHICLE_CARGO_SUFFIX = 0x19, /** Determine the next animation frame for a house. */ - CBID_HOUSE_ANIMATION_NEXT_FRAME = 0x1A, + CBID_HOUSE_ANIMATION_NEXT_FRAME = 0x1A, // 15 bit callback /** Called for periodically starting or stopping the animation. */ - CBID_HOUSE_ANIMATION_START_STOP = 0x1B, + CBID_HOUSE_ANIMATION_START_STOP = 0x1B, // 15 bit callback /** Called whenever the construction state of a house changes. */ - CBID_HOUSE_CONSTRUCTION_STATE_CHANGE = 0x1C, + CBID_HOUSE_CONSTRUCTION_STATE_CHANGE = 0x1C, // 15 bit callback /** Determine whether a wagon can be attached to an already existing train. */ CBID_TRAIN_ALLOW_WAGON_ATTACH = 0x1D, /** Called to determine the colour of a town building. */ - CBID_HOUSE_COLOUR = 0x1E, + CBID_HOUSE_COLOUR = 0x1E, // 15 bit callback /** Called to decide how much cargo a town building can accept. */ - CBID_HOUSE_CARGO_ACCEPTANCE = 0x1F, + CBID_HOUSE_CARGO_ACCEPTANCE = 0x1F, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ - CBID_HOUSE_ANIMATION_SPEED = 0x20, + CBID_HOUSE_ANIMATION_SPEED = 0x20, // 8 bit callback /** Called periodically to determine if a house should be destroyed. */ - CBID_HOUSE_DESTRUCTION = 0x21, + CBID_HOUSE_DESTRUCTION = 0x21, // 8 bit callback /** Called to determine if the given industry type is available */ - CBID_INDUSTRY_AVAILABLE = 0x22, + CBID_INDUSTRY_AVAILABLE = 0x22, // 15 bit callback /** This callback is called from vehicle purchase lists. It returns a value to be * used as a custom string ID in the 0xD000 range. */ CBID_VEHICLE_ADDITIONAL_TEXT = 0x23, /** Called when building a station to customize the tile layout */ - CBID_STATION_TILE_LAYOUT = 0x24, + CBID_STATION_TILE_LAYOUT = 0x24, // 15 bit callback /** Called for periodically starting or stopping the animation. */ - CBID_INDTILE_ANIM_START_STOP = 0x25, + CBID_INDTILE_ANIM_START_STOP = 0x25, // 15 bit callback /** Called to determine industry tile next animation frame. */ - CBID_INDTILE_ANIM_NEXT_FRAME = 0x26, + CBID_INDTILE_ANIM_NEXT_FRAME = 0x26, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ - CBID_INDTILE_ANIMATION_SPEED = 0x27, + CBID_INDTILE_ANIMATION_SPEED = 0x27, // 8 bit callback /** Called to determine if the given industry can be built on specific area. */ - CBID_INDUSTRY_LOCATION = 0x28, + CBID_INDUSTRY_LOCATION = 0x28, // 15 bit callback /** Called on production changes, so it can be adjusted. */ - CBID_INDUSTRY_PRODUCTION_CHANGE = 0x29, + CBID_INDUSTRY_PRODUCTION_CHANGE = 0x29, // 15 bit callback /** Called to determine which cargoes a town building should accept. */ - CBID_HOUSE_ACCEPT_CARGO = 0x2A, + CBID_HOUSE_ACCEPT_CARGO = 0x2A, // 15 bit callback /** Called to query the cargo acceptance of the industry tile */ - CBID_INDTILE_CARGO_ACCEPTANCE = 0x2B, + CBID_INDTILE_CARGO_ACCEPTANCE = 0x2B, // 15 bit callback /** Called to determine which cargoes an industry should accept. */ - CBID_INDTILE_ACCEPT_CARGO = 0x2C, + CBID_INDTILE_ACCEPT_CARGO = 0x2C, // 15 bit callback /** Called to determine if a specific colour map should be used for a vehicle * instead of the default livery. */ - CBID_VEHICLE_COLOUR_MAPPING = 0x2D, + CBID_VEHICLE_COLOUR_MAPPING = 0x2D, // 15 bit callback /** Called to determine how much cargo a town building produces. */ - CBID_HOUSE_PRODUCE_CARGO = 0x2E, + CBID_HOUSE_PRODUCE_CARGO = 0x2E, // 15 bit callback /** Called to determine if the given industry tile can be built on specific tile. */ - CBID_INDTILE_SHAPE_CHECK = 0x2F, + CBID_INDTILE_SHAPE_CHECK = 0x2F, // 15 bit callback /** Called to determine the type (if any) of foundation to draw for industry tile. */ - CBID_INDUSTRY_DRAW_FOUNDATIONS = 0x30, + CBID_INDUSTRY_DRAW_FOUNDATIONS = 0x30, // 15 bit callback /** Called when the player (or AI) tries to start or stop a vehicle. Mainly * used for preventing a vehicle from leaving the depot. */ - CBID_VEHICLE_START_STOP_CHECK = 0x31, + CBID_VEHICLE_START_STOP_CHECK = 0x31, // 15 bit callback, but 0xFF test is done with 8 bit /** Called for every vehicle every 32 days (not all on same date though). */ - CBID_VEHICLE_32DAY_CALLBACK = 0x32, + CBID_VEHICLE_32DAY_CALLBACK = 0x32, // 2 bit callback /** Called to play a special sound effect */ - CBID_VEHICLE_SOUND_EFFECT = 0x33, + CBID_VEHICLE_SOUND_EFFECT = 0x33, // 15 bit callback /** Return the vehicles this given vehicle can be "upgraded" to. */ - CBID_VEHICLE_AUTOREPLACE_SELECTION = 0x34, + CBID_VEHICLE_AUTOREPLACE_SELECTION = 0x34, // 15 bit callback /** Called monthly on production changes, so it can be adjusted more frequently */ - CBID_INDUSTRY_MONTHLYPROD_CHANGE = 0x35, + CBID_INDUSTRY_MONTHLYPROD_CHANGE = 0x35, // 15 bit callback /** Called to modify various vehicle properties. Callback parameter 1 * specifies the property index, as used in Action 0, to change. */ - CBID_VEHICLE_MODIFY_PROPERTY = 0x36, + CBID_VEHICLE_MODIFY_PROPERTY = 0x36, // 8/15 bit depends on queried property /** Called to determine text to display after cargo name */ - CBID_INDUSTRY_CARGO_SUFFIX = 0x37, + CBID_INDUSTRY_CARGO_SUFFIX = 0x37, // 15 bit callback, but 0xFF test is done with 8 bit /** Called to determine more text in the fund industry window */ - CBID_INDUSTRY_FUND_MORE_TEXT = 0x38, + CBID_INDUSTRY_FUND_MORE_TEXT = 0x38, // 15 bit callback /** Called to calculate the income of delivered cargo */ - CBID_CARGO_PROFIT_CALC = 0x39, + CBID_CARGO_PROFIT_CALC = 0x39, // 15 bit callback /** Called to determine more text in the industry window */ - CBID_INDUSTRY_WINDOW_MORE_TEXT = 0x3A, + CBID_INDUSTRY_WINDOW_MORE_TEXT = 0x3A, // 15 bit callback /** Called to determine industry special effects */ - CBID_INDUSTRY_SPECIAL_EFFECT = 0x3B, + CBID_INDUSTRY_SPECIAL_EFFECT = 0x3B, // 15 bit callback /** Called to determine if industry can alter the ground below industry tile */ - CBID_INDUSTRY_AUTOSLOPE = 0x3C, + CBID_INDUSTRY_AUTOSLOPE = 0x3C, // 15 bit callback /** Called to determine if the industry can still accept or refuse more cargo arrival */ - CBID_INDUSTRY_REFUSE_CARGO = 0x3D, + CBID_INDUSTRY_REFUSE_CARGO = 0x3D, // 15 bit callback /* There are no callbacks 0x3E - 0x13F */ /** Called for periodically starting or stopping the animation. */ - CBID_STATION_ANIM_START_STOP = 0x140, // not implemented + CBID_STATION_ANIM_START_STOP = 0x140, // 15 bit callback /** Called to determine station tile next animation frame. */ - CBID_STATION_ANIM_NEXT_FRAME = 0x141, // not implemented + CBID_STATION_ANIM_NEXT_FRAME = 0x141, // 15 bit callback /** Called to indicate how long the current animation frame should last. */ - CBID_STATION_ANIMATION_SPEED = 0x142, // not implemented + CBID_STATION_ANIMATION_SPEED = 0x142, // 8 bit callback /** Called to determine whether a town building can be destroyed. */ - CBID_HOUSE_DENY_DESTRUCTION = 0x143, + CBID_HOUSE_DENY_DESTRUCTION = 0x143, // 15 bit callback /** Select an ambient sound to play for a given type of tile. */ - CBID_SOUNDS_AMBIENT_EFFECT = 0x144, // not implemented + CBID_SOUNDS_AMBIENT_EFFECT = 0x144, // 15 bit callback, not implemented /** Called to calculate part of a station rating. */ - CBID_CARGO_STATION_RATING_CALC = 0x145, + CBID_CARGO_STATION_RATING_CALC = 0x145, // 15 bit callback, not implemented /** Allow signal sprites to be replaced dynamically. */ - CBID_NEW_SIGNALS_SPRITE_DRAW = 0x146, // not implemented + CBID_NEW_SIGNALS_SPRITE_DRAW = 0x146, // 15 bit callback, not implemented /** Add an offset to the default sprite numbers to show another sprite. */ - CBID_CANALS_SPRITE_OFFSET = 0x147, // not implemented + CBID_CANALS_SPRITE_OFFSET = 0x147, // 15 bit callback, not implemented /** Called when a cargo type specified in property 20 is accepted. */ - CBID_HOUSE_WATCHED_CARGO_ACCEPTED = 0x148, // not implemented + CBID_HOUSE_WATCHED_CARGO_ACCEPTED = 0x148, // 15 bit callback, not implemented /** Callback done for each tile of a station to check the slope. */ - CBID_STATION_LAND_SLOPE_CHECK = 0x149, // not implemented + CBID_STATION_LAND_SLOPE_CHECK = 0x149, // 15 bit callback, not implemented /** Called to determine the color of an industry. */ - CBID_INDUSTRY_DECIDE_COLOUR = 0x14A, + CBID_INDUSTRY_DECIDE_COLOUR = 0x14A, // 4 bit callback /** Customize the input cargo types of a newly build industry. */ - CBID_INDUSTRY_INPUT_CARGO_TYPES = 0x14B, + CBID_INDUSTRY_INPUT_CARGO_TYPES = 0x14B, // 8 bit callback /** Customize the output cargo types of a newly build industry. */ - CBID_INDUSTRY_OUTPUT_CARGO_TYPES = 0x14C, - - /* ATTENTION: - * When adding new callbacks and their result is 15bit, add them to newgrf_spritegroup.cpp:Is8BitCallback(). - * It does not harm to add them there though they are not implemented. But it does harm if they get forgotton. - */ + CBID_INDUSTRY_OUTPUT_CARGO_TYPES = 0x14C, // 8 bit callback }; /** diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_generic.cpp --- a/src/newgrf_generic.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_generic.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -176,5 +176,7 @@ object.u.generic.count = count; object.u.generic.station_size = station_size; - return GetGenericCallbackResult(feature, &object, file); + uint16 callback = GetGenericCallbackResult(feature, &object, file); + if (callback != CALLBACK_FAILED) callback = GB(callback, 0, 8); + return callback; } diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_house.cpp --- a/src/newgrf_house.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_house.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -21,6 +21,8 @@ #include "transparency.h" #include "functions.h" #include "player_func.h" +#include "animated_tile_func.h" +#include "date_func.h" #include "table/strings.h" #include "table/sprites.h" @@ -428,7 +430,7 @@ /* If the lower 7 bits of the upper byte of the callback * result are not empty, it is a sound effect. */ - if (GB(callback_res, 8, 7) != 0) PlayHouseSound(GB(callback_res, 8, 7), tile); + if (GB(callback_res, 8, 7) != 0) PlayTileSound(hs->grffile, GB(callback_res, 8, 7), tile); } } @@ -448,7 +450,7 @@ MarkTileDirtyByTile(tile); } -void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result) +void ChangeHouseAnimationFrame(const GRFFile *file, TileIndex tile, uint16 callback_result) { switch (callback_result & 0xFF) { case 0xFD: /* Do nothing. */ break; @@ -461,7 +463,7 @@ } /* If the lower 7 bits of the upper byte of the callback * result are not empty, it is a sound effect. */ - if (GB(callback_result, 8, 7) != 0) PlayHouseSound(GB(callback_result, 8, 7), tile); + if (GB(callback_result, 8, 7) != 0) PlayTileSound(file, GB(callback_result, 8, 7), tile); } bool CanDeleteHouse(TileIndex tile) @@ -489,7 +491,7 @@ uint32 param = (hs->extra_flags & SYNCHRONISED_CALLBACK_1B) ? (GB(Random(), 0, 16) | random_bits << 16) : Random(); uint16 callback_res = GetHouseCallback(CBID_HOUSE_ANIMATION_START_STOP, param, 0, GetHouseType(tile), GetTownByTile(tile), tile); - if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res); + if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grffile, tile, callback_res); } } @@ -525,7 +527,7 @@ /* Check callback 21, which determines if a house should be destroyed. */ if (HasBit(hs->callback_mask, CBM_HOUSE_DESTRUCTION)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_DESTRUCTION, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); - if (callback_res != CALLBACK_FAILED && callback_res > 0) { + if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) > 0) { ClearTownHouse(GetTownByTile(tile), tile); return false; } diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_house.h --- a/src/newgrf_house.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_house.h Mon Apr 21 21:15:50 2008 +0000 @@ -36,7 +36,7 @@ void DrawNewHouseTile(TileInfo *ti, HouseID house_id); void AnimateNewHouseTile(TileIndex tile); -void ChangeHouseAnimationFrame(TileIndex tile, uint16 callback_result); +void ChangeHouseAnimationFrame(const struct GRFFile *file, TileIndex tile, uint16 callback_result); uint16 GetHouseCallback(CallbackID callback, uint32 param1, uint32 param2, HouseID house_id, Town *town, TileIndex tile); diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_industrytiles.cpp --- a/src/newgrf_industrytiles.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_industrytiles.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -15,6 +15,7 @@ #include "newgrf_callbacks.h" #include "newgrf_industries.h" #include "newgrf_industrytiles.h" +#include "newgrf_sound.h" #include "newgrf_text.h" #include "industry_map.h" #include "clear_map.h" @@ -23,6 +24,7 @@ #include "functions.h" #include "town.h" #include "command_func.h" +#include "animated_tile_func.h" #include "table/sprites.h" #include "table/strings.h" @@ -336,6 +338,10 @@ frame = callback_res & 0xFF; break; } + + /* If the lower 7 bits of the upper byte of the callback + * result are not empty, it is a sound effect. */ + if (GB(callback_res, 8, 7) != 0) PlayTileSound(itspec->grf_prop.grffile, GB(callback_res, 8, 7), tile); } } @@ -355,7 +361,7 @@ MarkTileDirtyByTile(tile); } -static void ChangeIndustryTileAnimationFrame(TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind) +static void ChangeIndustryTileAnimationFrame(const IndustryTileSpec *itspec, TileIndex tile, IndustryAnimationTrigger iat, uint32 random_bits, IndustryGfx gfx, Industry *ind) { uint16 callback_res = GetIndustryTileCallback(CBID_INDTILE_ANIM_START_STOP, random_bits, iat, gfx, ind, tile); if (callback_res == CALLBACK_FAILED) return; @@ -369,6 +375,10 @@ AddAnimatedTile(tile); break; } + + /* If the lower 7 bits of the upper byte of the callback + * result are not empty, it is a sound effect. */ + if (GB(callback_res, 8, 7) != 0) PlayTileSound(itspec->grf_prop.grffile, GB(callback_res, 8, 7), tile); } bool StartStopIndustryTileAnimation(TileIndex tile, IndustryAnimationTrigger iat, uint32 random) @@ -379,7 +389,7 @@ if (!HasBit(itspec->animation_triggers, iat)) return false; Industry *ind = GetIndustryByTile(tile); - ChangeIndustryTileAnimationFrame(tile, iat, random, gfx, ind); + ChangeIndustryTileAnimationFrame(itspec, tile, iat, random, gfx, ind); return true; } diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_sound.cpp --- a/src/newgrf_sound.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_sound.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -69,9 +69,11 @@ return true; } -bool PlayHouseSound(uint16 sound_id, TileIndex tile) +bool PlayTileSound(const GRFFile *file, uint16 sound_id, TileIndex tile) { - if (sound_id < GetNumOriginalSounds()) { + if (sound_id >= GetNumOriginalSounds()) sound_id += file->sound_offset - GetNumOriginalSounds(); + + if (sound_id < GetNumSounds()) { SndPlayTileFx((SoundFx)sound_id, tile); return true; } diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_sound.h --- a/src/newgrf_sound.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_sound.h Mon Apr 21 21:15:50 2008 +0000 @@ -26,6 +26,6 @@ FileEntry *GetSound(uint index); uint GetNumSounds(); bool PlayVehicleSound(const Vehicle *v, VehicleSoundEvent event); -bool PlayHouseSound(uint16 sound_id, TileIndex tile); +bool PlayTileSound(const struct GRFFile *file, uint16 sound_id, TileIndex tile); #endif /* NEWGRF_SOUND_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_spritegroup.cpp --- a/src/newgrf_spritegroup.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_spritegroup.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -80,37 +80,6 @@ TemporaryStorageArray _temp_store; -static inline bool Is8BitCallback(const ResolverObject *object) -{ - /* Var 0x7E procedure results are always 15 bit */ - if (object == NULL || object->procedure_call) return false; - - switch (object->callback) { - /* All these functions are 15 bit callbacks */ - case CBID_STATION_SPRITE_LAYOUT: - case CBID_VEHICLE_REFIT_CAPACITY: - case CBID_HOUSE_COLOUR: - case CBID_HOUSE_CARGO_ACCEPTANCE: - case CBID_INDUSTRY_LOCATION: - case CBID_HOUSE_ACCEPT_CARGO: - case CBID_INDTILE_CARGO_ACCEPTANCE: - case CBID_INDTILE_ACCEPT_CARGO: - case CBID_VEHICLE_COLOUR_MAPPING: - case CBID_HOUSE_PRODUCE_CARGO: - case CBID_INDTILE_SHAPE_CHECK: - case CBID_VEHICLE_SOUND_EFFECT: - case CBID_VEHICLE_MODIFY_PROPERTY: // depends on queried property - case CBID_CARGO_PROFIT_CALC: - case CBID_SOUNDS_AMBIENT_EFFECT: - case CBID_CARGO_STATION_RATING_CALC: - return false; - - /* The rest is a 8 bit callback, which should be truncated properly */ - default: - return true; - } -} - static inline uint32 GetVariable(const ResolverObject *object, byte variable, byte parameter, bool *available) { /* First handle variables common with Action7/9/D */ @@ -236,7 +205,7 @@ if (group->g.determ.num_ranges == 0) { /* nvar == 0 is a special case -- we turn our value into a callback result */ nvarzero.type = SGT_CALLBACK; - nvarzero.g.callback.result = GB(value, 0, Is8BitCallback(object) ? 8 : 15); + nvarzero.g.callback.result = value; return &nvarzero; } @@ -295,14 +264,6 @@ case SGT_REAL: return object->ResolveReal(object, group); case SGT_DETERMINISTIC: return ResolveVariable(group, object); case SGT_RANDOMIZED: return ResolveRandom(group, object); - case SGT_CALLBACK: { - if (!Is8BitCallback(object)) return group; - - static SpriteGroup result8bit; - result8bit.type = SGT_CALLBACK; - result8bit.g.callback.result = GB(group->g.callback.result, 0, 8); - return &result8bit; - } default: return group; } } diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_station.cpp --- a/src/newgrf_station.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_station.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -16,12 +16,15 @@ #include "newgrf_commons.h" #include "newgrf_station.h" #include "newgrf_spritegroup.h" +#include "newgrf_sound.h" #include "cargotype.h" #include "town_map.h" #include "newgrf_town.h" #include "gfx_func.h" #include "date_func.h" #include "player_func.h" +#include "animated_tile_func.h" +#include "functions.h" #include "table/sprites.h" #include "table/strings.h" @@ -740,8 +743,12 @@ free(st->speclist); st->num_specs = 0; st->speclist = NULL; + st->cached_anim_triggers = 0; + return; } } + + StationUpdateAnimTriggers(st); } /** Draw representation of a station tile for GUI purposes. @@ -853,3 +860,186 @@ HasBit(statspec->pylons, GetStationGfx(tile)) || !HasBit(statspec->wires, GetStationGfx(tile)); } + +void AnimateStationTile(TileIndex tile) +{ + const StationSpec *ss = GetStationSpec(tile); + if (ss == NULL) return; + + const Station *st = GetStationByTile(tile); + + uint8 animation_speed = ss->anim_speed; + + if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_SPEED)) { + uint16 callback = GetStationCallback(CBID_STATION_ANIMATION_SPEED, 0, 0, ss, st, tile); + if (callback != CALLBACK_FAILED) animation_speed = Clamp(callback & 0xFF, 0, 16); + } + + if (_tick_counter % (1 << animation_speed) != 0) return; + + uint8 frame = GetStationAnimationFrame(tile); + uint8 num_frames = ss->anim_frames; + + bool frame_set_by_callback = false; + + if (HasBit(ss->callbackmask, CBM_STATION_ANIMATION_NEXT_FRAME)) { + uint32 param = HasBit(ss->flags, 2) ? Random() : 0; + uint16 callback = GetStationCallback(CBID_STATION_ANIM_NEXT_FRAME, param, 0, ss, st, tile); + + if (callback != CALLBACK_FAILED) { + frame_set_by_callback = true; + + switch (callback & 0xFF) { + case 0xFF: + DeleteAnimatedTile(tile); + break; + + case 0xFE: + frame_set_by_callback = false; + break; + + default: + frame = callback & 0xFF; + break; + } + + /* If the lower 7 bits of the upper byte of the callback + * result are not empty, it is a sound effect. */ + if (GB(callback, 8, 7) != 0) PlayTileSound(ss->grffile, GB(callback, 8, 7), tile); + } + } + + if (!frame_set_by_callback) { + if (frame < num_frames) { + frame++; + } else if (frame == num_frames && HasBit(ss->anim_status, 0)) { + /* This animation loops, so start again from the beginning */ + frame = 0; + } else { + /* This animation doesn't loop, so stay here */ + DeleteAnimatedTile(tile); + } + } + + SetStationAnimationFrame(tile, frame); + MarkTileDirtyByTile(tile); +} + + +static void ChangeStationAnimationFrame(const StationSpec *ss, const Station *st, TileIndex tile, uint16 random_bits, StatAnimTrigger trigger, CargoID cargo_type) +{ + uint16 callback = GetStationCallback(CBID_STATION_ANIM_START_STOP, (random_bits << 16) | Random(), (uint8)trigger | (cargo_type << 8), ss, st, tile); + if (callback == CALLBACK_FAILED) return; + + switch (callback & 0xFF) { + case 0xFD: /* Do nothing. */ break; + case 0xFE: AddAnimatedTile(tile); break; + case 0xFF: DeleteAnimatedTile(tile); break; + default: + SetStationAnimationFrame(tile, callback); + AddAnimatedTile(tile); + break; + } + + /* If the lower 7 bits of the upper byte of the callback + * result are not empty, it is a sound effect. */ + if (GB(callback, 8, 7) != 0) PlayTileSound(ss->grffile, GB(callback, 8, 7), tile); +} + +enum TriggerArea { + TA_TILE, + TA_PLATFORM, + TA_WHOLE, +}; + +struct TileArea { + TileIndex tile; + uint8 w; + uint8 h; + + TileArea(const Station *st, TileIndex tile, TriggerArea ta) + { + switch (ta) { + default: NOT_REACHED(); + + case TA_TILE: + this->tile = tile; + this->w = 1; + this->h = 1; + break; + + case TA_PLATFORM: { + TileIndex start, end; + Axis axis = GetRailStationAxis(tile); + TileIndexDiff delta = TileOffsByDiagDir(AxisToDiagDir(axis)); + + for (end = tile; IsRailwayStationTile(end + delta) && IsCompatibleTrainStationTile(tile, end + delta); end += delta) { /* Nothing */ } + for (start = tile; IsRailwayStationTile(start - delta) && IsCompatibleTrainStationTile(tile, start - delta); start -= delta) { /* Nothing */ } + + this->tile = start; + this->w = TileX(end) - TileX(start) + 1; + this->h = TileY(end) - TileY(start) + 1; + break; + } + + case TA_WHOLE: + this->tile = st->train_tile; + this->w = st->trainst_w + 1; + this->h = st->trainst_h + 1; + break; + } + } +}; + +void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type) +{ + /* List of coverage areas for each animation trigger */ + static const TriggerArea tas[] = { + TA_TILE, TA_WHOLE, TA_WHOLE, TA_PLATFORM, TA_PLATFORM, TA_PLATFORM, TA_WHOLE + }; + + /* Get Station if it wasn't supplied */ + if (st == NULL) st = GetStationByTile(tile); + + /* Check the cached animation trigger bitmask to see if we need + * to bother with any further processing. */ + if (!HasBit(st->cached_anim_triggers, trigger)) return; + + uint16 random_bits = Random(); + TileArea area = TileArea(st, tile, tas[trigger]); + + for (uint y = 0; y < area.h; y++) { + for (uint x = 0; x < area.w; x++) { + if (st->TileBelongsToRailStation(area.tile)) { + const StationSpec *ss = GetStationSpec(area.tile); + if (ss != NULL && HasBit(ss->anim_triggers, trigger)) { + CargoID cargo; + if (cargo_type == CT_INVALID) { + cargo = CT_INVALID; + } else { + cargo = GetReverseCargoTranslation(cargo_type, ss->grffile); + } + ChangeStationAnimationFrame(ss, st, area.tile, random_bits, trigger, cargo); + } + } + area.tile += TileDiffXY(1, 0); + } + area.tile += TileDiffXY(-area.w, 1); + } +} + +/** + * Update the cached animation trigger bitmask for a station. + * @param st Station to update. + */ +void StationUpdateAnimTriggers(Station *st) +{ + st->cached_anim_triggers = 0; + + /* Combine animation trigger bitmask for all station specs + * of this station. */ + for (uint i = 0; i < st->num_specs; i++) { + const StationSpec *ss = st->speclist[i].spec; + if (ss != NULL) st->cached_anim_triggers |= ss->anim_triggers; + } +} diff -r 7856e972f8aa -r 7798ae816af8 src/newgrf_station.h --- a/src/newgrf_station.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/newgrf_station.h Mon Apr 21 21:15:50 2008 +0000 @@ -83,6 +83,11 @@ StationLayout **layouts; bool copied_layouts; + uint8 anim_frames; + uint8 anim_status; + uint8 anim_speed; + uint16 anim_triggers; + /** * NUM_CARGO real cargo plus three pseudo cargo sprite groups. * Used for obtaining the sprite offset of custom sprites, and for @@ -132,4 +137,18 @@ /* Draw representation of a station tile for GUI purposes. */ bool DrawStationTile(int x, int y, RailType railtype, Axis axis, StationClassID sclass, uint station); +enum StatAnimTrigger { + STAT_ANIM_BUILT, + STAT_ANIM_NEW_CARGO, + STAT_ANIM_CARGO_TAKEN, + STAT_ANIM_TRAIN_ARRIVES, + STAT_ANIM_TRAIN_DEPARTS, + STAT_ANIM_TRAIN_LOADS, + STAT_ANIM_250_TICKS, +}; + +void AnimateStationTile(TileIndex tile); +void StationAnimationTrigger(const Station *st, TileIndex tile, StatAnimTrigger trigger, CargoID cargo_type = CT_INVALID); +void StationUpdateAnimTriggers(Station *st); + #endif /* NEWGRF_STATION_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/news_func.h --- a/src/news_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/news_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -14,10 +14,9 @@ void InitNewsItemStructs(); extern NewsItem _statusbar_news_item; -extern uint32 _news_display_opt; extern bool _news_ticker_sound; -extern const char *_news_display_name[NT_END]; +extern NewsTypeData _news_type_data[NT_END]; /** * Delete a news item type about a vehicle diff -r 7856e972f8aa -r 7798ae816af8 src/news_gui.cpp --- a/src/news_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/news_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -53,7 +53,6 @@ #define INVALID_NEWS 255 NewsItem _statusbar_news_item; -uint32 _news_display_opt; bool _news_ticker_sound; static NewsItem _news_items[MAX_NEWS]; ///< The news FIFO queue static NewsID _current_news = INVALID_NEWS; ///< points to news item that should be shown next @@ -335,25 +334,24 @@ /** - * Maximum age of news items. - * Don't show item if it's older than x days, corresponds with NewsType in news_type.h - * @see NewsType + * Per-NewsType data */ -static const byte _news_items_age[NT_END] = { - 60, ///< NT_ARRIVAL_PLAYER - 60, ///< NT_ARRIVAL_OTHER - 90, ///< NT_ACCIDENT - 60, ///< NT_COMPANY_INFO - 90, ///< NT_OPENCLOSE - 30, ///< NT_ECONOMY - 30, ///< NT_INDUSTRY_PLAYER - 30, ///< NT_INDUSTRY_OTHER - 30, ///< NT_INDUSTRY_NOBODY - 150, ///< NT_ADVICE - 30, ///< NT_NEW_VEHICLES - 90, ///< NT_ACCEPTANCE - 180, ///< NT_SUBSIDIES - 60 ///< NT_GENERAL +NewsTypeData _news_type_data[NT_END] = { + /* name, age, sound, display */ + { "arrival_player", 60, SND_1D_APPLAUSE, ND_FULL }, ///< NT_ARRIVAL_PLAYER + { "arrival_other", 60, SND_1D_APPLAUSE, ND_FULL }, ///< NT_ARRIVAL_OTHER + { "accident", 90, SND_BEGIN, ND_FULL }, ///< NT_ACCIDENT + { "company_info", 60, SND_BEGIN, ND_FULL }, ///< NT_COMPANY_INFO + { "openclose", 90, SND_BEGIN, ND_FULL }, ///< NT_OPENCLOSE + { "economy", 30, SND_BEGIN, ND_FULL }, ///< NT_ECONOMY + { "production_player", 30, SND_BEGIN, ND_FULL }, ///< NT_INDUSTRY_PLAYER + { "production_other", 30, SND_BEGIN, ND_FULL }, ///< NT_INDUSTRY_OTHER + { "production_nobody", 30, SND_BEGIN, ND_FULL }, ///< NT_INDUSTRY_NOBODY + { "advice", 150, SND_BEGIN, ND_FULL }, ///< NT_ADVICE + { "new_vehicles", 30, SND_1E_OOOOH, ND_FULL }, ///< NT_NEW_VEHICLES + { "acceptance", 90, SND_BEGIN, ND_FULL }, ///< NT_ACCEPTANCE + { "subsidies", 180, SND_BEGIN, ND_FULL }, ///< NT_SUBSIDIES + { "general", 60, SND_BEGIN, ND_FULL }, ///< NT_GENERAL }; @@ -401,63 +399,6 @@ NewsWindowProc }; -static const SoundFx _news_sounds[NT_END] = { - SND_1D_APPLAUSE, ///< NT_ARRIVAL_PLAYER - SND_1D_APPLAUSE, ///< NT_ARRIVAL_OTHER - SND_BEGIN, ///< NT_ACCIDENT - SND_BEGIN, ///< NT_COMPANY_INFO - SND_BEGIN, ///< NT_OPENCLOSE - SND_BEGIN, ///< NT_ECONOMY - SND_BEGIN, ///< NT_INDUSTRY_PLAYER - SND_BEGIN, ///< NT_INDUSTRY_OTHER - SND_BEGIN, ///< NT_INDUSTRY_NOBODY - SND_BEGIN, ///< NT_ADVICE - SND_1E_OOOOH, ///< NT_NEW_VEHICLES - SND_BEGIN, ///< NT_ACCEPTANCE - SND_BEGIN, ///< NT_SUBSIDIES - SND_BEGIN, ///< NT_GENERAL -}; - -const char *_news_display_name[NT_END] = { - "arrival_player", - "arrival_other", - "accident", - "company_info", - "openclose", - "economy", - "production_player", - "production_other", - "production_nobody", - "advice", - "new_vehicles", - "acceptance", - "subsidies", - "general", -}; - -/** - * Get the value of an item of the news-display settings. This is - * a little tricky since on/off/summary must use 2 bits to store the value - * @param item the item whose value is requested - * @return return the found value which is between 0-2 - */ -static inline byte GetNewsDisplayValue(byte item) -{ - assert(item < NT_END && GB(_news_display_opt, item * 2, 2) <= 2); - return GB(_news_display_opt, item * 2, 2); -} - -/** - * Set the value of an item in the news-display settings. This is - * a little tricky since on/off/summary must use 2 bits to store the value - * @param item the item whose value is being set - * @param val new value - */ -static inline void SetNewsDisplayValue(byte item, byte val) -{ - assert(item < NT_END && val <= 2); - SB(_news_display_opt, item * 2, 2, val); -} /** Open up an own newspaper window for the news item */ static void ShowNewspaper(NewsItem *ni) @@ -465,7 +406,7 @@ ni->flags &= ~NF_FORCE_BIG; ni->duration = 555; - SoundFx sound = _news_sounds[ni->type]; + SoundFx sound = _news_type_data[ni->type].sound; if (sound != 0) SndPlayFx(sound); int top = _screen.height; @@ -476,7 +417,7 @@ _news_type13_desc.top = top; w = AllocateWindowDesc(&_news_type13_desc); if (ni->flags & NF_VIEWPORT) { - AssignWindowViewport(w, 2, 58, 0x1AA, 0x6E, + InitializeWindowViewport(w, 2, 58, 426, 110, ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); } break; @@ -485,7 +426,7 @@ _news_type2_desc.top = top; w = AllocateWindowDesc(&_news_type2_desc); if (ni->flags & NF_VIEWPORT) { - AssignWindowViewport(w, 2, 58, 0x1AA, 0x46, + InitializeWindowViewport(w, 2, 58, 426, 70, ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); } break; @@ -494,7 +435,7 @@ _news_type0_desc.top = top; w = AllocateWindowDesc(&_news_type0_desc); if (ni->flags & NF_VIEWPORT) { - AssignWindowViewport(w, 3, 17, 0x112, 0x2F, + InitializeWindowViewport(w, 3, 17, 274, 47, ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS); } break; @@ -553,11 +494,11 @@ NewsItem *ni = &_news_items[_current_news]; /* check the date, don't show too old items */ - if (_date - _news_items_age[ni->type] > ni->date) return; + if (_date - _news_type_data[ni->type].age > ni->date) return; - switch (GetNewsDisplayValue(ni->type)) { + switch (_news_type_data[ni->type].display) { default: NOT_REACHED(); - case 0: { // Off - show nothing only a small reminder in the status bar + case ND_OFF: { // Off - show nothing only a small reminder in the status bar Window *w = FindWindowById(WC_STATUS_BAR, 0); if (w != NULL) { @@ -567,14 +508,14 @@ break; } - case 1: // Summary - show ticker, but if forced big, cascade to full + case ND_SUMMARY: // Summary - show ticker, but if forced big, cascade to full if (!(ni->flags & NF_FORCE_BIG)) { ShowTicker(ni); break; } /* Fallthrough */ - case 2: // Full - show newspaper + case ND_FULL: // Full - show newspaper ShowNewspaper(ni); break; } @@ -803,33 +744,30 @@ /* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */ switch (e->event) { case WE_CREATE: { - uint32 val = _news_display_opt; - uint32 all_val; + NewsDisplay all_val; /* Set up the initial disabled buttons in the case of 'off' or 'full' */ - all_val = val & 0x3; - for (int i = 0; i < NT_END; i++, val >>= 2) { - SetMessageButtonStates(w, val & 0x3, i); + all_val = _news_type_data[0].display; + for (int i = 0; i < NT_END; i++) { + SetMessageButtonStates(w, _news_type_data[i].display, i); /* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */ - if ((val & 0x3) != all_val) all_val = 0; + if (_news_type_data[i].display != all_val) all_val = ND_OFF; } /* If all values are the same value, the ALL-button will take over this value */ WP(w, def_d).data_1 = all_val; } break; case WE_PAINT: { - uint32 val = _news_display_opt; - if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER); w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1]; DrawWindowWidgets(w); /* Draw the string of each setting on each button. */ - for (int i = 0, y = 26; i < NT_END; i++, y += 12, val >>= 2) { + for (int i = 0, y = 26; i < NT_END; i++, y += 12) { /* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division, * which will give centered position */ - DrawStringCentered(51, y + 1, message_opt[val & 0x3], TC_BLACK); + DrawStringCentered(51, y + 1, message_opt[_news_type_data[i].display], TC_BLACK); } } break; @@ -849,10 +787,10 @@ int wid = e->we.click.widget - WIDGET_NEWSOPT_START_OPTION; if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) { int element = wid / NB_WIDG_PER_SETTING; - byte val = (GetNewsDisplayValue(element) + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3; + byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3; SetMessageButtonStates(w, val, element); - SetNewsDisplayValue(element, val); + _news_type_data[element].display = (NewsDisplay)val; SetWindowDirty(w); } } break; @@ -864,7 +802,7 @@ for (int i = 0; i < NT_END; i++) { SetMessageButtonStates(w, e->we.dropdown.index, i); - SetNewsDisplayValue(i, e->we.dropdown.index); + _news_type_data[i].display = (NewsDisplay)e->we.dropdown.index; } SetWindowDirty(w); break; diff -r 7856e972f8aa -r 7798ae816af8 src/news_type.h --- a/src/news_type.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/news_type.h Mon Apr 21 21:15:50 2008 +0000 @@ -8,6 +8,7 @@ #include "window_type.h" #include "date_type.h" #include "strings_type.h" +#include "sound_type.h" /** * Type of news. @@ -75,6 +76,25 @@ NB_BNEWCOMPANY = (4 << 4), ///< A new company has been started }; +/** + * News display options + */ +enum NewsDisplay { + ND_OFF, ///< Only show a reminder in the status bar + ND_SUMMARY, ///< Show ticker + ND_FULL, ///< Show newspaper +}; + +/** + * Per-NewsType data + */ +struct NewsTypeData { + const char *const name; ///< Name + const byte age; ///< Maximum age of news items (in days) + const SoundFx sound; ///< Sound + NewsDisplay display; ///< Display mode (off, summary, full) +}; + struct NewsItem { StringID string_id; ///< Message text (sometimes also used for storing other info) uint16 duration; ///< Remaining time for showing this news message diff -r 7856e972f8aa -r 7798ae816af8 src/oldloader.cpp --- a/src/oldloader.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/oldloader.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -23,7 +23,8 @@ #include "date_func.h" #include "vehicle_func.h" #include "variables.h" -#include "settings_type.h" +#include "strings_func.h" +#include "effectvehicle_base.h" #include "table/strings.h" @@ -84,6 +85,12 @@ OC_TILE = OC_VAR_U32 | OC_FILE_U16, + /** + * Dereference the pointer once before writing to it, + * so we do not have to use big static arrays. + */ + OC_DEREFERENCE_POINTER = 1 << 31, + OC_END = 0 ///< End of the whole chunk, all 32bits set to zero }; @@ -201,10 +208,10 @@ byte *base_ptr = (byte*)base; while (chunk->type != OC_END) { - byte* ptr = (byte*)chunk->ptr; - uint i; + byte *ptr = (byte*)chunk->ptr; + if ((chunk->type & OC_DEREFERENCE_POINTER) != 0) ptr = *(byte**)ptr; - for (i = 0; i < chunk->amount; i++) { + for (uint i = 0; i < chunk->amount; i++) { if (ls->failed) return false; /* Handle simple types */ @@ -391,10 +398,10 @@ extern TileIndex *_animated_tile_list; extern uint _animated_tile_count; -extern char _name_array[512][32]; +extern char *_old_name_array; static byte _old_vehicle_multiplier; -static uint8 _old_map3[OLD_MAP_SIZE * 2]; +static uint8 *_old_map3; static bool _new_ttdpatch_format; static uint32 _old_town_index; static uint16 _old_string_id; @@ -819,7 +826,7 @@ OCL_SVAR( OC_FILE_U32 | OC_VAR_I64, Player, bankrupt_value ), OCL_SVAR( OC_UINT16, Player, bankrupt_timeout ), - OCL_SVAR( OC_FILE_U32 | OC_VAR_U16, Player, cargo_types ), + OCL_SVAR( OC_UINT32, Player, cargo_types ), OCL_CHUNK( 3, OldPlayerYearly ), OCL_CHUNK( 1, OldPlayerEconomy ), @@ -932,9 +939,9 @@ OCL_END() }; -static const OldChunks vehicle_special_chunk[] = { - OCL_SVAR( OC_UINT16, VehicleSpecial, animation_state ), - OCL_SVAR( OC_UINT8, VehicleSpecial, animation_substate ), +static const OldChunks vehicle_effect_chunk[] = { + OCL_SVAR( OC_UINT16, VehicleEffect, animation_state ), + OCL_SVAR( OC_UINT8, VehicleEffect, animation_substate ), OCL_NULL( 7 ), // Junk @@ -969,7 +976,7 @@ case VEH_ROAD : res = LoadChunk(ls, &v->u.road, vehicle_road_chunk); break; case VEH_SHIP : res = LoadChunk(ls, &v->u.ship, vehicle_ship_chunk); break; case VEH_AIRCRAFT: res = LoadChunk(ls, &v->u.air, vehicle_air_chunk); break; - case VEH_SPECIAL : res = LoadChunk(ls, &v->u.special, vehicle_special_chunk); break; + case VEH_EFFECT : res = LoadChunk(ls, &v->u.effect, vehicle_effect_chunk); break; case VEH_DISASTER: res = LoadChunk(ls, &v->u.disaster, vehicle_disaster_chunk); break; } @@ -1082,7 +1089,7 @@ case 0x11 /*VEH_ROAD */: v = new (_current_vehicle_id) RoadVehicle(); break; case 0x12 /*VEH_SHIP */: v = new (_current_vehicle_id) Ship(); break; case 0x13 /*VEH_AIRCRAFT*/: v = new (_current_vehicle_id) Aircraft(); break; - case 0x14 /*VEH_SPECIAL */: v = new (_current_vehicle_id) SpecialVehicle(); break; + case 0x14 /*VEH_EFFECT */: v = new (_current_vehicle_id) EffectVehicle(); break; case 0x15 /*VEH_DISASTER*/: v = new (_current_vehicle_id) DisasterVehicle(); break; } if (!LoadChunk(ls, v, vehicle_chunk)) return false; @@ -1116,7 +1123,7 @@ v->name = CopyFromOldName(_old_string_id); /* Vehicle-subtype is different in TTD(Patch) */ - if (v->type == VEH_SPECIAL) v->subtype = v->subtype >> 1; + if (v->type == VEH_EFFECT) v->subtype = v->subtype >> 1; if (_cargo_count != 0) { CargoPacket *cp = new CargoPacket((_cargo_source == 0xFF) ? INVALID_STATION : _cargo_source, _cargo_count); @@ -1374,7 +1381,7 @@ OCL_ASSERT( 0x6F0F2 ), - OCL_VAR ( OC_UINT8, 32 * 500, &_name_array[0] ), + OCL_VAR ( OC_UINT8 | OC_DEREFERENCE_POINTER, 32 * 500, &_old_name_array ), OCL_NULL( 0x2000 ), ///< Old hash-table, no longer in use @@ -1454,8 +1461,10 @@ DEBUG(oldloader, 3, "Reading main chunk..."); /* Load the biggest chunk */ + _old_map3 = MallocT(OLD_MAP_SIZE * 2); if (!LoadChunk(ls, NULL, main_chunk)) { DEBUG(oldloader, 0, "Loading failed"); + free(_old_map3); return false; } DEBUG(oldloader, 3, "Done, converting game data..."); @@ -1522,6 +1531,8 @@ DEBUG(oldloader, 3, "Finished converting game data"); DEBUG(oldloader, 1, "TTD(Patch) savegame successfully converted"); + free(_old_map3); + return true; } diff -r 7856e972f8aa -r 7798ae816af8 src/openttd.cpp --- a/src/openttd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/openttd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -59,6 +59,8 @@ #include "date_func.h" #include "vehicle_func.h" #include "cheat_func.h" +#include "animated_tile_func.h" +#include "functions.h" #include "newgrf.h" #include "newgrf_config.h" @@ -93,6 +95,8 @@ void DoPaletteAnimations(); void MusicLoop(); void ResetMusic(); +void ResetOldNames(); +void ProcessAsyncSaveFinish(); extern void SetDifficultyLevel(int mode, GameOptions *gm_opt); extern Player* DoStartupNewPlayer(bool is_ai); @@ -654,39 +658,6 @@ } } - -/** Mutex so that only one thread can communicate with the main program - * at any given time */ -static ThreadMsg _message = MSG_OTTD_NO_MESSAGE; - -static inline void OTTD_ReleaseMutex() {_message = MSG_OTTD_NO_MESSAGE;} -static inline ThreadMsg OTTD_PollThreadEvent() {return _message;} - -/** Called by running thread to execute some action in the main game. - * It will stall as long as the mutex is not freed (handled) by the game */ -void OTTD_SendThreadMessage(ThreadMsg msg) -{ - if (_exit_game) return; - while (_message != MSG_OTTD_NO_MESSAGE) CSleep(10); - - _message = msg; -} - - -/** Handle the user-messages sent to us - * @param message message sent - */ -static void ProcessSentMessage(ThreadMsg message) -{ - switch (message) { - case MSG_OTTD_SAVETHREAD_DONE: SaveFileDone(); break; - case MSG_OTTD_SAVETHREAD_ERROR: SaveFileError(); break; - default: NOT_REACHED(); - } - - OTTD_ReleaseMutex(); // release mutex so that other threads, messages can be handled -} - static void ShowScreenshotResult(bool b) { if (b) { @@ -1104,9 +1075,7 @@ void GameLoop() { - ThreadMsg message; - - if ((message = OTTD_PollThreadEvent()) != 0) ProcessSentMessage(message); + ProcessAsyncSaveFinish(); /* autosave game? */ if (_do_autosave) { @@ -1400,6 +1369,9 @@ } } + /* From this point the old names array is cleared. */ + ResetOldNames(); + /* convert road side to my format. */ if (_opt.road_side) _opt.road_side = 1; diff -r 7856e972f8aa -r 7798ae816af8 src/openttd.h --- a/src/openttd.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/openttd.h Mon Apr 21 21:15:50 2008 +0000 @@ -1,4 +1,5 @@ /* $Id$ */ + /** @file openttd.h */ #ifndef OPENTTD_H @@ -108,17 +109,6 @@ }; extern byte _no_scroll; -/** To have a concurrently running thread interface with the main program, use - * the OTTD_SendThreadMessage() function. Actions to perform upon the message are handled - * in the ProcessSentMessage() function */ -enum ThreadMsg { - MSG_OTTD_NO_MESSAGE, - MSG_OTTD_SAVETHREAD_DONE, - MSG_OTTD_SAVETHREAD_ERROR, -}; - -void OTTD_SendThreadMessage(ThreadMsg msg); - extern byte _game_mode; extern bool _exit_game; extern int8 _pause_game; diff -r 7856e972f8aa -r 7798ae816af8 src/player_base.h --- a/src/player_base.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/player_base.h Mon Apr 21 21:15:50 2008 +0000 @@ -44,7 +44,7 @@ byte block_preview; PlayerByte index; - uint16 cargo_types; ///< which cargo types were transported the last year + uint32 cargo_types; ///< which cargo types were transported the last year TileIndex location_of_house; TileIndex last_build_coordinate; diff -r 7856e972f8aa -r 7798ae816af8 src/players.cpp --- a/src/players.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/players.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -648,14 +648,12 @@ */ CommandCost CmdSetAutoReplace(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { - Player *p; if (!IsValidPlayer(_current_player)) return CMD_ERROR; - p = GetPlayer(_current_player); + Player *p = GetPlayer(_current_player); switch (GB(p1, 0, 3)) { case 0: - if (p->engine_renew == HasBit(p2, 0)) - return CMD_ERROR; + if (p->engine_renew == HasBit(p2, 0)) return CMD_ERROR; if (flags & DC_EXEC) { p->engine_renew = HasBit(p2, 0); @@ -665,9 +663,10 @@ } } break; + case 1: - if (p->engine_renew_months == (int16)p2) - return CMD_ERROR; + if (Clamp((int16)p2, -12, 12) != (int16)p2) return CMD_ERROR; + if (p->engine_renew_months == (int16)p2) return CMD_ERROR; if (flags & DC_EXEC) { p->engine_renew_months = (int16)p2; @@ -677,18 +676,20 @@ } } break; + case 2: - if (p->engine_renew_money == (uint32)p2) - return CMD_ERROR; + if (ClampU(p2, 0, 2000000) != p2) return CMD_ERROR; + if (p->engine_renew_money == p2) return CMD_ERROR; if (flags & DC_EXEC) { - p->engine_renew_money = (uint32)p2; + p->engine_renew_money = p2; if (IsLocalPlayer()) { _patches.autorenew_money = p->engine_renew_money; InvalidateWindow(WC_GAME_OPTIONS, 0); } } break; + case 3: { EngineID old_engine_type = GB(p2, 0, 16); EngineID new_engine_type = GB(p2, 16, 16); @@ -699,21 +700,19 @@ if (new_engine_type != INVALID_ENGINE) { /* First we make sure that it's a valid type the user requested * check that it's an engine that is in the engine array */ - if (!IsEngineIndex(new_engine_type)) - return CMD_ERROR; + if (!IsEngineIndex(new_engine_type)) return CMD_ERROR; /* check that the new vehicle type is the same as the original one */ - if (GetEngine(old_engine_type)->type != GetEngine(new_engine_type)->type) - return CMD_ERROR; + if (GetEngine(old_engine_type)->type != GetEngine(new_engine_type)->type) return CMD_ERROR; /* make sure that we do not replace a plane with a helicopter or vise versa */ if (GetEngine(new_engine_type)->type == VEH_AIRCRAFT && - (AircraftVehInfo(old_engine_type)->subtype & AIR_CTOL) != (AircraftVehInfo(new_engine_type)->subtype & AIR_CTOL)) + (AircraftVehInfo(old_engine_type)->subtype & AIR_CTOL) != (AircraftVehInfo(new_engine_type)->subtype & AIR_CTOL)) { return CMD_ERROR; + } /* make sure that the player can actually buy the new engine */ - if (!HasBit(GetEngine(new_engine_type)->player_avail, _current_player)) - return CMD_ERROR; + if (!HasBit(GetEngine(new_engine_type)->player_avail, _current_player)) return CMD_ERROR; cost = AddEngineReplacementForPlayer(p, old_engine_type, new_engine_type, id_g, flags); } else { @@ -726,10 +725,13 @@ } case 4: + if (Clamp((int16)GB(p1, 16, 16), -12, 12) != (int16)GB(p1, 16, 16)) return CMD_ERROR; + if (ClampU(p2, 0, 2000000) != p2) return CMD_ERROR; + if (flags & DC_EXEC) { p->engine_renew = HasBit(p1, 15); p->engine_renew_months = (int16)GB(p1, 16, 16); - p->engine_renew_money = (uint32)p2; + p->engine_renew_money = p2; if (IsLocalPlayer()) { _patches.autorenew = p->engine_renew; @@ -739,9 +741,9 @@ } } break; + case 5: - if (p->renew_keep_length == HasBit(p2, 0)) - return CMD_ERROR; + if (p->renew_keep_length == HasBit(p2, 0)) return CMD_ERROR; if (flags & DC_EXEC) { p->renew_keep_length = HasBit(p2, 0); @@ -750,8 +752,8 @@ } } break; + } - } return CommandCost(); } @@ -1102,7 +1104,8 @@ SLE_CONDVAR(Player, avail_railtypes, SLE_UINT8, 0, 57), SLE_VAR(Player, block_preview, SLE_UINT8), - SLE_VAR(Player, cargo_types, SLE_UINT16), + SLE_CONDVAR(Player, cargo_types, SLE_FILE_U16 | SLE_VAR_U32, 0, 93), + SLE_CONDVAR(Player, cargo_types, SLE_UINT32, 94, SL_MAX_VERSION), SLE_CONDVAR(Player, location_of_house, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), SLE_CONDVAR(Player, location_of_house, SLE_UINT32, 6, SL_MAX_VERSION), SLE_CONDVAR(Player, last_build_coordinate, SLE_FILE_U16 | SLE_VAR_U32, 0, 5), diff -r 7856e972f8aa -r 7798ae816af8 src/rail_cmd.cpp --- a/src/rail_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/rail_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -43,6 +43,7 @@ #include "tunnelbridge.h" #include "station_map.h" #include "water_map.h" +#include "functions.h" #include "table/sprites.h" #include "table/strings.h" diff -r 7856e972f8aa -r 7798ae816af8 src/rail_gui.cpp --- a/src/rail_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/rail_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -952,7 +952,7 @@ const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i); if (statspec != NULL && statspec->name != 0) { - if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) { + if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) { GfxFillRect(8, y - 2, 127, y + 10, (1 << PALETTE_MODIFIER_GREYOUT)); } @@ -1097,7 +1097,7 @@ statspec = GetCustomStationSpec(_railstation.station_class, y); if (statspec != NULL && HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && - GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return; + GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return; _railstation.station_type = y; @@ -1510,7 +1510,7 @@ if (statspec != NULL && HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && - GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) { + GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) { GfxFillRect(4 + i * 68, 18, 67 + i * 68, 75, (1 << PALETTE_MODIFIER_GREYOUT)); } } @@ -1530,7 +1530,7 @@ const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type); if (statspec != NULL && HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && - GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) return; + GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return; _cur_waypoint_type = type; SndPlayFx(SND_15_BEEP); diff -r 7856e972f8aa -r 7798ae816af8 src/road_cmd.cpp --- a/src/road_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/road_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -36,6 +36,8 @@ #include "road_func.h" #include "tunnelbridge.h" #include "cheat_func.h" +#include "functions.h" +#include "effectvehicle_func.h" #include "table/sprites.h" #include "table/strings.h" diff -r 7856e972f8aa -r 7798ae816af8 src/roadveh.h --- a/src/roadveh.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/roadveh.h Mon Apr 21 21:15:50 2008 +0000 @@ -73,7 +73,7 @@ ExpensesType GetExpenseType(bool income) const { return income ? EXPENSES_ROADVEH_INC : EXPENSES_ROADVEH_RUN; } WindowClass GetVehicleListWindowClass() const { return WC_ROADVEH_LIST; } bool IsPrimaryVehicle() const { return IsRoadVehFront(this); } - int GetImage(Direction direction) const; + SpriteID GetImage(Direction direction) const; int GetDisplaySpeed() const { return this->cur_speed * 10 / 32; } int GetDisplayMaxSpeed() const { return this->max_speed * 10 / 32; } Money GetRunningCost() const { return RoadVehInfo(this->engine_type)->running_cost * GetPriceByIndex(RoadVehInfo(this->engine_type)->running_cost_class); } diff -r 7856e972f8aa -r 7798ae816af8 src/roadveh_cmd.cpp --- a/src/roadveh_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/roadveh_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -43,6 +43,7 @@ #include "order_func.h" #include "depot_base.h" #include "depot_func.h" +#include "effectvehicle_func.h" #include "table/strings.h" @@ -94,36 +95,42 @@ TRACKDIR_X_NE, TRACKDIR_Y_SE, TRACKDIR_X_SW, TRACKDIR_Y_NW }; -int RoadVehicle::GetImage(Direction direction) const +static SpriteID GetRoadVehIcon(EngineID engine) { - int img = this->spritenum; - int image; + uint8 spritenum = RoadVehInfo(engine)->image_index; - if (is_custom_sprite(img)) { - image = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img))); - if (image != 0) return image; - img = _orig_road_vehicle_info[this->engine_type - ROAD_ENGINES_INDEX].image_index; + if (is_custom_sprite(spritenum)) { + SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W); + if (sprite != 0) return sprite; + + spritenum = _orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index; } - image = direction + _roadveh_images[img]; - if (this->cargo.Count() >= this->cargo_cap / 2U) image += _roadveh_full_adder[img]; - return image; + return 6 + _roadveh_images[spritenum]; +} + +SpriteID RoadVehicle::GetImage(Direction direction) const +{ + uint8 spritenum = this->spritenum; + SpriteID sprite; + + if (is_custom_sprite(spritenum)) { + sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum))); + if (sprite != 0) return sprite; + + spritenum = _orig_road_vehicle_info[this->engine_type - ROAD_ENGINES_INDEX].image_index; + } + + sprite = direction + _roadveh_images[spritenum]; + + if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _roadveh_full_adder[spritenum]; + + return sprite; } void DrawRoadVehEngine(int x, int y, EngineID engine, SpriteID pal) { - int spritenum = RoadVehInfo(engine)->image_index; - - if (is_custom_sprite(spritenum)) { - int sprite = GetCustomVehicleIcon(engine, DIR_W); - - if (sprite != 0) { - DrawSprite(sprite, pal, x, y); - return; - } - spritenum = _orig_road_vehicle_info[engine - ROAD_ENGINES_INDEX].image_index; - } - DrawSprite(6 + _roadveh_images[spritenum], pal, x, y); + DrawSprite(GetRoadVehIcon(engine), pal, x, y); } static CommandCost EstimateRoadVehCost(EngineID engine_type) @@ -293,19 +300,16 @@ */ CommandCost CmdStartStopRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { - Vehicle *v; - uint16 callback; - if (!IsValidVehicleID(p1)) return CMD_ERROR; - v = GetVehicle(p1); + Vehicle *v = GetVehicle(p1); if (v->type != VEH_ROAD || !CheckOwnership(v->owner)) return CMD_ERROR; /* Check if this road veh can be started/stopped. The callback will fail or * return 0xFF if it can. */ - callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); - if (callback != CALLBACK_FAILED && callback != 0xFF) { + uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); + if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) { StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback); return_cmd_error(error); } @@ -707,7 +711,7 @@ if (!(v->vehstatus & VS_HIDDEN)) { Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE); - if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2; + if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2; } } @@ -1847,7 +1851,7 @@ HandleBrokenRoadVeh(v); return; } - v->breakdown_ctr--; + if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } if (v->vehstatus & VS_STOPPED) return; diff -r 7856e972f8aa -r 7798ae816af8 src/saveload.cpp --- a/src/saveload.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/saveload.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -34,7 +34,7 @@ #include "table/strings.h" -extern const uint16 SAVEGAME_VERSION = 93; +extern const uint16 SAVEGAME_VERSION = 94; uint16 _sl_version; ///< the major savegame version identifier byte _sl_minor_version; ///< the minor savegame version, DO NOT USE! @@ -87,6 +87,32 @@ throw std::exception(); } +typedef void (*AsyncSaveFinishProc)(); +static AsyncSaveFinishProc _async_save_finish = NULL; + +/** + * Called by save thread to tell we finished saving. + */ +static void SetAsyncSaveFinish(AsyncSaveFinishProc proc) +{ + if (_exit_game) return; + while (_async_save_finish != NULL) CSleep(10); + + _async_save_finish = proc; +} + +/** + * Handle async save finishes. + */ +void ProcessAsyncSaveFinish() +{ + if (_async_save_finish == NULL) return; + + _async_save_finish(); + + _async_save_finish = NULL; +} + /** * Fill the input buffer by reading from the file with the given reader */ @@ -1248,6 +1274,7 @@ /* these define the chunks */ extern const ChunkHandler _misc_chunk_handlers[]; +extern const ChunkHandler _name_chunk_handlers[]; extern const ChunkHandler _cheat_chunk_handlers[] ; extern const ChunkHandler _setting_chunk_handlers[]; extern const ChunkHandler _player_chunk_handlers[]; @@ -1268,6 +1295,7 @@ static const ChunkHandler * const _chunk_handlers[] = { _misc_chunk_handlers, + _name_chunk_handlers, _cheat_chunk_handlers, _setting_chunk_handlers, _veh_chunk_handlers, @@ -1455,7 +1483,7 @@ /** Update the gui accordingly when starting saving * and set locks on saveload. Also turn off fast-forward cause with that * saving takes Aaaaages */ -void SaveFileStart() +static void SaveFileStart() { _ts.ff_state = _fast_forward; _fast_forward = 0; @@ -1467,7 +1495,7 @@ /** Update the gui accordingly when saving is done and release locks * on saveload */ -void SaveFileDone() +static void SaveFileDone() { _fast_forward = _ts.ff_state; if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE); @@ -1494,7 +1522,7 @@ } /** Show a gui message when saving has failed */ -void SaveFileError() +static void SaveFileError() { SetDParamStr(0, GetSaveLoadErrorString()); ShowErrorMessage(STR_012D, STR_NULL, 0, 0); @@ -1543,7 +1571,7 @@ GetSavegameFormat("memory")->uninit_write(); // clean the memorypool fclose(_sl.fh); - if (threaded) OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_DONE); + if (threaded) SetAsyncSaveFinish(SaveFileDone); return SL_OK; } @@ -1555,7 +1583,7 @@ fprintf(stderr, GetSaveLoadErrorString()); if (threaded) { - OTTD_SendThreadMessage(MSG_OTTD_SAVETHREAD_ERROR); + SetAsyncSaveFinish(SaveFileError); } else { SaveFileError(); } diff -r 7856e972f8aa -r 7798ae816af8 src/saveload.h --- a/src/saveload.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/saveload.h Mon Apr 21 21:15:50 2008 +0000 @@ -320,7 +320,4 @@ void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); -void SaveFileStart(); -void SaveFileDone(); -void SaveFileError(); #endif /* SAVELOAD_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/settings.cpp --- a/src/settings.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/settings.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -1648,20 +1648,18 @@ #undef NO #undef CR -static uint NewsDisplayLoadConfig(IniFile *ini, const char *grpname) +static void NewsDisplayLoadConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini_getgroup(ini, grpname, -1); IniItem *item; - /* By default, set everything to full (0xAAAAAAAA = 1010101010101010) */ - uint res = 0xAAAAAAAA; - /* If no group exists, return everything full */ - if (group == NULL) return res; + /* If no group exists, return */ + if (group == NULL) return; for (item = group->item; item != NULL; item = item->next) { int news_item = -1; for (int i = 0; i < NT_END; i++) { - if (strcasecmp(item->name, _news_display_name[i]) == 0) { + if (strcasecmp(item->name, _news_type_data[i].name) == 0) { news_item = i; break; } @@ -1672,18 +1670,16 @@ } if (strcasecmp(item->value, "full") == 0) { - SB(res, news_item * 2, 2, 2); + _news_type_data[news_item].display = ND_FULL; } else if (strcasecmp(item->value, "off") == 0) { - SB(res, news_item * 2, 2, 0); + _news_type_data[news_item].display = ND_OFF; } else if (strcasecmp(item->value, "summarized") == 0) { - SB(res, news_item * 2, 2, 1); + _news_type_data[news_item].display = ND_SUMMARY; } else { DEBUG(misc, 0, "Invalid display value: %s", item->value); continue; } } - - return res; } /* Load a GRF configuration from the given group name */ @@ -1739,7 +1735,7 @@ return first; } -static void NewsDisplaySaveConfig(IniFile *ini, const char *grpname, uint news_display) +static void NewsDisplaySaveConfig(IniFile *ini, const char *grpname) { IniGroup *group = ini_getgroup(ini, grpname, -1); IniItem **item; @@ -1750,11 +1746,11 @@ for (int i = 0; i < NT_END; i++) { const char *value; - int v = GB(news_display, i * 2, 2); + int v = _news_type_data[i].display; - value = (v == 0 ? "off" : (v == 1 ? "summarized" : "full")); + value = (v == ND_OFF ? "off" : (v == ND_SUMMARY ? "summarized" : "full")); - *item = ini_item_alloc(group, _news_display_name[i], strlen(_news_display_name[i])); + *item = ini_item_alloc(group, _news_type_data[i].name, strlen(_news_type_data[i].name)); (*item)->value = (char*)pool_strdup(&ini->pool, value, strlen(value)); item = &(*item)->next; } @@ -1841,7 +1837,7 @@ HandleSettingDescs(ini, ini_load_settings, ini_load_setting_list); _grfconfig_newgame = GRFLoadConfig(ini, "newgrf", false); _grfconfig_static = GRFLoadConfig(ini, "newgrf-static", true); - _news_display_opt = NewsDisplayLoadConfig(ini, "news_display"); + NewsDisplayLoadConfig(ini, "news_display"); CheckDifficultyLevels(); ini_free(ini); } @@ -1853,7 +1849,7 @@ HandleSettingDescs(ini, ini_save_settings, ini_save_setting_list); GRFSaveConfig(ini, "newgrf", _grfconfig_newgame); GRFSaveConfig(ini, "newgrf-static", _grfconfig_static); - NewsDisplaySaveConfig(ini, "news_display", _news_display_opt); + NewsDisplaySaveConfig(ini, "news_display"); SaveVersionInConfig(ini); ini_save(_config_file, ini); ini_free(ini); diff -r 7856e972f8aa -r 7798ae816af8 src/ship.h --- a/src/ship.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/ship.h Mon Apr 21 21:15:50 2008 +0000 @@ -35,7 +35,7 @@ WindowClass GetVehicleListWindowClass() const { return WC_SHIPS_LIST; } void PlayLeaveStationSound() const; bool IsPrimaryVehicle() const { return true; } - int GetImage(Direction direction) const; + SpriteID GetImage(Direction direction) const; int GetDisplaySpeed() const { return this->cur_speed * 10 / 32; } int GetDisplayMaxSpeed() const { return this->max_speed * 10 / 32; } Money GetRunningCost() const { return ShipVehInfo(this->engine_type)->running_cost * _price.ship_running; } diff -r 7856e972f8aa -r 7798ae816af8 src/ship_cmd.cpp --- a/src/ship_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/ship_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -40,6 +40,7 @@ #include "gfx_func.h" #include "settings_type.h" #include "order_func.h" +#include "effectvehicle_func.h" #include "table/strings.h" @@ -57,20 +58,23 @@ return TrackStatusToTrackBits(GetTileTrackStatus(tile, TRANSPORT_WATER, 0)); } -void DrawShipEngine(int x, int y, EngineID engine, SpriteID pal) +static SpriteID GetShipIcon(EngineID engine) { - int spritenum = ShipVehInfo(engine)->image_index; + uint8 spritenum = ShipVehInfo(engine)->image_index; if (is_custom_sprite(spritenum)) { - int sprite = GetCustomVehicleIcon(engine, DIR_W); + SpriteID sprite = GetCustomVehicleIcon(engine, DIR_W); + if (sprite != 0) return sprite; - if (sprite != 0) { - DrawSprite(sprite, pal, x, y); - return; - } spritenum = _orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index; } - DrawSprite(6 + _ship_sprites[spritenum], pal, x, y); + + return 6 + _ship_sprites[spritenum]; +} + +void DrawShipEngine(int x, int y, EngineID engine, SpriteID pal) +{ + DrawSprite(GetShipIcon(engine), pal, x, y); } /** Get the size of the sprite of a ship sprite heading west (used for lists) @@ -80,35 +84,23 @@ */ void GetShipSpriteSize(EngineID engine, uint &width, uint &height) { - SpriteID spritenum = ShipVehInfo(engine)->image_index; - SpriteID custom_sprite = 0; - - if (is_custom_sprite(spritenum)) { - custom_sprite = GetCustomVehicleIcon(engine, DIR_W); - spritenum = _orig_ship_vehicle_info[engine - SHIP_ENGINES_INDEX].image_index; - } - if (custom_sprite == 0) { - spritenum = 6 + _ship_sprites[spritenum]; - } else { - spritenum = custom_sprite; - } - - const Sprite *spr = GetSprite(spritenum); + const Sprite *spr = GetSprite(GetShipIcon(engine)); width = spr->width; height = spr->height; } -int Ship::GetImage(Direction direction) const +SpriteID Ship::GetImage(Direction direction) const { - int spritenum = this->spritenum; + uint8 spritenum = this->spritenum; if (is_custom_sprite(spritenum)) { - int sprite = GetCustomVehicleSprite(this, direction); + SpriteID sprite = GetCustomVehicleSprite(this, direction); + if (sprite != 0) return sprite; - if (sprite != 0) return sprite; spritenum = _orig_ship_vehicle_info[this->engine_type - SHIP_ENGINES_INDEX].image_index; } + return _ship_sprites[spritenum] + direction; } @@ -210,7 +202,7 @@ if (!(v->vehstatus & VS_HIDDEN)) { Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE); - if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2; + if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2; } } @@ -594,7 +586,7 @@ HandleBrokenShip(v); return; } - v->breakdown_ctr--; + if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } if (v->vehstatus & VS_STOPPED) return; @@ -881,19 +873,16 @@ */ CommandCost CmdStartStopShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2) { - Vehicle *v; - uint16 callback; - if (!IsValidVehicleID(p1)) return CMD_ERROR; - v = GetVehicle(p1); + Vehicle *v = GetVehicle(p1); if (v->type != VEH_SHIP || !CheckOwnership(v->owner)) return CMD_ERROR; /* Check if this ship can be started/stopped. The callback will fail or * return 0xFF if it can. */ - callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); - if (callback != CALLBACK_FAILED && callback != 0xFF) { + uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); + if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) { StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback); return_cmd_error(error); } diff -r 7856e972f8aa -r 7798ae816af8 src/smallmap_gui.cpp --- a/src/smallmap_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/smallmap_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -682,7 +682,7 @@ byte color; FOR_ALL_VEHICLES(v) { - if (v->type != VEH_SPECIAL && + if (v->type != VEH_EFFECT && (v->vehstatus & (VS_HIDDEN | VS_UNCLICKABLE)) == 0) { /* Remap into flat coordinates. */ Point pt = RemapCoords( @@ -1108,15 +1108,15 @@ static void ExtraViewPortWndProc(Window *w, WindowEvent *e) { switch (e->event) { - case WE_CREATE: /* Disable zoom in button */ + case WE_CREATE: // Disable zoom in button /* New viewport start at (zero,zero) */ - AssignWindowViewport(w, 3, 17, w->widget[4].right - w->widget[4].left - 1, w->widget[4].bottom - w->widget[4].top - 1, 0, ZOOM_LVL_VIEWPORT); + InitializeWindowViewport(w, 3, 17, w->widget[4].right - w->widget[4].left - 1, w->widget[4].bottom - w->widget[4].top - 1, 0, ZOOM_LVL_VIEWPORT); w->DisableWidget(5); break; case WE_PAINT: - // set the number in the title bar + /* set the number in the title bar */ SetDParam(0, w->window_number + 1); DrawWindowWidgets(w); @@ -1128,7 +1128,7 @@ case 5: DoZoomInOutWindow(ZOOM_IN, w); break; case 6: DoZoomInOutWindow(ZOOM_OUT, w); break; - case 7: { /* location button (move main view to same spot as this view) 'Paste Location' */ + case 7: { // location button (move main view to same spot as this view) 'Paste Location' Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0); int x = WP(w, vp_d).scrollpos_x; // Where is the main looking at int y = WP(w, vp_d).scrollpos_y; @@ -1138,7 +1138,7 @@ WP(w2, vp_d).dest_scrollpos_y = y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2; } break; - case 8: { /* inverse location button (move this view to same spot as main view) 'Copy Location' */ + case 8: { // inverse location button (move this view to same spot as main view) 'Copy Location' const Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0); int x = WP(w2, const vp_d).scrollpos_x; int y = WP(w2, const vp_d).scrollpos_y; diff -r 7856e972f8aa -r 7798ae816af8 src/sound.cpp --- a/src/sound.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/sound.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -207,6 +207,14 @@ } } +/** + * Decide 'where' (between left and right speaker) to play the sound effect. + * @param sound Sound effect to play + * @param left Left edge of virtual coordinates where the sound is produced + * @param right Right edge of virtual coordinates where the sound is produced + * @param top Top edge of virtual coordinates where the sound is produced + * @param bottom Bottom edge of virtual coordinates where the sound is produced + */ static void SndPlayScreenCoordFx(SoundFx sound, int left, int right, int top, int bottom) { Window* const *wz; @@ -231,7 +239,6 @@ return; } } - } void SndPlayTileFx(SoundFx sound, TileIndex tile) diff -r 7856e972f8aa -r 7798ae816af8 src/station_base.h --- a/src/station_base.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/station_base.h Mon Apr 21 21:15:50 2008 +0000 @@ -159,6 +159,7 @@ uint16 random_bits; byte waiting_triggers; + uint8 cached_anim_triggers; ///< Combined animation trigger bitmask, used to determine if trigger processing should happen. StationRect rect; ///< Station spread out rectangle (not saved) maintained by StationRect_xxx() functions diff -r 7856e972f8aa -r 7798ae816af8 src/station_cmd.cpp --- a/src/station_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/station_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -42,6 +42,7 @@ #include "string_func.h" #include "signal_func.h" #include "oldpool_func.h" +#include "animated_tile_func.h" #include "table/sprites.h" #include "table/strings.h" @@ -1013,7 +1014,7 @@ } /* Check if the station is buildable */ - if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE) == 0) { + if (HasBit(statspec->callbackmask, CBM_STATION_AVAIL) && GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) { return CMD_ERROR; } } @@ -1038,6 +1039,12 @@ st->rect.BeforeAddRect(tile_org, w_org, h_org, StationRect::ADD_TRY); + if (statspec != NULL) { + /* Include this station spec's animation trigger bitmask + * in the station's cached copy. */ + st->cached_anim_triggers |= statspec->anim_triggers; + } + tile_delta = (axis == AXIS_X ? TileDiffXY(1, 0) : TileDiffXY(0, 1)); track = AxisToTrack(axis); @@ -1054,6 +1061,7 @@ MakeRailStation(tile, st->owner, st->index, axis, layout & ~1, (RailType)GB(p2, 0, 4)); SetCustomStationSpecIndex(tile, specindex); SetStationTileRandomBits(tile, GB(Random(), 0, 4)); + SetStationAnimationFrame(tile, 0); if (statspec != NULL) { /* Use a fixed axis for GetPlatformInfo as our platforms / numtracks are always the right way around */ @@ -1062,6 +1070,9 @@ /* As the station is not yet completely finished, the station does not yet exist. */ uint16 callback = GetStationCallback(CBID_STATION_TILE_LAYOUT, platinfo, 0, statspec, NULL, tile); if (callback != CALLBACK_FAILED && callback < 8) SetStationGfx(tile, (callback & ~1) + axis); + + /* Trigger station animation -- after building? */ + StationAnimationTrigger(st, tile, STAT_ANIM_BUILT); } tile += tile_delta; @@ -1283,6 +1294,7 @@ free(st->speclist); st->num_specs = 0; st->speclist = NULL; + st->cached_anim_triggers = 0; InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS); UpdateStationVirtCoordDirty(st); @@ -2368,6 +2380,11 @@ { GFX_WINDSACK_INTERCON_FIRST, GFX_WINDSACK_INTERCON_LAST, 1 } }; + if (IsRailwayStation(tile)) { + AnimateStationTile(tile); + return; + } + StationGfx gfx = GetStationGfx(tile); for (const AnimData *i = data; i != endof(data); i++) { @@ -2614,7 +2631,16 @@ if (IsValidStationID(i)) StationHandleBigTick(GetStation(i)); Station *st; - FOR_ALL_STATIONS(st) StationHandleSmallTick(st); + FOR_ALL_STATIONS(st) { + StationHandleSmallTick(st); + + /* Run 250 tick interval trigger for station animation. + * Station index is included so that triggers are not all done + * at the same time. */ + if ((_tick_counter + st->index) % 250 == 0) { + StationAnimationTrigger(st, st->xy, STAT_ANIM_250_TICKS); + } + } } void StationMonthlyLoop() @@ -2646,6 +2672,8 @@ st->goods[type].cargo.Append(new CargoPacket(st->index, amount)); SetBit(st->goods[type].acceptance_pickup, GoodsEntry::PICKUP); + StationAnimationTrigger(st, st->xy, STAT_ANIM_NEW_CARGO, type); + InvalidateWindow(WC_STATION_VIEW, st->index); st->MarkTilesDirty(true); } @@ -3008,6 +3036,8 @@ } for (CargoID c = 0; c < NUM_CARGO; c++) st->goods[c].cargo.InvalidateCache(); + + StationUpdateAnimTriggers(st); } } diff -r 7856e972f8aa -r 7798ae816af8 src/station_gui.cpp --- a/src/station_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/station_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -184,35 +184,36 @@ assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(plstations_d)); /** - * Set the 'SL_REBUILD' flag for all station lists + * Set the station sort flag for all station-list windows. + * @param sl_flag Sort list flag to set for all station-list windows */ -void RebuildStationLists() +static void SetStationListsFlag(StationListFlags sl_flag) { Window *const *wz; FOR_ALL_WINDOWS(wz) { Window *w = *wz; if (w->window_class == WC_STATION_LIST) { - WP(w, plstations_d).flags |= SL_REBUILD; + WP(w, plstations_d).flags |= sl_flag; SetWindowDirty(w); } } } /** + * Set the 'SL_REBUILD' flag for all station lists + */ +void RebuildStationLists() +{ + SetStationListsFlag(SL_REBUILD); +} + +/** * Set the 'SL_RESORT' flag for all station lists */ void ResortStationLists() { - Window *const *wz; - - FOR_ALL_WINDOWS(wz) { - Window *w = *wz; - if (w->window_class == WC_STATION_LIST) { - WP(w, plstations_d).flags |= SL_RESORT; - SetWindowDirty(w); - } - } + SetStationListsFlag(SL_RESORT); } /** diff -r 7856e972f8aa -r 7798ae816af8 src/strings.cpp --- a/src/strings.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/strings.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -37,6 +37,7 @@ #include "settings_type.h" #include "video/video_driver.hpp" #include "engine_func.h" +#include "saveload.h" #include "table/strings.h" #include "table/control_codes.h" @@ -1045,11 +1046,11 @@ static char *StationGetSpecialString(char *buff, int x, const char* last) { - if ((x & 0x01) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN); - if ((x & 0x02) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY); - if ((x & 0x04) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS); - if ((x & 0x08) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE); - if ((x & 0x10) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP); + if ((x & FACIL_TRAIN) && (buff + Utf8CharLen(SCC_TRAIN) < last)) buff += Utf8Encode(buff, SCC_TRAIN); + if ((x & FACIL_TRUCK_STOP) && (buff + Utf8CharLen(SCC_LORRY) < last)) buff += Utf8Encode(buff, SCC_LORRY); + if ((x & FACIL_BUS_STOP) && (buff + Utf8CharLen(SCC_BUS) < last)) buff += Utf8Encode(buff, SCC_BUS); + if ((x & FACIL_AIRPORT) && (buff + Utf8CharLen(SCC_PLANE) < last)) buff += Utf8Encode(buff, SCC_PLANE); + if ((x & FACIL_DOCK) && (buff + Utf8CharLen(SCC_SHIP) < last)) buff += Utf8Encode(buff, SCC_SHIP); *buff = '\0'; return buff; } @@ -1226,31 +1227,6 @@ return NULL; } -/** - * remap a string ID from the old format to the new format - * @param s StringID that requires remapping - * @return translated ID*/ -StringID RemapOldStringID(StringID s) -{ - switch (s) { - case 0x0006: return STR_SV_EMPTY; - case 0x7000: return STR_SV_UNNAMED; - case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH; - case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH; - case 0x8864: return STR_SV_TRAIN_NAME; - case 0x902B: return STR_SV_ROADVEH_NAME; - case 0x9830: return STR_SV_SHIP_NAME; - case 0xA02F: return STR_SV_AIRCRAFT_NAME; - - default: - if (IsInsideMM(s, 0x300F, 0x3030)) { - return s - 0x300F + STR_SV_STNAME; - } else { - return s; - } - } -} - #ifdef ENABLE_NETWORK extern void SortNetworkLanguages(); #else /* ENABLE_NETWORK */ @@ -1342,6 +1318,8 @@ return getenv("LANG"); } +#else +const char *GetCurrentLocale(const char *param); #endif /* !(defined(WIN32) || defined(__APPLE__)) */ int CDECL StringIDSorter(const void *a, const void *b) @@ -1548,3 +1526,118 @@ } } } + + +/* --- Handling of saving/loading string IDs from old savegames --- */ + +/** + * Remap a string ID from the old format to the new format + * @param s StringID that requires remapping + * @return translated ID + */ +StringID RemapOldStringID(StringID s) +{ + switch (s) { + case 0x0006: return STR_SV_EMPTY; + case 0x7000: return STR_SV_UNNAMED; + case 0x70E4: return SPECSTR_PLAYERNAME_ENGLISH; + case 0x70E9: return SPECSTR_PLAYERNAME_ENGLISH; + case 0x8864: return STR_SV_TRAIN_NAME; + case 0x902B: return STR_SV_ROADVEH_NAME; + case 0x9830: return STR_SV_SHIP_NAME; + case 0xA02F: return STR_SV_AIRCRAFT_NAME; + + default: + if (IsInsideMM(s, 0x300F, 0x3030)) { + return s - 0x300F + STR_SV_STNAME; + } else { + return s; + } + } +} + +/** Location to load the old names to. */ +char *_old_name_array = NULL; + +/** + * Copy and convert old custom names to UTF-8. + * They were all stored in a 512 by 32 long string array and are + * now stored with stations, waypoints and other places with names. + * @param id the StringID of the custom name to clone. + * @return the clones custom name. + */ +char *CopyFromOldName(StringID id) +{ + /* Is this name an (old) custom name? */ + if (GB(id, 11, 5) != 15) return NULL; + + if (CheckSavegameVersion(37)) { + /* Old names were 32 characters long, so 128 characters should be + * plenty to allow for expansion when converted to UTF-8. */ + char tmp[128]; + const char *strfrom = &_old_name_array[32 * GB(id, 0, 9)]; + char *strto = tmp; + + for (; *strfrom != '\0'; strfrom++) { + WChar c = (byte)*strfrom; + + /* Map from non-ISO8859-15 characters to UTF-8. */ + switch (c) { + case 0xA4: c = 0x20AC; break; // Euro + case 0xA6: c = 0x0160; break; // S with caron + case 0xA8: c = 0x0161; break; // s with caron + case 0xB4: c = 0x017D; break; // Z with caron + case 0xB8: c = 0x017E; break; // z with caron + case 0xBC: c = 0x0152; break; // OE ligature + case 0xBD: c = 0x0153; break; // oe ligature + case 0xBE: c = 0x0178; break; // Y with diaresis + default: break; + } + + /* Check character will fit into our buffer. */ + if (strto + Utf8CharLen(c) > lastof(tmp)) break; + + strto += Utf8Encode(strto, c); + } + + /* Terminate the new string and copy it back to the name array */ + *strto = '\0'; + + return strdup(tmp); + } else { + /* Name will already be in UTF-8. */ + return strdup(&_old_name_array[32 * GB(id, 0, 9)]); + } +} + +/** + * Free the memory of the old names array. + * Should be called once the old names have all been converted. + */ +void ResetOldNames() +{ + free(_old_name_array); + _old_name_array = NULL; +} + +/** + * Initialize the old names table memory. + */ +void InitializeOldNames() +{ + free(_old_name_array); + _old_name_array = CallocT(512 * 32); +} + +static void Load_NAME() +{ + int index; + + while ((index = SlIterateArray()) != -1) { + SlArray(&_old_name_array[32 * index], SlGetFieldLength(), SLE_UINT8); + } +} + +extern const ChunkHandler _name_chunk_handlers[] = { + { 'NAME', NULL, Load_NAME, CH_ARRAY | CH_LAST}, +}; diff -r 7856e972f8aa -r 7798ae816af8 src/strings_func.h --- a/src/strings_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/strings_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -78,4 +78,7 @@ void CheckForMissingGlyphsInLoadedLanguagePack(); +StringID RemapOldStringID(StringID s); +char *CopyFromOldName(StringID id); + #endif /* STRINGS_TYPE_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/texteff.cpp --- a/src/texteff.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/texteff.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -4,10 +4,8 @@ #include "stdafx.h" #include "openttd.h" -#include "tile_cmd.h" #include "landscape.h" #include "gfx_func.h" -#include "saveload.h" #include "console.h" #include "variables.h" #include "blitter/factory.hpp" @@ -423,128 +421,3 @@ default: NOT_REACHED(); } } - -/** The table/list with animated tiles. */ -TileIndex *_animated_tile_list = NULL; -/** The number of animated tiles in the current state. */ -uint _animated_tile_count = 0; -/** The number of slots for animated tiles allocated currently. */ -static uint _animated_tile_allocated = 0; - -/** - * Removes the given tile from the animated tile table. - * @param tile the tile to remove - */ -void DeleteAnimatedTile(TileIndex tile) -{ - for (TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { - if (tile == *ti) { - /* Remove the hole - * The order of the remaining elements must stay the same, otherwise the animation loop - * may miss a tile; that's why we must use memmove instead of just moving the last element. - */ - memmove(ti, ti + 1, (_animated_tile_list + _animated_tile_count - (ti + 1)) * sizeof(*ti)); - _animated_tile_count--; - MarkTileDirtyByTile(tile); - return; - } - } -} - -/** - * Add the given tile to the animated tile table (if it does not exist - * on that table yet). Also increases the size of the table if necessary. - * @param tile the tile to make animated - */ -void AddAnimatedTile(TileIndex tile) -{ - MarkTileDirtyByTile(tile); - - for (const TileIndex *ti = _animated_tile_list; ti < _animated_tile_list + _animated_tile_count; ti++) { - if (tile == *ti) return; - } - - /* Table not large enough, so make it larger */ - if (_animated_tile_count == _animated_tile_allocated) { - _animated_tile_allocated *= 2; - _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); - } - - _animated_tile_list[_animated_tile_count] = tile; - _animated_tile_count++; -} - -/** - * Animate all tiles in the animated tile list, i.e.\ call AnimateTile on them. - */ -void AnimateAnimatedTiles() -{ - const TileIndex *ti = _animated_tile_list; - while (ti < _animated_tile_list + _animated_tile_count) { - const TileIndex curr = *ti; - AnimateTile(curr); - /* During the AnimateTile call, DeleteAnimatedTile could have been called, - * deleting an element we've already processed and pushing the rest one - * slot to the left. We can detect this by checking whether the index - * in the current slot has changed - if it has, an element has been deleted, - * and we should process the current slot again instead of going forward. - * NOTE: this will still break if more than one animated tile is being - * deleted during the same AnimateTile call, but no code seems to - * be doing this anyway. - */ - if (*ti == curr) ++ti; - } -} - -/** - * Initialize all animated tile variables to some known begin point - */ -void InitializeAnimatedTiles() -{ - _animated_tile_list = ReallocT(_animated_tile_list, 256); - _animated_tile_count = 0; - _animated_tile_allocated = 256; -} - -/** - * Save the ANIT chunk. - */ -static void Save_ANIT() -{ - SlSetLength(_animated_tile_count * sizeof(*_animated_tile_list)); - SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); -} - -/** - * Load the ANIT chunk; the chunk containing the animated tiles. - */ -static void Load_ANIT() -{ - /* Before version 80 we did NOT have a variable length animated tile table */ - if (CheckSavegameVersion(80)) { - /* In pre version 6, we has 16bit per tile, now we have 32bit per tile, convert it ;) */ - SlArray(_animated_tile_list, 256, CheckSavegameVersion(6) ? (SLE_FILE_U16 | SLE_VAR_U32) : SLE_UINT32); - - for (_animated_tile_count = 0; _animated_tile_count < 256; _animated_tile_count++) { - if (_animated_tile_list[_animated_tile_count] == 0) break; - } - return; - } - - _animated_tile_count = SlGetFieldLength() / sizeof(*_animated_tile_list); - - /* Determine a nice rounded size for the amount of allocated tiles */ - _animated_tile_allocated = 256; - while (_animated_tile_allocated < _animated_tile_count) _animated_tile_allocated *= 2; - - _animated_tile_list = ReallocT(_animated_tile_list, _animated_tile_allocated); - SlArray(_animated_tile_list, _animated_tile_count, SLE_UINT32); -} - -/** - * "Definition" imported by the saveload code to be able to load and save - * the animated tile table. - */ -extern const ChunkHandler _animated_tile_chunk_handlers[] = { - { 'ANIT', Save_ANIT, Load_ANIT, CH_RIFF | CH_LAST}, -}; diff -r 7856e972f8aa -r 7798ae816af8 src/toolbar_gui.cpp --- a/src/toolbar_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/toolbar_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -1419,8 +1419,7 @@ Window *AllocateToolbar() { - /* Clean old GUI values */ - _last_built_railtype = RAILTYPE_RAIL; + /* Clean old GUI values; railtype is (re)set by rail_gui.cpp */ _last_built_roadtype = ROADTYPE_ROAD; Window *w = AllocateWindowDesc((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc); diff -r 7856e972f8aa -r 7798ae816af8 src/town_cmd.cpp --- a/src/town_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/town_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -45,6 +45,9 @@ #include "economy_func.h" #include "station_func.h" #include "cheat_func.h" +#include "functions.h" +#include "animated_tile_func.h" +#include "date_func.h" #include "table/strings.h" #include "table/sprites.h" @@ -268,7 +271,10 @@ pos += (pos < dest) ? 1 : -1; SetLiftPosition(tile, pos); - if (pos == dest) HaltLift(tile); + if (pos == dest) { + HaltLift(tile); + DeleteAnimatedTile(tile); + } MarkTileDirtyByTile(tile); } @@ -375,16 +381,19 @@ IncHouseConstructionTick(tile); if (GetHouseConstructionTick(tile) != 0) return; + const HouseSpec *hs = GetHouseSpecs(GetHouseType(tile)); + /* Check and/or */ - if (HasBit(GetHouseSpecs(GetHouseType(tile))->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) { + if (HasBit(hs->callback_mask, CBM_HOUSE_CONSTRUCTION_STATE_CHANGE)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_CONSTRUCTION_STATE_CHANGE, 0, 0, GetHouseType(tile), GetTownByTile(tile), tile); - if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(tile, callback_res); + if (callback_res != CALLBACK_FAILED) ChangeHouseAnimationFrame(hs->grffile, tile, callback_res); } if (IsHouseCompleted(tile)) { /* Now that construction is complete, we can add the population of the * building to the town. */ - ChangePopulation(GetTownByTile(tile), GetHouseSpecs(GetHouseType(tile))->population); + ChangePopulation(GetTownByTile(tile), hs->population); + SetHouseConstructionYear(tile, _cur_year); } MarkTileDirtyByTile(tile); } @@ -1644,6 +1653,9 @@ assert(CmdSucceeded(cc)); MakeHouseTile(tile, tid, counter, stage, type, random_bits); + if (GetHouseSpecs(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(tile); + + MarkTileDirtyByTile(tile); } @@ -1924,7 +1936,7 @@ if (HasBit(hs->callback_mask, CBM_HOUSE_ALLOW_CONSTRUCTION)) { uint16 callback_res = GetHouseCallback(CBID_HOUSE_ALLOW_CONSTRUCTION, 0, 0, house, t, tile); - if (callback_res != CALLBACK_FAILED && callback_res == 0) continue; + if (callback_res != CALLBACK_FAILED && GB(callback_res, 0, 8) == 0) continue; } } diff -r 7856e972f8aa -r 7798ae816af8 src/town_gui.cpp --- a/src/town_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/town_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -396,7 +396,7 @@ if (w != NULL) { w->flags4 |= WF_DISABLE_VP_SCROLL; - AssignWindowViewport(w, 3, 17, 0xFE, 0x56, GetTown(town)->xy, ZOOM_LVL_TOWN); + InitializeWindowViewport(w, 3, 17, 254, 86, GetTown(town)->xy, ZOOM_LVL_TOWN); } } diff -r 7856e972f8aa -r 7798ae816af8 src/town_map.h --- a/src/town_map.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/town_map.h Mon Apr 21 21:15:50 2008 +0000 @@ -6,9 +6,8 @@ #define TOWN_MAP_H #include "town.h" -#include "date_func.h" +#include "date_type.h" #include "tile_map.h" -#include "functions.h" /** * Get the index of which town this house/street is attached to. @@ -113,7 +112,6 @@ static inline void HaltLift(TileIndex t) { SB(_me[t].m7, 0, 4, 0); - DeleteAnimatedTile(t); } /** @@ -206,9 +204,6 @@ _m[t].m5 = IsHouseCompleted(t) ? 0 : (stage << 3 | counter); SetHouseAnimationFrame(t, 0); _me[t].m7 = GetHouseSpecs(type)->processing_time; - - if (GetHouseSpecs(type)->building_flags & BUILDING_IS_ANIMATED) AddAnimatedTile(t); - MarkTileDirtyByTile(t); } /** @@ -266,11 +261,22 @@ /* House is now completed. * Store the year of construction as well, for newgrf house purpose */ SetHouseCompleted(t, true); - _m[t].m5 = Clamp(_cur_year - ORIGINAL_BASE_YEAR, 0, 0xFF); } } /** + * Set the year that this house was constructed (between 1920 and 2175). + * @param t the tile of this house + * @param year the year to set + * @pre IsTileType(t, MP_HOUSE) && IsHouseCompleted(t) + */ +static inline void SetHouseConstructionYear(TileIndex t, Year year) +{ + assert(IsTileType(t, MP_HOUSE) && IsHouseCompleted(t)); + _m[t].m5 = Clamp(year - ORIGINAL_BASE_YEAR, 0, 0xFF); +} + +/** * Get the year that this house was constructed (between 1920 and 2175). * @param t the tile of this house * @pre IsTileType(t, MP_HOUSE) diff -r 7856e972f8aa -r 7798ae816af8 src/train.h --- a/src/train.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/train.h Mon Apr 21 21:15:50 2008 +0000 @@ -296,7 +296,7 @@ WindowClass GetVehicleListWindowClass() const { return WC_TRAINS_LIST; } void PlayLeaveStationSound() const; bool IsPrimaryVehicle() const { return IsFrontEngine(this); } - int GetImage(Direction direction) const; + SpriteID GetImage(Direction direction) const; int GetDisplaySpeed() const { return this->u.rail.last_speed * 10 / 16; } int GetDisplayMaxSpeed() const { return this->u.rail.cached_max_speed * 10 / 16; } Money GetRunningCost() const; diff -r 7856e972f8aa -r 7798ae816af8 src/train_cmd.cpp --- a/src/train_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/train_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -49,6 +49,8 @@ #include "ai/ai.h" #include "settings_type.h" #include "order_func.h" +#include "newgrf_station.h" +#include "effectvehicle_func.h" #include "table/strings.h" #include "table/train_cmd.h" @@ -239,7 +241,7 @@ if (HasBit(EngInfo(u->engine_type)->callbackmask, CBM_TRAIN_WAGON_POWER)) { uint16 callback = GetVehicleCallback(CBID_TRAIN_WAGON_POWER, 0, 0, u->engine_type, u); - if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = callback; + if (callback != CALLBACK_FAILED) u->u.rail.cached_vis_effect = GB(callback, 0, 8); } if (rvi_v->pow_wag_power != 0 && rvi_u->railveh_type == RAILVEH_WAGON && @@ -466,59 +468,61 @@ v->acceleration = Clamp(power / weight * 4, 1, 255); } -int Train::GetImage(Direction direction) const +SpriteID Train::GetImage(Direction direction) const { - int img = this->spritenum; - int base; + uint8 spritenum = this->spritenum; + SpriteID sprite; if (HasBit(this->u.rail.flags, VRF_REVERSE_DIRECTION)) direction = ReverseDir(direction); - if (is_custom_sprite(img)) { - base = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(img))); - if (base != 0) return base; - img = _orig_rail_vehicle_info[this->engine_type].image_index; + if (is_custom_sprite(spritenum)) { + sprite = GetCustomVehicleSprite(this, (Direction)(direction + 4 * IS_CUSTOM_SECONDHEAD_SPRITE(spritenum))); + if (sprite != 0) return sprite; + + spritenum = _orig_rail_vehicle_info[this->engine_type].image_index; } - base = _engine_sprite_base[img] + ((direction + _engine_sprite_add[img]) & _engine_sprite_and[img]); - - if (this->cargo.Count() >= this->cargo_cap / 2U) base += _wagon_full_adder[img]; - return base; + sprite = _engine_sprite_base[spritenum] + ((direction + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]); + + if (this->cargo.Count() >= this->cargo_cap / 2U) sprite += _wagon_full_adder[spritenum]; + + return sprite; +} + +static SpriteID GetRailIcon(EngineID engine, bool rear_head, int &y) +{ + Direction dir = rear_head ? DIR_E : DIR_W; + uint8 spritenum = RailVehInfo(engine)->image_index; + + if (is_custom_sprite(spritenum)) { + SpriteID sprite = GetCustomVehicleIcon(engine, dir); + if (sprite != 0) { + y += _traininfo_vehicle_pitch; // TODO Make this per-GRF + return sprite; + } + + spritenum = _orig_rail_vehicle_info[engine].image_index; + } + + if (rear_head) spritenum++; + + return ((6 + _engine_sprite_add[spritenum]) & _engine_sprite_and[spritenum]) + _engine_sprite_base[spritenum]; } void DrawTrainEngine(int x, int y, EngineID engine, SpriteID pal) { - const RailVehicleInfo *rvi = RailVehInfo(engine); - - int img = rvi->image_index; - SpriteID image = 0; - - if (is_custom_sprite(img)) { - image = GetCustomVehicleIcon(engine, DIR_W); - if (image == 0) { - img = _orig_rail_vehicle_info[engine].image_index; - } else { - y += _traininfo_vehicle_pitch; - } - } - if (image == 0) { - image = (6 & _engine_sprite_and[img]) + _engine_sprite_base[img]; + if (RailVehInfo(engine)->railveh_type == RAILVEH_MULTIHEAD) { + int yf = y; + int yr = y; + + SpriteID spritef = GetRailIcon(engine, false, yf); + SpriteID spriter = GetRailIcon(engine, true, yr); + DrawSprite(spritef, pal, x - 14, yf); + DrawSprite(spriter, pal, x + 15, yr); + } else { + SpriteID sprite = GetRailIcon(engine, false, y); + DrawSprite(sprite, pal, x, y); } - - if (rvi->railveh_type == RAILVEH_MULTIHEAD) { - DrawSprite(image, pal, x - 14, y); - x += 15; - image = 0; - if (is_custom_sprite(img)) { - image = GetCustomVehicleIcon(engine, DIR_E); - if (image == 0) img = _orig_rail_vehicle_info[engine].image_index; - } - if (image == 0) { - image = - ((6 + _engine_sprite_add[img + 1]) & _engine_sprite_and[img + 1]) + - _engine_sprite_base[img + 1]; - } - } - DrawSprite(image, pal, x, y); } static CommandCost CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags) @@ -1279,7 +1283,7 @@ /* Check if this train can be started/stopped. The callback will fail or * return 0xFF if it can. */ uint16 callback = GetVehicleCallback(CBID_VEHICLE_START_STOP_CHECK, 0, 0, v->engine_type, v); - if (callback != CALLBACK_FAILED && callback != 0xFF) { + if (callback != CALLBACK_FAILED && GB(callback, 0, 8) != 0xFF) { StringID error = GetGRFStringID(GetEngineGRFID(v->engine_type), 0xD000 + callback); return_cmd_error(error); } @@ -2219,6 +2223,8 @@ SND_41_MAGLEV }; + if (IsTileType(this->tile, MP_STATION)) StationAnimationTrigger(NULL, this->tile, STAT_ANIM_TRAIN_DEPARTS); + if (PlayVehicleSound(this, VSE_START)) return; EngineID engtype = this->engine_type; @@ -2639,6 +2645,8 @@ } v->BeginLoading(); + + StationAnimationTrigger(st, v->tile, STAT_ANIM_TRAIN_ARRIVES); } static byte AfterSetTrainPos(Vehicle *v, bool new_tile) @@ -3234,7 +3242,7 @@ if (!(v->vehstatus & VS_HIDDEN)) { Vehicle *u = CreateEffectVehicleRel(v, 4, 4, 5, EV_BREAKDOWN_SMOKE); - if (u != NULL) u->u.special.animation_state = v->breakdown_delay * 2; + if (u != NULL) u->u.effect.animation_state = v->breakdown_delay * 2; } } @@ -3423,7 +3431,7 @@ HandleBrokenTrain(v); return; } - v->breakdown_ctr--; + if (!v->current_order.IsType(OT_LOADING)) v->breakdown_ctr--; } if (HasBit(v->u.rail.flags, VRF_REVERSING) && v->cur_speed == 0) { diff -r 7856e972f8aa -r 7798ae816af8 src/vehicle.cpp --- a/src/vehicle.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/vehicle.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -47,6 +47,8 @@ #include "settings_type.h" #include "oldpool_func.h" #include "depot_map.h" +#include "animated_tile_func.h" +#include "effectvehicle_base.h" #include "table/sprites.h" #include "table/strings.h" @@ -106,6 +108,7 @@ if (!p->engine_renew) return false; if (this->age - this->max_age < (p->engine_renew_months * 30)) return false; + if (this->age == 0) return false; // rail cars don't age and lacks a max age return true; } @@ -691,11 +694,32 @@ /* now we handle all the vehicles that entered a depot this tick */ v = _first_veh_in_depot_list; - while (v != NULL) { - Vehicle *w = v->depot_list; - v->depot_list = NULL; // it should always be NULL at the end of each tick - MaybeReplaceVehicle(v, false, true); - v = w; + if (v != NULL) { + while (v != NULL) { + /* Autoreplace needs the current player set as the vehicle owner */ + _current_player = v->owner; + + /* Buffer v->depot_list and clear it. + * Autoreplace might clear this so it has to be buffered. */ + Vehicle *w = v->depot_list; + v->depot_list = NULL; // it should always be NULL at the end of each tick + + /* Start vehicle if we stopped them in VehicleEnteredDepotThisTick() + * We need to stop them between VehicleEnteredDepotThisTick() and here or we risk that + * they are already leaving the depot again before being replaced. */ + if (v->leave_depot_instantly) { + v->leave_depot_instantly = false; + v->vehstatus &= ~VS_STOPPED; + } + + CommandCost cost = MaybeReplaceVehicle(v, 0, true); + if (CmdSucceeded(cost) && cost.GetCost() != 0) { + /* Looks like we can replace this vehicle so we go ahead and do so */ + MaybeReplaceVehicle(v, DC_EXEC, true); + } + v = w; + } + _current_player = OWNER_NONE; } } @@ -823,605 +847,6 @@ } } -static void ChimneySmokeInit(Vehicle *v) -{ - uint32 r = Random(); - v->cur_image = SPR_CHIMNEY_SMOKE_0 + GB(r, 0, 3); - v->progress = GB(r, 16, 3); -} - -static void ChimneySmokeTick(Vehicle *v) -{ - if (v->progress > 0) { - v->progress--; - } else { - BeginVehicleMove(v); - - TileIndex tile = TileVirtXY(v->x_pos, v->y_pos); - if (!IsTileType(tile, MP_INDUSTRY)) { - EndVehicleMove(v); - delete v; - return; - } - - if (v->cur_image != SPR_CHIMNEY_SMOKE_7) { - v->cur_image++; - } else { - v->cur_image = SPR_CHIMNEY_SMOKE_0; - } - v->progress = 7; - VehiclePositionChanged(v); - EndVehicleMove(v); - } -} - -static void SteamSmokeInit(Vehicle *v) -{ - v->cur_image = SPR_STEAM_SMOKE_0; - v->progress = 12; -} - -static void SteamSmokeTick(Vehicle *v) -{ - bool moved = false; - - BeginVehicleMove(v); - - v->progress++; - - if ((v->progress & 7) == 0) { - v->z_pos++; - moved = true; - } - - if ((v->progress & 0xF) == 4) { - if (v->cur_image != SPR_STEAM_SMOKE_4) { - v->cur_image++; - } else { - EndVehicleMove(v); - delete v; - return; - } - moved = true; - } - - if (moved) { - VehiclePositionChanged(v); - EndVehicleMove(v); - } -} - -static void DieselSmokeInit(Vehicle *v) -{ - v->cur_image = SPR_DIESEL_SMOKE_0; - v->progress = 0; -} - -static void DieselSmokeTick(Vehicle *v) -{ - v->progress++; - - if ((v->progress & 3) == 0) { - BeginVehicleMove(v); - v->z_pos++; - VehiclePositionChanged(v); - EndVehicleMove(v); - } else if ((v->progress & 7) == 1) { - BeginVehicleMove(v); - if (v->cur_image != SPR_DIESEL_SMOKE_5) { - v->cur_image++; - VehiclePositionChanged(v); - EndVehicleMove(v); - } else { - EndVehicleMove(v); - delete v; - } - } -} - -static void ElectricSparkInit(Vehicle *v) -{ - v->cur_image = SPR_ELECTRIC_SPARK_0; - v->progress = 1; -} - -static void ElectricSparkTick(Vehicle *v) -{ - if (v->progress < 2) { - v->progress++; - } else { - v->progress = 0; - BeginVehicleMove(v); - if (v->cur_image != SPR_ELECTRIC_SPARK_5) { - v->cur_image++; - VehiclePositionChanged(v); - EndVehicleMove(v); - } else { - EndVehicleMove(v); - delete v; - } - } -} - -static void SmokeInit(Vehicle *v) -{ - v->cur_image = SPR_SMOKE_0; - v->progress = 12; -} - -static void SmokeTick(Vehicle *v) -{ - bool moved = false; - - BeginVehicleMove(v); - - v->progress++; - - if ((v->progress & 3) == 0) { - v->z_pos++; - moved = true; - } - - if ((v->progress & 0xF) == 4) { - if (v->cur_image != SPR_SMOKE_4) { - v->cur_image++; - } else { - EndVehicleMove(v); - delete v; - return; - } - moved = true; - } - - if (moved) { - VehiclePositionChanged(v); - EndVehicleMove(v); - } -} - -static void ExplosionLargeInit(Vehicle *v) -{ - v->cur_image = SPR_EXPLOSION_LARGE_0; - v->progress = 0; -} - -static void ExplosionLargeTick(Vehicle *v) -{ - v->progress++; - if ((v->progress & 3) == 0) { - BeginVehicleMove(v); - if (v->cur_image != SPR_EXPLOSION_LARGE_F) { - v->cur_image++; - VehiclePositionChanged(v); - EndVehicleMove(v); - } else { - EndVehicleMove(v); - delete v; - } - } -} - -static void BreakdownSmokeInit(Vehicle *v) -{ - v->cur_image = SPR_BREAKDOWN_SMOKE_0; - v->progress = 0; -} - -static void BreakdownSmokeTick(Vehicle *v) -{ - v->progress++; - if ((v->progress & 7) == 0) { - BeginVehicleMove(v); - if (v->cur_image != SPR_BREAKDOWN_SMOKE_3) { - v->cur_image++; - } else { - v->cur_image = SPR_BREAKDOWN_SMOKE_0; - } - VehiclePositionChanged(v); - EndVehicleMove(v); - } - - v->u.special.animation_state--; - if (v->u.special.animation_state == 0) { - BeginVehicleMove(v); - EndVehicleMove(v); - delete v; - } -} - -static void ExplosionSmallInit(Vehicle *v) -{ - v->cur_image = SPR_EXPLOSION_SMALL_0; - v->progress = 0; -} - -static void ExplosionSmallTick(Vehicle *v) -{ - v->progress++; - if ((v->progress & 3) == 0) { - BeginVehicleMove(v); - if (v->cur_image != SPR_EXPLOSION_SMALL_B) { - v->cur_image++; - VehiclePositionChanged(v); - EndVehicleMove(v); - } else { - EndVehicleMove(v); - delete v; - } - } -} - -static void BulldozerInit(Vehicle *v) -{ - v->cur_image = SPR_BULLDOZER_NE; - v->progress = 0; - v->u.special.animation_state = 0; - v->u.special.animation_substate = 0; -} - -struct BulldozerMovement { - byte direction:2; - byte image:2; - byte duration:3; -}; - -static const BulldozerMovement _bulldozer_movement[] = { - { 0, 0, 4 }, - { 3, 3, 4 }, - { 2, 2, 7 }, - { 0, 2, 7 }, - { 1, 1, 3 }, - { 2, 2, 7 }, - { 0, 2, 7 }, - { 1, 1, 3 }, - { 2, 2, 7 }, - { 0, 2, 7 }, - { 3, 3, 6 }, - { 2, 2, 6 }, - { 1, 1, 7 }, - { 3, 1, 7 }, - { 0, 0, 3 }, - { 1, 1, 7 }, - { 3, 1, 7 }, - { 0, 0, 3 }, - { 1, 1, 7 }, - { 3, 1, 7 } -}; - -static const struct { - int8 x; - int8 y; -} _inc_by_dir[] = { - { -1, 0 }, - { 0, 1 }, - { 1, 0 }, - { 0, -1 } -}; - -static void BulldozerTick(Vehicle *v) -{ - v->progress++; - if ((v->progress & 7) == 0) { - const BulldozerMovement* b = &_bulldozer_movement[v->u.special.animation_state]; - - BeginVehicleMove(v); - - v->cur_image = SPR_BULLDOZER_NE + b->image; - - v->x_pos += _inc_by_dir[b->direction].x; - v->y_pos += _inc_by_dir[b->direction].y; - - v->u.special.animation_substate++; - if (v->u.special.animation_substate >= b->duration) { - v->u.special.animation_substate = 0; - v->u.special.animation_state++; - if (v->u.special.animation_state == lengthof(_bulldozer_movement)) { - EndVehicleMove(v); - delete v; - return; - } - } - VehiclePositionChanged(v); - EndVehicleMove(v); - } -} - -static void BubbleInit(Vehicle *v) -{ - v->cur_image = SPR_BUBBLE_GENERATE_0; - v->spritenum = 0; - v->progress = 0; -} - -struct BubbleMovement { - int8 x:4; - int8 y:4; - int8 z:4; - byte image:4; -}; - -#define MK(x, y, z, i) { x, y, z, i } -#define ME(i) { i, 4, 0, 0 } - -static const BubbleMovement _bubble_float_sw[] = { - MK(0, 0, 1, 0), - MK(1, 0, 1, 1), - MK(0, 0, 1, 0), - MK(1, 0, 1, 2), - ME(1) -}; - - -static const BubbleMovement _bubble_float_ne[] = { - MK( 0, 0, 1, 0), - MK(-1, 0, 1, 1), - MK( 0, 0, 1, 0), - MK(-1, 0, 1, 2), - ME(1) -}; - -static const BubbleMovement _bubble_float_se[] = { - MK(0, 0, 1, 0), - MK(0, 1, 1, 1), - MK(0, 0, 1, 0), - MK(0, 1, 1, 2), - ME(1) -}; - -static const BubbleMovement _bubble_float_nw[] = { - MK(0, 0, 1, 0), - MK(0, -1, 1, 1), - MK(0, 0, 1, 0), - MK(0, -1, 1, 2), - ME(1) -}; - -static const BubbleMovement _bubble_burst[] = { - MK(0, 0, 1, 2), - MK(0, 0, 1, 7), - MK(0, 0, 1, 8), - MK(0, 0, 1, 9), - ME(0) -}; - -static const BubbleMovement _bubble_absorb[] = { - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(0, 0, 1, 0), - MK(0, 0, 1, 2), - MK(0, 0, 1, 0), - MK(0, 0, 1, 1), - MK(2, 1, 3, 0), - MK(1, 1, 3, 1), - MK(2, 1, 3, 0), - MK(1, 1, 3, 2), - MK(2, 1, 3, 0), - MK(1, 1, 3, 1), - MK(2, 1, 3, 0), - MK(1, 0, 1, 2), - MK(0, 0, 1, 0), - MK(1, 0, 1, 1), - MK(0, 0, 1, 0), - MK(1, 0, 1, 2), - MK(0, 0, 1, 0), - MK(1, 0, 1, 1), - MK(0, 0, 1, 0), - MK(1, 0, 1, 2), - ME(2), - MK(0, 0, 0, 0xA), - MK(0, 0, 0, 0xB), - MK(0, 0, 0, 0xC), - MK(0, 0, 0, 0xD), - MK(0, 0, 0, 0xE), - ME(0) -}; -#undef ME -#undef MK - -static const BubbleMovement * const _bubble_movement[] = { - _bubble_float_sw, - _bubble_float_ne, - _bubble_float_se, - _bubble_float_nw, - _bubble_burst, - _bubble_absorb, -}; - -static void BubbleTick(Vehicle *v) -{ - /* - * Warning: those effects can NOT use Random(), and have to use - * InteractiveRandom(), because somehow someone forgot to save - * spritenum to the savegame, and so it will cause desyncs in - * multiplayer!! (that is: in ToyLand) - */ - uint et; - - v->progress++; - if ((v->progress & 3) != 0) return; - - BeginVehicleMove(v); - - if (v->spritenum == 0) { - v->cur_image++; - if (v->cur_image < SPR_BUBBLE_GENERATE_3) { - VehiclePositionChanged(v); - EndVehicleMove(v); - return; - } - if (v->u.special.animation_substate != 0) { - v->spritenum = GB(InteractiveRandom(), 0, 2) + 1; - } else { - v->spritenum = 6; - } - et = 0; - } else { - et = v->engine_type + 1; - } - - const BubbleMovement *b = &_bubble_movement[v->spritenum - 1][et]; - - if (b->y == 4 && b->x == 0) { - EndVehicleMove(v); - delete v; - return; - } - - if (b->y == 4 && b->x == 1) { - if (v->z_pos > 180 || Chance16I(1, 96, InteractiveRandom())) { - v->spritenum = 5; - SndPlayVehicleFx(SND_2F_POP, v); - } - et = 0; - } - - if (b->y == 4 && b->x == 2) { - TileIndex tile; - - et++; - SndPlayVehicleFx(SND_31_EXTRACT, v); - - tile = TileVirtXY(v->x_pos, v->y_pos); - if (IsTileType(tile, MP_INDUSTRY) && GetIndustryGfx(tile) == GFX_BUBBLE_CATCHER) AddAnimatedTile(tile); - } - - v->engine_type = et; - b = &_bubble_movement[v->spritenum - 1][et]; - - v->x_pos += b->x; - v->y_pos += b->y; - v->z_pos += b->z; - v->cur_image = SPR_BUBBLE_0 + b->image; - - VehiclePositionChanged(v); - EndVehicleMove(v); -} - - -typedef void EffectInitProc(Vehicle *v); -typedef void EffectTickProc(Vehicle *v); - -static EffectInitProc * const _effect_init_procs[] = { - ChimneySmokeInit, - SteamSmokeInit, - DieselSmokeInit, - ElectricSparkInit, - SmokeInit, - ExplosionLargeInit, - BreakdownSmokeInit, - ExplosionSmallInit, - BulldozerInit, - BubbleInit, -}; - -static EffectTickProc * const _effect_tick_procs[] = { - ChimneySmokeTick, - SteamSmokeTick, - DieselSmokeTick, - ElectricSparkTick, - SmokeTick, - ExplosionLargeTick, - BreakdownSmokeTick, - ExplosionSmallTick, - BulldozerTick, - BubbleTick, -}; - - -Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type) -{ - Vehicle *v = new SpecialVehicle(); - if (v != NULL) { - v->subtype = type; - v->x_pos = x; - v->y_pos = y; - v->z_pos = z; - v->tile = 0; - v->UpdateDeltaXY(INVALID_DIR); - v->vehstatus = VS_UNCLICKABLE; - - _effect_init_procs[type](v); - - VehiclePositionChanged(v); - BeginVehicleMove(v); - EndVehicleMove(v); - } - return v; -} - -Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type) -{ - int safe_x = Clamp(x, 0, MapMaxX() * TILE_SIZE); - int safe_y = Clamp(y, 0, MapMaxY() * TILE_SIZE); - return CreateEffectVehicle(x, y, GetSlopeZ(safe_x, safe_y) + z, type); -} - -Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type) -{ - return CreateEffectVehicle(v->x_pos + x, v->y_pos + y, v->z_pos + z, type); -} - -void SpecialVehicle::Tick() -{ - _effect_tick_procs[this->subtype](this); -} - Vehicle *CheckClickOnVehicle(const ViewPort *vp, int x, int y) { Vehicle *found = NULL, *v; @@ -1695,16 +1120,11 @@ for (uint i = 0; i < engine_count; i++) { Vehicle *v = vl[i]; - bool stopped = !(v->vehstatus & VS_STOPPED); /* Ensure that the vehicle completely in the depot */ if (!v->IsInDepot()) continue; - if (stopped) { - v->vehstatus |= VS_STOPPED; // Stop the vehicle - v->leave_depot_instantly = true; - } - CommandCost ret = MaybeReplaceVehicle(v, !(flags & DC_EXEC), false); + CommandCost ret = MaybeReplaceVehicle(v, flags, false); if (CmdSucceeded(ret)) { cost.AddCost(ret); @@ -2480,7 +1900,7 @@ /* Vehicle is turning around, get the direction from vehicle's direction */ return DiagdirToDiagTrackdir(DirToDiagDir(v->direction)); - /* case VEH_AIRCRAFT: case VEH_SPECIAL: case VEH_DISASTER: */ + /* case VEH_AIRCRAFT: case VEH_EFFECT: case VEH_DISASTER: */ default: return INVALID_TRACKDIR; } } @@ -2937,7 +2357,7 @@ }; static const SaveLoad _special_desc[] = { - SLE_WRITEBYTE(Vehicle, type, VEH_SPECIAL), + SLE_WRITEBYTE(Vehicle, type, VEH_EFFECT), SLE_VAR(Vehicle, subtype, SLE_UINT8), @@ -2955,8 +2375,8 @@ SLE_VAR(Vehicle, progress, SLE_UINT8), SLE_VAR(Vehicle, vehstatus, SLE_UINT8), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_state), SLE_UINT16), - SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleSpecial, animation_substate), SLE_UINT8), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_state), SLE_UINT16), + SLE_VARX(cpp_offsetof(Vehicle, u) + cpp_offsetof(VehicleEffect, animation_substate), SLE_UINT8), /* reserve extra space in savegame here. (currently 16 bytes) */ SLE_CONDNULL(16, 2, SL_MAX_VERSION), @@ -3044,7 +2464,7 @@ case VEH_ROAD: v = new (index) RoadVehicle(); break; case VEH_SHIP: v = new (index) Ship(); break; case VEH_AIRCRAFT: v = new (index) Aircraft(); break; - case VEH_SPECIAL: v = new (index) SpecialVehicle(); break; + case VEH_EFFECT: v = new (index) EffectVehicle(); break; case VEH_DISASTER: v = new (index) DisasterVehicle(); break; case VEH_INVALID: v = new (index) InvalidVehicle(); break; default: NOT_REACHED(); @@ -3264,15 +2684,6 @@ } } -void SpecialVehicle::UpdateDeltaXY(Direction direction) -{ - this->x_offs = 0; - this->y_offs = 0; - this->x_extent = 1; - this->y_extent = 1; - this->z_extent = 1; -} - void StopAllVehicles() { Vehicle *v; diff -r 7856e972f8aa -r 7798ae816af8 src/vehicle_base.h --- a/src/vehicle_base.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/vehicle_base.h Mon Apr 21 21:15:50 2008 +0000 @@ -78,20 +78,27 @@ }; struct VehicleRail { + /* Link between the two ends of a multiheaded engine */ + Vehicle *other_multiheaded_part; + + /* Cached wagon override spritegroup */ + const struct SpriteGroup *cached_override; + uint16 last_speed; // NOSAVE: only used in UI uint16 crash_anim_pos; /* cached values, recalculated on load and each time a vehicle is added to/removed from the consist. */ - uint16 cached_max_speed; // max speed of the consist. (minimum of the max speed of all vehicles in the consist) - uint32 cached_power; // total power of the consist. - bool cached_tilt; // train can tilt; feature provides a bonus in curves - uint8 cached_veh_length; // length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback + uint32 cached_power; ///< total power of the consist. + uint16 cached_max_speed; ///< max speed of the consist. (minimum of the max speed of all vehicles in the consist) uint16 cached_total_length; ///< Length of the whole train, valid only for first engine. + uint8 cached_veh_length; ///< length of this vehicle in units of 1/8 of normal length, cached because this can be set by a callback + bool cached_tilt; ///< train can tilt; feature provides a bonus in curves /* cached values, recalculated when the cargo on a train changes (in addition to the conditions above) */ - uint32 cached_weight; // total weight of the consist. - uint32 cached_veh_weight; // weight of the vehicle. - uint32 cached_max_te; // max tractive effort of consist + uint32 cached_weight; ///< total weight of the consist. + uint32 cached_veh_weight; ///< weight of the vehicle. + uint32 cached_max_te; ///< max tractive effort of consist + /** * Position/type of visual effect. * bit 0 - 3 = position of effect relative to vehicle. (0 = front, 8 = centre, 15 = rear) @@ -106,18 +113,11 @@ * 0xffff == not in train */ EngineID first_engine; + byte flags; TrackBitsByte track; byte force_proceed; RailTypeByte railtype; RailTypes compatible_railtypes; - - byte flags; - - /* Link between the two ends of a multiheaded engine */ - Vehicle *other_multiheaded_part; - - /* Cached wagon override spritegroup */ - const struct SpriteGroup *cached_override; }; enum VehicleRailFlags { @@ -169,7 +169,7 @@ RoadTypes compatible_roadtypes; }; -struct VehicleSpecial { +struct VehicleEffect { uint16 animation_state; byte animation_substate; }; @@ -193,32 +193,64 @@ extern bool LoadOldVehicle(LoadgameState *ls, int num); struct Vehicle : PoolItem, BaseVehicle { - byte subtype; // subtype (Filled with values from EffectVehicles/TrainSubTypes/AircraftSubTypes) - private: - Vehicle *next; // pointer to the next vehicle in the chain - Vehicle *previous; // NOSAVE: pointer to the previous vehicle in the chain - Vehicle *first; // NOSAVE: pointer to the first vehicle in the chain + Vehicle *next; ///< pointer to the next vehicle in the chain + Vehicle *previous; ///< NOSAVE: pointer to the previous vehicle in the chain + Vehicle *first; ///< NOSAVE: pointer to the first vehicle in the chain public: - friend const SaveLoad *GetVehicleDescription(VehicleType vt); // So we can use private/protected variables in the saveload code - friend void AfterLoadVehicles(bool clear_te_id); // So we can set the previous and first pointers while loading - friend bool LoadOldVehicle(LoadgameState *ls, int num); // So we can set the proper next pointer while loading + friend const SaveLoad *GetVehicleDescription(VehicleType vt); ///< So we can use private/protected variables in the saveload code + friend void AfterLoadVehicles(bool clear_te_id); ///< So we can set the previous and first pointers while loading + friend bool LoadOldVehicle(LoadgameState *ls, int num); ///< So we can set the proper next pointer while loading - Vehicle *depot_list; // NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace + Vehicle *depot_list; ///< NOSAVE: linked list to tell what vehicles entered a depot during the last tick. Used by autoreplace char *name; ///< Name of vehicle - UnitID unitnumber; // unit number, for display purposes only - PlayerByte owner; // which player owns the vehicle? + TileIndex tile; ///< Current tile index + TileIndex dest_tile; ///< Heading for this tile - TileIndex tile; // Current tile index - TileIndex dest_tile; // Heading for this tile + Vehicle *next_shared; ///< If not NULL, this points to the next vehicle that shared the order + Vehicle *prev_shared; ///< If not NULL, this points to the prev vehicle that shared the order + + Money profit_this_year; ///< Profit this year << 8, low 8 bits are fract + Money profit_last_year; ///< Profit last year << 8, low 8 bits are fract + Money value; + + /* Used for timetabling. */ + uint32 current_order_time; ///< How many ticks have passed since this order started. + int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is. + + /* Boundaries for the current position in the world and a next hash link. + * NOSAVE: All of those can be updated with VehiclePositionChanged() */ + int32 left_coord; + int32 top_coord; + int32 right_coord; + int32 bottom_coord; + Vehicle *next_hash; + Vehicle *next_new_hash; + Vehicle **old_new_hash; + + SpriteID colormap; // NOSAVE: cached color mapping + + /* Related to age and service time */ + Year build_year; + Date age; // Age in days + Date max_age; // Maximum age + Date date_of_last_service; + Date service_interval; + uint16 reliability; + uint16 reliability_spd_dec; + byte breakdown_ctr; + byte breakdown_delay; + byte breakdowns_since_last_service; + byte breakdown_chance; int32 x_pos; // coordinates int32 y_pos; byte z_pos; DirectionByte direction; // facing + PlayerByte owner; // which player owns the vehicle? byte spritenum; // currently displayed sprite index // 0xfd == custom sprite, 0xfe == custom second head sprite // 0xff == reserved for another custom sprite @@ -231,89 +263,53 @@ EngineID engine_type; TextEffectID fill_percent_te_id; // a text-effect id to a loading indicator object + UnitID unitnumber; // unit number, for display purposes only + + uint16 max_speed; ///< maximum speed + uint16 cur_speed; ///< current speed + byte subspeed; ///< fractional speed + byte acceleration; ///< used by train & aircraft + uint32 motion_counter; + byte progress; /* for randomized variational spritegroups * bitmask used to resolve them; parts of it get reseeded when triggers * of corresponding spritegroups get matched */ byte random_bits; - byte waiting_triggers; // triggers to be yet matched + byte waiting_triggers; ///< triggers to be yet matched - uint16 max_speed; // maximum speed - uint16 cur_speed; // current speed - byte subspeed; // fractional speed - byte acceleration; // used by train & aircraft - byte progress; - uint32 motion_counter; - - byte vehstatus; // Status StationID last_station_visited; - CargoID cargo_type; // type of cargo this vehicle is carrying - uint16 cargo_cap; // total capacity + CargoID cargo_type; ///< type of cargo this vehicle is carrying byte cargo_subtype; ///< Used for livery refits (NewGRF variations) + uint16 cargo_cap; ///< total capacity CargoList cargo; ///< The cargo this vehicle is carrying - byte day_counter; ///< Increased by one for each day byte tick_counter; ///< Increased by one for each tick byte running_ticks; ///< Number of ticks this vehicle was not stopped this day - /* Begin Order-stuff */ - Order current_order; ///< The current order (+ status, like: loading) + byte vehstatus; ///< Status + Order current_order; ///< The current order (+ status, like: loading) + VehicleOrderID num_orders; ///< How many orders there are in the list VehicleOrderID cur_order_index; ///< The index to the current order - Order *orders; ///< Pointer to the first order for this vehicle - VehicleOrderID num_orders; ///< How many orders there are in the list - - Vehicle *next_shared; ///< If not NULL, this points to the next vehicle that shared the order - Vehicle *prev_shared; ///< If not NULL, this points to the prev vehicle that shared the order - /* End Order-stuff */ - - /* Boundaries for the current position in the world and a next hash link. - * NOSAVE: All of those can be updated with VehiclePositionChanged() */ - int32 left_coord; - int32 top_coord; - int32 right_coord; - int32 bottom_coord; - Vehicle *next_hash; - Vehicle *next_new_hash; - Vehicle **old_new_hash; + Order *orders; ///< Pointer to the first order for this vehicle - /* Related to age and service time */ - Date age; // Age in days - Date max_age; // Maximum age - Date date_of_last_service; - Date service_interval; - uint16 reliability; - uint16 reliability_spd_dec; - byte breakdown_ctr; - byte breakdown_delay; - byte breakdowns_since_last_service; - byte breakdown_chance; - Year build_year; + bool leave_depot_instantly; ///< NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace - bool leave_depot_instantly; // NOSAVE: stores if the vehicle needs to leave the depot it just entered. Used by autoreplace - + byte vehicle_flags; ///< Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) uint16 load_unload_time_rem; - byte vehicle_flags; // Used for gradual loading and other miscellaneous things (@see VehicleFlags enum) - Money profit_this_year; ///< Profit this year << 8, low 8 bits are fract - Money profit_last_year; ///< Profit last year << 8, low 8 bits are fract - Money value; + GroupID group_id; ///< Index of group Pool array - GroupID group_id; ///< Index of group Pool array - - /* Used for timetabling. */ - uint32 current_order_time; ///< How many ticks have passed since this order started. - int32 lateness_counter; ///< How many ticks late (or early if negative) this vehicle is. - - SpriteID colormap; // NOSAVE: cached color mapping + byte subtype; ///< subtype (Filled with values from EffectVehicles/TrainSubTypes/AircraftSubTypes) union { VehicleRail rail; VehicleAir air; VehicleRoad road; - VehicleSpecial special; + VehicleEffect effect; VehicleDisaster disaster; VehicleShip ship; } u; @@ -394,7 +390,7 @@ * @param direction the direction the vehicle is facing * @return the sprite for the given vehicle in the given direction */ - virtual int GetImage(Direction direction) const { return 0; } + virtual SpriteID GetImage(Direction direction) const { return 0; } /** * Gets the speed in mph that can be sent into SetDParam for string processing. @@ -539,33 +535,6 @@ * v = new (v) Train(); * * As side-effect the vehicle type is set correctly. - * - * A special vehicle is one of the following: - * - smoke - * - electric sparks for trains - * - explosions - * - bulldozer (road works) - * - bubbles (industry) - */ -struct SpecialVehicle : public Vehicle { - /** Initializes the Vehicle to a special vehicle */ - SpecialVehicle() { this->type = VEH_SPECIAL; } - - /** We want to 'destruct' the right class. */ - virtual ~SpecialVehicle() {} - - const char *GetTypeString() const { return "special vehicle"; } - void UpdateDeltaXY(Direction direction); - void Tick(); -}; - -/** - * This class 'wraps' Vehicle; you do not actually instantiate this class. - * You create a Vehicle using AllocateVehicle, so it is added to the pool - * and you reinitialize that to a Train using: - * v = new (v) Train(); - * - * As side-effect the vehicle type is set correctly. */ struct DisasterVehicle : public Vehicle { /** Initializes the Vehicle to a disaster vehicle */ diff -r 7856e972f8aa -r 7798ae816af8 src/vehicle_func.h --- a/src/vehicle_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/vehicle_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -1,6 +1,6 @@ /* $Id$ */ -/** @vehicle.h Functions related to vehicles. */ +/** @file vehicle.h Functions related to vehicles. */ #ifndef VEHICLE_FUNC_H #define VEHICLE_FUNC_H @@ -72,7 +72,7 @@ CommandCost SendAllVehiclesToDepot(VehicleType type, uint32 flags, bool service, PlayerID owner, uint16 vlw_flag, uint32 id); void VehicleEnterDepot(Vehicle *v); -CommandCost MaybeReplaceVehicle(Vehicle *v, bool check, bool display_costs); +CommandCost MaybeReplaceVehicle(Vehicle *v, uint32 flags, bool display_costs); bool CanBuildVehicleInfrastructure(VehicleType type); void CcCloneVehicle(bool success, TileIndex tile, uint32 p1, uint32 p2); @@ -172,13 +172,9 @@ bool EnsureNoVehicleOnGround(TileIndex tile); void StopAllVehicles(); -Vehicle *CreateEffectVehicle(int x, int y, int z, EffectVehicle type); -Vehicle *CreateEffectVehicleAbove(int x, int y, int z, EffectVehicle type); -Vehicle *CreateEffectVehicleRel(const Vehicle *v, int x, int y, int z, EffectVehicle type); - extern VehicleID _vehicle_id_ctr_day; extern Vehicle *_place_clicked_vehicle; extern VehicleID _new_vehicle_id; extern uint16 _returned_refit_capacity; -#endif /* VEHICLE_H */ +#endif /* VEHICLE_FUNC_H */ diff -r 7856e972f8aa -r 7798ae816af8 src/vehicle_gui.cpp --- a/src/vehicle_gui.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/vehicle_gui.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -35,7 +35,6 @@ #include "settings_type.h" #include "widgets/dropdown_func.h" #include "order_func.h" -#include "depot_base.h" #include "table/sprites.h" #include "table/strings.h" @@ -103,7 +102,11 @@ INVALID_STRING_ID }; -void RebuildVehicleLists() +/** + * Set sort list flag for all vehicle list windows + * @param sl_flag Sort list flag to set + */ +static void SetVehicleListsFlag(SortListFlags sl_flag) { Window* const *wz; @@ -115,7 +118,7 @@ case WC_ROADVEH_LIST: case WC_SHIPS_LIST: case WC_AIRCRAFT_LIST: - WP(w, vehiclelist_d).l.flags |= VL_REBUILD; + WP(w, vehiclelist_d).l.flags |= sl_flag; SetWindowDirty(w); break; @@ -124,25 +127,20 @@ } } +/** + * Rebuild all vehicle list windows + */ +void RebuildVehicleLists() +{ + SetVehicleListsFlag(VL_REBUILD); +} + +/** + * Resort all vehicle list windows + */ void ResortVehicleLists() { - Window* const *wz; - - FOR_ALL_WINDOWS(wz) { - Window *w = *wz; - - switch (w->window_class) { - case WC_TRAINS_LIST: - case WC_ROADVEH_LIST: - case WC_SHIPS_LIST: - case WC_AIRCRAFT_LIST: - WP(w, vehiclelist_d).l.flags |= VL_RESORT; - SetWindowDirty(w); - break; - - default: break; - } - } + SetVehicleListsFlag(VL_RESORT); } void BuildVehicleList(vehiclelist_d *vl, PlayerID owner, uint16 index, uint16 window_type) @@ -1753,7 +1751,7 @@ if (w != NULL) { w->caption_color = v->owner; - AssignWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH, + InitializeWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH, (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT, w->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]); } diff -r 7856e972f8aa -r 7798ae816af8 src/vehicle_type.h --- a/src/vehicle_type.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/vehicle_type.h Mon Apr 21 21:15:50 2008 +0000 @@ -14,7 +14,7 @@ VEH_ROAD, VEH_SHIP, VEH_AIRCRAFT, - VEH_SPECIAL, + VEH_EFFECT, VEH_DISASTER, VEH_END, VEH_INVALID = 0xFF, @@ -38,20 +38,6 @@ static const VehicleID INVALID_VEHICLE = 0xFFFF; -/* Effect vehicle types */ -enum EffectVehicle { - EV_CHIMNEY_SMOKE = 0, - EV_STEAM_SMOKE = 1, - EV_DIESEL_SMOKE = 2, - EV_ELECTRIC_SPARK = 3, - EV_SMOKE = 4, - EV_EXPLOSION_LARGE = 5, - EV_BREAKDOWN_SMOKE = 6, - EV_EXPLOSION_SMALL = 7, - EV_BULLDOZER = 8, - EV_BUBBLE = 9 -}; - /** Pathfinding option states */ enum { VPF_OPF = 0, ///< The Original PathFinder diff -r 7856e972f8aa -r 7798ae816af8 src/video/dedicated_v.cpp --- a/src/video/dedicated_v.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/video/dedicated_v.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -140,6 +140,7 @@ _screen.width = _screen.pitch = _cur_resolution[0]; _screen.height = _cur_resolution[1]; + ScreenSizeChanged(); SetDebugString("net=6"); diff -r 7856e972f8aa -r 7798ae816af8 src/viewport.cpp --- a/src/viewport.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/viewport.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -158,7 +158,19 @@ w->viewport = NULL; } -void AssignWindowViewport(Window *w, int x, int y, +/** + * Initialize viewport of the window for use. + * @param w Window to use/display the viewport in + * @param x Offset of left edge of viewport with respect to left edge window \a w + * @param y Offset of top edge of viewport with respect to top edge window \a w + * @param width Width of the viewport + * @param height Height of the viewport + * @param follow_flags Flags controlling the viewport. + * - If bit 31 is set, the lower 16 bits are the vehicle that the viewport should follow. + * - If bit 31 is clear, it is a tile position. + * @param zoom Zoomlevel to display + */ +void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom) { assert(w->viewport == NULL); @@ -324,7 +336,14 @@ } } - +/** + * Is a xy position inside the viewport of the window? + * @param w Window to examine its viewport + * @param x X coordinate of the xy position + * @param y Y coordinate of the xy position + * @return Pointer to the viewport if the xy position is in the viewport of the window, + * otherwise \c NULL is returned. + */ ViewPort *IsPtInWindowViewport(const Window *w, int x, int y) { ViewPort *vp = w->viewport; @@ -1591,11 +1610,12 @@ } /** - * Marks a viewport as dirty for repaint. - * - * @param vp The viewport to mark as dirty - * @todo documents the missing parameters @c left, @c top, @c right and @c bottom - * @todo detailed description missing + * Marks a viewport as dirty for repaint if it displays (a part of) the area the needs to be repainted. + * @param vp The viewport to mark as dirty + * @param left Left edge of area to repaint + * @param top Top edge of area to repaint + * @param right Right edge of area to repaint + * @param bottom Bottom edge of area to repaint * @ingroup dirty */ static void MarkViewportDirty(const ViewPort *vp, int left, int top, int right, int bottom) @@ -1622,6 +1642,14 @@ ); } +/** + * Mark all viewports that display an area as dirty (in need of repaint). + * @param left Left edge of area to repaint + * @param top Top edge of area to repaint + * @param right Right edge of area to repaint + * @param bottom Bottom edge of area to repaint + * @ingroup dirty + */ void MarkAllViewportsDirty(int left, int top, int right, int bottom) { Window **wz; diff -r 7856e972f8aa -r 7798ae816af8 src/viewport_func.h --- a/src/viewport_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/viewport_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -13,7 +13,7 @@ void SetSelectionRed(bool); void DeleteWindowViewport(Window *w); -void AssignWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom); +void InitializeWindowViewport(Window *w, int x, int y, int width, int height, uint32 follow_flags, ZoomLevel zoom); ViewPort *IsPtInWindowViewport(const Window *w, int x, int y); Point GetTileBelowCursor(); void UpdateViewportPosition(Window *w); diff -r 7856e972f8aa -r 7798ae816af8 src/water_cmd.cpp --- a/src/water_cmd.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/water_cmd.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -39,6 +39,7 @@ #include "station_base.h" #include "airport.h" #include "newgrf_cargo.h" +#include "effectvehicle_func.h" #include "table/sprites.h" #include "table/strings.h" diff -r 7856e972f8aa -r 7798ae816af8 src/window.cpp --- a/src/window.cpp Mon Apr 21 20:52:54 2008 +0000 +++ b/src/window.cpp Mon Apr 21 21:15:50 2008 +0000 @@ -303,6 +303,7 @@ } } + /* Setup blitter, and dispatch a repaint event to window *wz */ DrawPixelInfo *dp = _cur_dpi; dp->width = right - left; dp->height = bottom - top; @@ -334,6 +335,7 @@ bottom > w->top && left < w->left + w->width && top < w->top + w->height) { + /* Window w intersects with the rectangle => needs repaint */ DrawOverlappedWindow(wz, left, top, right, bottom); } } @@ -398,7 +400,8 @@ } /** - * Remove window and all its child windows from the window stack + * Remove window and all its child windows from the window stack. + * @param w Window to delete */ void DeleteWindow(Window *w) { @@ -622,11 +625,11 @@ { Window* const *wz; - for (wz = _z_windows;; wz++) { + FOR_ALL_WINDOWS(wz) { Window *w = *wz; - assert(wz < _last_z_window); if (w->window_class != WC_MAIN_WINDOW && !IsVitalWindow(w)) return w; } + NOT_REACHED(); } bool IsWindowOfPrototype(const Window *w, const Widget *widget) @@ -1018,9 +1021,7 @@ * @return a pointer to the found window if any, NULL otherwise */ Window *FindWindowFromPt(int x, int y) { - Window* const *wz; - - for (wz = _last_z_window; wz != _z_windows;) { + for (Window * const *wz = _last_z_window; wz != _z_windows;) { Window *w = *--wz; if (IsInsideBS(x, w->left, w->width) && IsInsideBS(y, w->top, w->height)) { return w; @@ -1038,6 +1039,7 @@ IConsoleClose(); _last_z_window = _z_windows; + _mouseover_last_w = NULL; _no_scroll = 0; } @@ -1604,8 +1606,7 @@ static bool MaybeBringWindowToFront(const Window *w) { bool bring_to_front = false; - Window* const *wz; - Window* const *uz; + Window * const *wz; if (w->window_class == WC_MAIN_WINDOW || IsVitalWindow(w) || @@ -1615,7 +1616,7 @@ } wz = FindWindowZPosition(w); - for (uz = wz; ++uz != _last_z_window;) { + for (Window * const *uz = wz; ++uz != _last_z_window;) { Window *u = *uz; /* A modal child will prevent the activation of the parent window */ @@ -1789,9 +1790,6 @@ } } -extern void UpdateTileSelection(); -extern bool VpHandlePlaceSizingDrag(); - /** * Local counter that is incremented each time an mouse input event is detected. * The counter is used to stop auto-scrolling. @@ -1852,6 +1850,9 @@ TIME_BETWEEN_DOUBLE_CLICK = 500, ///< Time between 2 left clicks before it becoming a double click, in ms }; +extern void UpdateTileSelection(); +extern bool VpHandlePlaceSizingDrag(); + void MouseLoop(MouseClick click, int mousewheel) { int x,y; @@ -2064,8 +2065,9 @@ } /** - * Mark window data as invalid (in need of re-computing) - * @param w Window with invalid data + * Mark window as dirty (in need of repainting) + * @param cls Window class + * @param number Window number in that class */ void InvalidateWindow(WindowClass cls, WindowNumber number) { @@ -2077,7 +2079,7 @@ } } -/* +/** * Mark a particular widget in a particular window as dirty (in need of repainting) * @param cls Window class * @param number Window number in that class @@ -2095,7 +2097,7 @@ } } -/* +/** * Mark all windows of a particular class as dirty (in need of repainting) * @param cls Window class */ @@ -2119,7 +2121,7 @@ } /** - * Mark window data the window of a given class and specific window number as invalid (in need of re-computing) + * Mark window data of the window of a given class and specific window number as invalid (in need of re-computing) * @param cls Window class * @param number Window number within the class */ @@ -2151,13 +2153,17 @@ */ void CallWindowTickEvent() { - Window* const *wz; - - for (wz = _last_z_window; wz != _z_windows;) { + for (Window * const *wz = _last_z_window; wz != _z_windows;) { CallWindowEventNP(*--wz, WE_TICK); } } +/** + * Try to delete a non-vital window. + * Non-vital windows are windows other than the game selection, main toolbar, + * status bar, toolbar menu, and tooltip windows. Stickied windows are also + * considered vital. + */ void DeleteNonVitalWindows() { Window* const *wz; diff -r 7856e972f8aa -r 7798ae816af8 src/window_func.h --- a/src/window_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/window_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -32,7 +32,6 @@ void DeleteAllNonVitalWindows(); void HideVitalWindows(); void ShowVitalWindows(); -Window **FindWindowZPosition(const Window *w); void InvalidateWindow(WindowClass cls, WindowNumber number); void InvalidateWindowWidget(WindowClass cls, WindowNumber number, byte widget_index); diff -r 7856e972f8aa -r 7798ae816af8 src/window_gui.h --- a/src/window_gui.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/window_gui.h Mon Apr 21 21:15:50 2008 +0000 @@ -549,15 +549,9 @@ bool IsWindowOfPrototype(const Window *w, const Widget *widget); void AssignWidgetToWindow(Window *w, const Widget *widget); -Window *AllocateWindow( - int x, - int y, - int width, - int height, - WindowProc *proc, - WindowClass cls, - const Widget *widget, - void *data = NULL); +Window *AllocateWindow(int x, int y, int width, int height, + WindowProc *proc, WindowClass cls, const Widget *widget, + void *data = NULL); Window *AllocateWindowDesc(const WindowDesc *desc, void *data = NULL); Window *AllocateWindowDescFront(const WindowDesc *desc, int window_number, void *data = NULL); @@ -594,12 +588,6 @@ void DrawSortButtonState(const Window *w, int widget, SortButtonState state); -Window *GetCallbackWnd(); -void DeleteNonVitalWindows(); -void DeleteAllNonVitalWindows(); -void HideVitalWindows(); -void ShowVitalWindows(); -Window **FindWindowZPosition(const Window *w); /* window.cpp */ extern Window *_z_windows[]; @@ -624,6 +612,13 @@ WSM_PRESIZE = 3, }; +Window *GetCallbackWnd(); +void DeleteNonVitalWindows(); +void DeleteAllNonVitalWindows(); +void HideVitalWindows(); +void ShowVitalWindows(); +Window **FindWindowZPosition(const Window *w); + void ScrollbarClickHandler(Window *w, const Widget *wi, int x, int y); void ResizeButtons(Window *w, byte left, byte right); diff -r 7856e972f8aa -r 7798ae816af8 src/zoom_func.h --- a/src/zoom_func.h Mon Apr 21 20:52:54 2008 +0000 +++ b/src/zoom_func.h Mon Apr 21 21:15:50 2008 +0000 @@ -1,6 +1,6 @@ /* $Id$ */ -/** @file zoom_func.hpp */ +/** @file zoom_func.h */ #ifndef ZOOM_FUNC_H #define ZOOM_FUNC_H