--- 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
--- 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 @@
>
</File>
<File
+ RelativePath=".\..\src\animated_tile.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\articulated_vehicles.cpp"
>
</File>
@@ -544,6 +548,10 @@
>
</File>
<File
+ RelativePath=".\..\src\effectvehicle.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\elrail.cpp"
>
</File>
@@ -816,6 +824,10 @@
>
</File>
<File
+ RelativePath=".\..\src\animated_tile_func.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\articulated_vehicles.h"
>
</File>
@@ -964,6 +976,14 @@
>
</File>
<File
+ RelativePath=".\..\src\effectvehicle_func.h"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\effectvehicle_base.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\core\endian_func.hpp"
>
</File>
--- 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 @@
>
</File>
<File
+ RelativePath=".\..\src\animated_tile.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\articulated_vehicles.cpp"
>
</File>
@@ -541,6 +545,10 @@
>
</File>
<File
+ RelativePath=".\..\src\effectvehicle.cpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\elrail.cpp"
>
</File>
@@ -813,6 +821,10 @@
>
</File>
<File
+ RelativePath=".\..\src\animated_tile_func.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\articulated_vehicles.h"
>
</File>
@@ -961,6 +973,14 @@
>
</File>
<File
+ RelativePath=".\..\src\effectvehicle_func.h"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\effectvehicle_base.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\core\endian_func.hpp"
>
</File>
--- 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
--- 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; }
--- 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--;
}
}
--- /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<TileIndex>(_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<TileIndex>(_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<TileIndex>(_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},
+};
--- /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 */
--- 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. */
--- 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;
}
--- 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<CargoPacket, CargoPacketID, &_CargoPacket_pool> {
- 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?
/**
--- 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"
--- 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;
--- /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;
+}
--- /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 */
--- /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 */
--- 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
--- 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();
--- 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)
--- 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);
}
}
--- 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"
--- 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}
--- 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) {
--- 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},
};
--- 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:
--- 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
};
/**
--- 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;
}
--- 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;
}
--- 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);
--- 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;
}
--- 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;
}
--- 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 */
--- 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<uint32, 0x110> _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;
}
}
--- 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;
+ }
+}
--- 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 */
--- 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
--- 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;
--- 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
--- 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<byte>(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;
}
--- 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;
--- 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;
--- 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;
--- 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),
--- 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"
--- 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);
--- 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"
--- 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); }
--- 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;
--- 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();
}
--- 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 */
--- 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);
--- 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; }
--- 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);
}
--- 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;
--- 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)
--- 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
--- 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);
}
}
--- 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);
}
/**
--- 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<char>(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},
+};
--- 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 */
--- 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<TileIndex>(_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<TileIndex>(_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<TileIndex>(_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},
-};
--- 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);
--- 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;
}
}
--- 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);
}
}
--- 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)
--- 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;
--- 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) {
--- 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;
--- 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<Vehicle, VehicleID, &_Vehicle_pool>, 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 */
--- 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 */
--- 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]);
}
--- 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
--- 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");
--- 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;
--- 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);
--- 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"
--- 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;
--- 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);
--- 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);
--- 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