Changeset - r7413:3ccdde9800e0
[Not reviewed]
master
0 15 0
rubidium - 17 years ago 2007-08-05 21:20:55
rubidium@openttd.org
(svn r10799) -Fix: only calling QuickFree and not the destructor on pool cleanups might cause memory leaks due to the way C++ works.
15 files changed with 48 insertions and 67 deletions:
0 comments (0 inline, 0 general)
src/depot.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file depot.cpp */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "vehicle.h"
 
#include "depot.h"
 
#include "functions.h"
 
#include "landscape.h"
 
#include "tile.h"
 
#include "map.h"
 
#include "table/strings.h"
 
#include "saveload.h"
 
#include "order.h"
 

	
 
DEFINE_OLD_POOL_GENERIC(Depot, Depot)
 

	
 
/**
 
 * Gets a depot from a tile
 
 *
 
 * @return Returns the depot if the tile had a depot, else it returns NULL
 
 */
 
Depot *GetDepotByTile(TileIndex tile)
 
{
 
	Depot *depot;
 

	
 
	FOR_ALL_DEPOTS(depot) {
 
		if (depot->xy == tile) return depot;
 
	}
 

	
 
	return NULL;
 
}
 

	
 
/**
 
 * Clean up a depot
 
 */
 
Depot::~Depot()
 
{
 
	if (CleaningPool()) return;
 

	
 
	/* Clear the depot from all order-lists */
 
	RemoveOrderFromAllVehicles(OT_GOTO_DEPOT, this->index);
 

	
 
	/* Delete the depot-window */
 
	DeleteWindowById(WC_VEHICLE_DEPOT, this->xy);
 
	this->xy = 0;
 
}
 

	
 
void InitializeDepots()
 
{
 
	_Depot_pool.CleanPool();
 
	_Depot_pool.AddBlockToPool();
 
}
 

	
 

	
 
static const SaveLoad _depot_desc[] = {
 
	SLE_CONDVAR(Depot, xy,         SLE_FILE_U16 | SLE_VAR_U32, 0, 5),
 
	SLE_CONDVAR(Depot, xy,         SLE_UINT32,                 6, SL_MAX_VERSION),
 
	    SLE_VAR(Depot, town_index, SLE_UINT16),
 
	SLE_END()
 
};
 

	
 
static void Save_DEPT()
 
{
 
	Depot *depot;
 

	
 
	FOR_ALL_DEPOTS(depot) {
 
		SlSetArrayIndex(depot->index);
 
		SlObject(depot, _depot_desc);
 
	}
 
}
 

	
 
static void Load_DEPT()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Depot *depot = new (index) Depot();
 
		SlObject(depot, _depot_desc);
 
	}
 
}
 

	
 
extern const ChunkHandler _depot_chunk_handlers[] = {
 
	{ 'DEPT', Save_DEPT, Load_DEPT, CH_ARRAY | CH_LAST},
 
};
src/group.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file group.h */
 

	
 
#ifndef GROUP_H
 
#define GROUP_H
 

	
 
#include "oldpool.h"
 

	
 
enum {
 
	ALL_GROUP     = 0xFFFD,
 
	DEFAULT_GROUP = 0xFFFE,
 
	INVALID_GROUP = 0xFFFF,
 
};
 

	
 
struct Group;
 
DECLARE_OLD_POOL(Group, Group, 5, 2047)
 

	
 
struct Group : PoolItem<Group, GroupID, &_Group_pool> {
 
	StringID string_id;                     ///< Group Name
 

	
 
	uint16 num_vehicle;                     ///< Number of vehicles wich belong to the group
 
	PlayerID owner;                         ///< Group Owner
 
	VehicleTypeByte vehicle_type;           ///< Vehicle type of the group
 

	
 
	bool replace_protection;                ///< If set to true, the global autoreplace have no effect on the group
 
	uint16 num_engines[TOTAL_NUM_ENGINES];  ///< Caches the number of engines of each type the player owns (no need to save this)
 

	
 
	Group(StringID str = STR_NULL);
 
	virtual ~Group();
 

	
 
	void QuickFree();
 

	
 
	bool IsValid() const;
 
};
 

	
 

	
 
static inline bool IsValidGroupID(GroupID index)
 
{
 
	return index < GetGroupPoolSize() && GetGroup(index)->IsValid();
 
}
 

	
 
static inline bool IsDefaultGroupID(GroupID index)
 
{
 
	return index == DEFAULT_GROUP;
 
}
 

	
 
/**
 
 * Checks if a GroupID stands for all vehicles of a player
 
 * @param id_g The GroupID to check
 
 * @return true is id_g is identical to ALL_GROUP
 
 */
 
static inline bool IsAllGroupID(GroupID id_g)
 
{
 
	return id_g == ALL_GROUP;
 
}
 

	
 
#define FOR_ALL_GROUPS_FROM(g, start) for (g = GetGroup(start); g != NULL; g = (g->index + 1U < GetGroupPoolSize()) ? GetGroup(g->index + 1) : NULL) if (g->IsValid())
 
#define FOR_ALL_GROUPS(g) FOR_ALL_GROUPS_FROM(g, 0)
 

	
 
/**
 
 * Get the current size of the GroupPool
 
 */
 
static inline uint GetGroupArraySize(void)
 
{
 
	const Group *g;
 
	uint num = 0;
 

	
 
	FOR_ALL_GROUPS(g) num++;
 

	
 
	return num;
 
}
 

	
 
/**
 
 * Get the number of engines with EngineID id_e in the group with GroupID
 
 * id_g
 
 * @param id_g The GroupID of the group used
 
 * @param id_e The EngineID of the engine to count
 
 * @return The number of engines with EngineID id_e in the group
 
 */
 
static inline uint GetGroupNumEngines(GroupID id_g, EngineID id_e)
src/group_cmd.cpp
Show inline comments
 
@@ -5,105 +5,100 @@
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "variables.h"
 
#include "functions.h"
 
#include "player.h"
 
#include "table/strings.h"
 
#include "command.h"
 
#include "vehicle.h"
 
#include "saveload.h"
 
#include "debug.h"
 
#include "group.h"
 
#include "train.h"
 
#include "aircraft.h"
 
#include "string.h"
 
#include "window.h"
 
#include "vehicle_gui.h"
 
#include "strings.h"
 
#include "misc/autoptr.hpp"
 

	
 
/**
 
 * Update the num engines of a groupID. Decrease the old one and increase the new one
 
 * @note called in SetTrainGroupID and UpdateTrainGroupID
 
 * @param i     EngineID we have to update
 
 * @param old_g index of the old group
 
 * @param new_g index of the new group
 
 */
 
static inline void UpdateNumEngineGroup(EngineID i, GroupID old_g, GroupID new_g)
 
{
 
	if (old_g != new_g) {
 
		/* Decrease the num engines of EngineID i of the old group if it's not the default one */
 
		if (!IsDefaultGroupID(old_g) && IsValidGroupID(old_g)) GetGroup(old_g)->num_engines[i]--;
 

	
 
		/* Increase the num engines of EngineID i of the new group if it's not the new one */
 
		if (!IsDefaultGroupID(new_g) && IsValidGroupID(new_g)) GetGroup(new_g)->num_engines[i]++;
 
	}
 
}
 

	
 

	
 
DEFINE_OLD_POOL_GENERIC(Group, Group)
 

	
 

	
 
Group::Group(StringID str)
 
{
 
	this->string_id = str;
 
}
 

	
 
Group::~Group()
 
{
 
	this->QuickFree();
 
	DeleteName(this->string_id);
 
	this->string_id = STR_NULL;
 
}
 

	
 
void Group::QuickFree()
 
{
 
	DeleteName(this->string_id);
 
}
 

	
 
bool Group::IsValid() const
 
{
 
	return this->string_id != STR_NULL;
 
}
 

	
 
void InitializeGroup(void)
 
{
 
	_Group_pool.CleanPool();
 
	_Group_pool.AddBlockToPool();
 
}
 

	
 

	
 
static WindowClass GetWCForVT(VehicleType vt)
 
{
 
	switch (vt) {
 
		default:
 
		case VEH_TRAIN:    return WC_TRAINS_LIST;
 
		case VEH_ROAD:     return WC_ROADVEH_LIST;
 
		case VEH_SHIP:     return WC_SHIPS_LIST;
 
		case VEH_AIRCRAFT: return WC_AIRCRAFT_LIST;
 
	}
 
}
 

	
 

	
 
/**
 
 * Create a new vehicle group.
 
 * @param tile unused
 
 * @param p1   vehicle type
 
 * @param p2   unused
 
 */
 
CommandCost CmdCreateGroup(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
 
{
 
	VehicleType vt = (VehicleType)p1;
 
	if (!IsPlayerBuildableVehicleType(vt)) return CMD_ERROR;
 

	
 
	AutoPtrT<Group> g_auto_delete;
 

	
 
	Group *g = new Group(STR_EMPTY);
 
	if (g == NULL) return CMD_ERROR;
 

	
 
	g_auto_delete = g;
 

	
 
	if (flags & DC_EXEC) {
 
		g->owner = _current_player;
 
		g->replace_protection = false;
 
		g->vehicle_type = vt;
 

	
 
		InvalidateWindowData(GetWCForVT(vt), (vt << 11) | VLW_GROUP_LIST | _current_player);
src/oldpool.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file oldpool.cpp */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "debug.h"
 
#include "functions.h"
 
#include "oldpool.h"
 
#include "helpers.hpp"
 

	
 
/**
 
 * Clean a pool in a safe way (does free all blocks)
 
 */
 
void OldMemoryPoolBase::CleanPool()
 
{
 
	uint i;
 

	
 
	DEBUG(misc, 4, "[Pool] (%s) cleaning pool..", this->name);
 

	
 
	this->cleaning_pool = true;
 
	/* Free all blocks */
 
	for (i = 0; i < this->current_blocks; i++) {
 
		if (this->clean_block_proc != NULL) {
 
			this->clean_block_proc(i * (1 << this->block_size_bits), (i + 1) * (1 << this->block_size_bits) - 1);
 
		}
 
		free(this->blocks[i]);
 
	}
 
	this->cleaning_pool = false;
 

	
 
	/* Free the block itself */
 
	free(this->blocks);
 

	
 
	/* Clear up some critical data */
 
	this->total_items = 0;
 
	this->current_blocks = 0;
 
	this->blocks = NULL;
 
	this->first_free_index = 0;
 
}
 

	
 
/**
 
 * This function tries to increase the size of array by adding
 
 *  1 block too it
 
 *
 
 * @return Returns false if the pool could not be increased
 
 */
 
bool OldMemoryPoolBase::AddBlockToPool()
 
{
 
	/* Is the pool at his max? */
 
	if (this->max_blocks == this->current_blocks) return false;
 

	
 
	this->total_items = (this->current_blocks + 1) * (1 << this->block_size_bits);
 

	
 
	DEBUG(misc, 4, "[Pool] (%s) increasing size of pool to %d items (%d bytes)", this->name, this->total_items, this->total_items * this->item_size);
 

	
 
	/* Increase the poolsize */
 
	this->blocks = ReallocT(this->blocks, this->current_blocks + 1);
 
	if (this->blocks == NULL) error("Pool: (%s) could not allocate memory for blocks", this->name);
 

	
 
	/* Allocate memory to the new block item */
 
	this->blocks[this->current_blocks] = MallocT<byte>(this->item_size * (1 << this->block_size_bits));
 
	if (this->blocks[this->current_blocks] == NULL)
 
		error("Pool: (%s) could not allocate memory for blocks", this->name);
 

	
 
	/* Clean the content of the new block */
 
	memset(this->blocks[this->current_blocks], 0, this->item_size * (1 << this->block_size_bits));
 

	
 
	/* Call a custom function if defined (e.g. to fill indexes) */
 
	if (this->new_block_proc != NULL) this->new_block_proc(this->current_blocks * (1 << this->block_size_bits));
 

	
 
	/* We have a new block */
 
	this->current_blocks++;
 

	
 
	return true;
 
}
 

	
 
/**
src/oldpool.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file oldpool.h */
 

	
 
#ifndef OLDPOOL_H
 
#define OLDPOOL_H
 

	
 
/* The function that is called after a new block is added
 
     start_item is the first item of the new made block */
 
typedef void OldMemoryPoolNewBlock(uint start_item);
 
/* The function that is called before a block is cleaned up */
 
typedef void OldMemoryPoolCleanBlock(uint start_item, uint end_item);
 

	
 
/**
 
 * Stuff for dynamic vehicles. Use the wrappers to access the OldMemoryPool
 
 *  please try to avoid manual calls!
 
 */
 
struct OldMemoryPoolBase {
 
	void CleanPool();
 
	bool AddBlockToPool();
 
	bool AddBlockIfNeeded(uint index);
 

	
 
protected:
 
	OldMemoryPoolBase(const char *name, uint max_blocks, uint block_size_bits, uint item_size,
 
				OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) :
 
		name(name), max_blocks(max_blocks), block_size_bits(block_size_bits),
 
		new_block_proc(new_block_proc), clean_block_proc(clean_block_proc), current_blocks(0),
 
		total_items(0), item_size(item_size), first_free_index(0), blocks(NULL) {}
 
		total_items(0), cleaning_pool(false), item_size(item_size), first_free_index(0), blocks(NULL) {}
 

	
 
	const char* name;     ///< Name of the pool (just for debugging)
 

	
 
	const uint max_blocks;      ///< The max amount of blocks this pool can have
 
	const uint block_size_bits; ///< The size of each block in bits
 

	
 
	/// Pointer to a function that is called after a new block is added
 
	OldMemoryPoolNewBlock *new_block_proc;
 
	/// Pointer to a function that is called to clean a block
 
	OldMemoryPoolCleanBlock *clean_block_proc;
 

	
 
	uint current_blocks;        ///< How many blocks we have in our pool
 
	uint total_items;           ///< How many items we now have in this pool
 

	
 
	bool cleaning_pool;         ///< Are we currently cleaning the pool?
 
public:
 
	const uint item_size;       ///< How many bytes one block is
 
	uint first_free_index;      ///< The index of the first free pool item in this pool
 
	byte **blocks;              ///< An array of blocks (one block hold all the items)
 

	
 
	/**
 
	 * Get the size of this pool, i.e. the total number of items you
 
	 * can put into it at the current moment; the pool might still
 
	 * be able to increase the size of the pool.
 
	 * @return the size of the pool
 
	 */
 
	inline uint GetSize() const
 
	{
 
		return this->total_items;
 
	}
 

	
 
	/**
 
	 * Can this pool allocate more blocks, i.e. is the maximum amount
 
	 * of allocated blocks not yet reached?
 
	 * @return the if and only if the amount of allocable blocks is
 
	 *         less than the amount of allocated blocks.
 
	 */
 
	inline bool CanAllocateMoreBlocks() const
 
	{
 
		return this->current_blocks < this->max_blocks;
 
	}
 

	
 
	/**
 
	 * Get the maximum number of allocable blocks.
 
	 * @return the numebr of blocks
 
	 */
 
	inline uint GetBlockCount() const
 
	{
 
		return this->current_blocks;
 
	}
 

	
 
	/**
 
	 * Get the name of this pool.
 
	 * @return the name
 
	 */
 
	inline const char *GetName() const
 
	{
 
		return this->name;
 
	}
 

	
 
	/**
 
	 * Is the pool in the cleaning phase?
 
	 * @return true if it is
 
	 */
 
	inline bool CleaningPool() const
 
	{
 
		return this->cleaning_pool;
 
	}
 
};
 

	
 
template <typename T>
 
struct OldMemoryPool : public OldMemoryPoolBase {
 
	OldMemoryPool(const char *name, uint max_blocks, uint block_size_bits, uint item_size,
 
				OldMemoryPoolNewBlock *new_block_proc, OldMemoryPoolCleanBlock *clean_block_proc) :
 
		OldMemoryPoolBase(name, max_blocks, block_size_bits, item_size, new_block_proc, clean_block_proc) {}
 

	
 
	/**
 
	 * Get the pool entry at the given index.
 
	 * @param index the index into the pool
 
	 * @pre index < this->GetSize()
 
	 * @return the pool entry.
 
	 */
 
	inline T *Get(uint index) const
 
	{
 
		assert(index < this->GetSize());
 
		return (T*)(this->blocks[index >> this->block_size_bits] +
 
				(index & ((1 << this->block_size_bits) - 1)) * this->item_size);
 
	}
 
};
 

	
 
/**
 
 * Generic function to initialize a new block in a pool.
 
 * @param start_item the first item that needs to be initialized
 
 */
 
template <typename T, OldMemoryPool<T> *Tpool>
 
static void PoolNewBlock(uint start_item)
 
{
 
	for (T *t = Tpool->Get(start_item); t != NULL; t = (t->index + 1U < Tpool->GetSize()) ? Tpool->Get(t->index + 1U) : NULL) {
 
		t = new (t) T();
 
		t->index = start_item++;
 
	}
 
}
 

	
 
/**
 
 * Generic function to free a new block in a pool.
 
 * This function uses QuickFree that is intended to only free memory that would be lost if the pool is freed.
 
 * @param start_item the first item that needs to be cleaned
 
 * @param end_item   the last item that needs to be cleaned
 
 */
 
template <typename T, OldMemoryPool<T> *Tpool>
 
static void PoolCleanBlock(uint start_item, uint end_item)
 
{
 
	for (uint i = start_item; i <= end_item; i++) {
 
		T *t = Tpool->Get(i);
 
		if (t->IsValid()) {
 
			t->QuickFree();
 
		}
 
		delete t;
 
	}
 
}
 

	
 

	
 
/**
 
 * Generalization for all pool items that are saved in the savegame.
 
 * It specifies all the mechanics to access the pool easily.
 
 */
 
template <typename T, typename Tid, OldMemoryPool<T> *Tpool>
 
struct PoolItem {
 
	/**
 
	 * The pool-wide index of this object.
 
	 */
 
	Tid index;
 

	
 
	/**
 
	 * We like to have the correct class destructed.
 
	 */
 
	virtual ~PoolItem()
 
	{
 
		if (this->index < Tpool->first_free_index) Tpool->first_free_index = this->index;
 
	}
 

	
 
	/**
 
	 * Called on each object when the pool is being destroyed, so one
 
	 * can free allocated memory without the need for freeing for
 
	 * example orders.
 
	 */
 
	virtual void QuickFree()
 
	{
 
	}
 

	
 
	/**
 
	 * An overriden version of new that allocates memory on the pool.
 
	 * @param size the size of the variable (unused)
 
	 * @return the memory that is 'allocated'
 
	 */
 
	void *operator new(size_t size)
 
	{
 
		return AllocateRaw();
 
	}
 

	
 
	/**
 
	 * 'Free' the memory allocated by the overriden new.
 
	 * @param p the memory to 'free'
 
	 */
 
	void operator delete(void *p)
 
	{
 
	}
 

	
 
	/**
 
	 * An overriden version of new, so you can directly allocate a new object with
 
	 * the correct index when one is loading the savegame.
 
	 * @param size  the size of the variable (unused)
 
	 * @param index the index of the object
 
	 * @return the memory that is 'allocated'
 
	 */
 
	void *operator new(size_t size, int index)
 
	{
 
		if (!Tpool->AddBlockIfNeeded(index)) error("%s: failed loading savegame: too many %s", Tpool->GetName(), Tpool->GetName());
 

	
 
		return Tpool->Get(index);
 
	}
 

	
 
	/**
 
	 * 'Free' the memory allocated by the overriden new.
 
	 * @param p     the memory to 'free'
 
	 * @param index the original parameter given to create the memory
 
	 */
 
	void operator delete(void *p, int index)
 
	{
 
	}
 

	
 
	/**
 
	 * An overriden version of new, so you can use the vehicle instance
 
	 * instead of a newly allocated piece of memory.
 
	 * @param size the size of the variable (unused)
 
	 * @param pn   the already existing object to use as 'storage' backend
 
	 * @return the memory that is 'allocated'
 
	 */
 
	void *operator new(size_t size, T *pn)
 
	{
 
		return pn;
 
	}
 

	
 
	/**
 
	 * 'Free' the memory allocated by the overriden new.
 
	 * @param p  the memory to 'free'
 
	 * @param pn the pointer that was given to 'new' on creation.
 
	 */
 
	void operator delete(void *p, T *pn)
 
	{
 
	}
 

	
 
	/**
 
	 * Is this a valid object or not?
 
	 * @return true if and only if it is valid
 
	 */
 
	virtual bool IsValid() const
 
	{
 
		return false;
 
	}
 

	
 
protected:
 
	/**
 
	 * Allocate a pool item; possibly allocate a new block in the pool.
 
	 * @return the allocated pool item (or NULL when the pool is full).
 
	 */
 
	static T *AllocateRaw()
 
	static inline T *AllocateRaw()
 
	{
 
		return AllocateRaw(Tpool->first_free_index);
 
	}
 

	
 
	/**
 
	 * Allocate a pool item; possibly allocate a new block in the pool.
 
	 * @param first the first pool item to start searching
 
	 * @return the allocated pool item (or NULL when the pool is full).
 
	 */
 
	static T *AllocateRaw(uint &first)
 
	static inline T *AllocateRaw(uint &first)
 
	{
 
		uint last_minus_one = Tpool->GetSize() - 1;
 

	
 
		for (T *t = Tpool->Get(first); t != NULL; t = (t->index < last_minus_one) ? Tpool->Get(t->index + 1U) : NULL) {
 
			if (!t->IsValid()) {
 
				first = t->index;
 
				Tid index = t->index;
 

	
 
				memset(t, 0, Tpool->item_size);
 
				t->index = index;
 
				return t;
 
			}
 
		}
 

	
 
		/* Check if we can add a block to the pool */
 
		if (Tpool->AddBlockToPool()) return AllocateRaw(first);
 

	
 
		return NULL;
 
	}
 

	
 
	/**
 
	 * Are we cleaning this pool?
 
	 * @return true if we are
 
	 */
 
	static inline bool CleaningPool()
 
	{
 
		return Tpool->CleaningPool();
 
	}
 
};
 

	
 

	
 
#define OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
 
	enum { \
 
		name##_POOL_BLOCK_SIZE_BITS = block_size_bits, \
 
		name##_POOL_MAX_BLOCKS      = max_blocks \
 
	};
 

	
 

	
 
#define OLD_POOL_ACCESSORS(name, type) \
 
	static inline type* Get##name(uint index) { return _##name##_pool.Get(index);  } \
 
	static inline uint Get##name##PoolSize()  { return _##name##_pool.GetSize(); }
 

	
 

	
 
#define DECLARE_OLD_POOL(name, type, block_size_bits, max_blocks) \
 
	OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
 
	extern OldMemoryPool<type> _##name##_pool; \
 
	OLD_POOL_ACCESSORS(name, type)
 

	
 

	
 
#define DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
 
	OldMemoryPool<type> _##name##_pool( \
 
		#name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
 
		new_block_proc, clean_block_proc);
 

	
 
#define DEFINE_OLD_POOL_GENERIC(name, type) \
 
	OldMemoryPool<type> _##name##_pool( \
 
		#name, name##_POOL_MAX_BLOCKS, name##_POOL_BLOCK_SIZE_BITS, sizeof(type), \
 
		PoolNewBlock<type, &_##name##_pool>, PoolCleanBlock<type, &_##name##_pool>);
 

	
 

	
 
#define STATIC_OLD_POOL(name, type, block_size_bits, max_blocks, new_block_proc, clean_block_proc) \
 
	OLD_POOL_ENUM(name, type, block_size_bits, max_blocks) \
 
	static DEFINE_OLD_POOL(name, type, new_block_proc, clean_block_proc) \
 
	OLD_POOL_ACCESSORS(name, type)
 

	
 
#endif /* OLDPOOL_H */
src/signs.cpp
Show inline comments
 
/* $Id$ */
 

	
 
/** @file signs.cpp */
 

	
 
#include "stdafx.h"
 
#include "openttd.h"
 
#include "table/strings.h"
 
#include "strings.h"
 
#include "functions.h"
 
#include "landscape.h"
 
#include "player.h"
 
#include "signs.h"
 
#include "saveload.h"
 
#include "command.h"
 
#include "variables.h"
 
#include "misc/autoptr.hpp"
 

	
 
SignID _new_sign_id;
 
uint _total_signs;
 

	
 
/* Initialize the sign-pool */
 
DEFINE_OLD_POOL_GENERIC(Sign, Sign)
 

	
 
Sign::Sign(StringID string)
 
{
 
	this->str = string;
 
}
 

	
 
Sign::~Sign()
 
{
 
	this->QuickFree();
 
	DeleteName(this->str);
 
	this->str = STR_NULL;
 
}
 

	
 
void Sign::QuickFree()
 
{
 
	DeleteName(this->str);
 
}
 

	
 
/**
 
 *
 
 * Update the coordinate of one sign
 
 * @param si Pointer to the Sign
 
 *
 
 */
 
static void UpdateSignVirtCoords(Sign *si)
 
{
 
	Point pt = RemapCoords(si->x, si->y, si->z);
 
	SetDParam(0, si->index);
 
	UpdateViewportSignPos(&si->sign, pt.x, pt.y - 6, STR_2806);
 
}
 

	
 
/**
 
 *
 
 * Update the coordinates of all signs
 
 *
 
 */
 
void UpdateAllSignVirtCoords()
 
{
 
	Sign *si;
 

	
 
	FOR_ALL_SIGNS(si) UpdateSignVirtCoords(si);
 

	
 
}
 

	
 
/**
 
 *
 
 * Marks the region of a sign as dirty
 
 *
 
 * @param si Pointer to the Sign
 
 */
 
static void MarkSignDirty(Sign *si)
 
{
 
	/* We use ZOOM_LVL_MAX here, as every viewport can have an other zoom,
 
		*  and there is no way for us to know which is the biggest. So make the
 
		*  biggest area dirty, and we are safe for sure. */
 
	MarkAllViewportsDirty(
 
		si->sign.left - 6,
 
		si->sign.top  - 3,
 
		si->sign.left + ScaleByZoom(si->sign.width_1 + 12, ZOOM_LVL_MAX),
 
		si->sign.top  + ScaleByZoom(12, ZOOM_LVL_MAX));
 
}
 

	
 
/**
 
 * Place a sign at the given coordinates. Ownership of sign has
 
 * no effect whatsoever except for the colour the sign gets for easy recognition,
 
 * but everybody is able to rename/remove it.
src/signs.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file signs.h */
 

	
 
#ifndef SIGNS_H
 
#define SIGNS_H
 

	
 
#include "oldpool.h"
 

	
 
struct Sign;
 
DECLARE_OLD_POOL(Sign, Sign, 2, 16000)
 

	
 
struct Sign : PoolItem<Sign, SignID, &_Sign_pool> {
 
	StringID     str;
 
	ViewportSign sign;
 
	int32        x;
 
	int32        y;
 
	byte         z;
 
	PlayerByte   owner; // placed by this player. Anyone can delete them though. OWNER_NONE for gray signs from old games.
 

	
 
	/**
 
	 * Creates a new sign
 
	 */
 
	Sign(StringID string = STR_NULL);
 

	
 
	/** Destroy the sign */
 
	~Sign();
 

	
 
	bool IsValid() const { return this->str != STR_NULL; }
 

	
 
	void QuickFree();
 
};
 

	
 
enum {
 
	INVALID_SIGN = 0xFFFF,
 
};
 

	
 
extern SignID _new_sign_id;
 

	
 

	
 
static inline SignID GetMaxSignIndex()
 
{
 
	/* TODO - This isn't the real content of the function, but
 
	 *  with the new pool-system this will be replaced with one that
 
	 *  _really_ returns the highest index. Now it just returns
 
	 *  the next safe value we are sure about everything is below.
 
	 */
 
	return GetSignPoolSize() - 1;
 
}
 

	
 
static inline uint GetNumSigns()
 
{
 
	extern uint _total_signs;
 
	return _total_signs;
 
}
 

	
 
static inline bool IsValidSignID(uint index)
 
{
 
	return index < GetSignPoolSize() && GetSign(index)->IsValid();
 
}
 

	
 
#define FOR_ALL_SIGNS_FROM(ss, start) for (ss = GetSign(start); ss != NULL; ss = (ss->index + 1U < GetSignPoolSize()) ? GetSign(ss->index + 1U) : NULL) if (ss->IsValid())
 
#define FOR_ALL_SIGNS(ss) FOR_ALL_SIGNS_FROM(ss, 0)
 

	
 
VARDEF bool _sign_sort_dirty;
 

	
 
void UpdateAllSignVirtCoords();
 
void PlaceProc_Sign(TileIndex tile);
 

	
 
/* signs_gui.cpp */
 
void ShowRenameSignWindow(const Sign *si);
 

	
 
void ShowSignList();
 

	
 
#endif /* SIGNS_H */
src/station.cpp
Show inline comments
 
@@ -19,121 +19,118 @@
 
#include "command.h"
 
#include "town.h"
 
#include "vehicle.h"
 
#include "news.h"
 
#include "saveload.h"
 
#include "economy.h"
 
#include "player.h"
 
#include "airport.h"
 
#include "sprite.h"
 
#include "depot.h"
 
#include "train.h"
 
#include "water_map.h"
 
#include "industry_map.h"
 
#include "newgrf_callbacks.h"
 
#include "newgrf_station.h"
 
#include "yapf/yapf.h"
 
#include "date.h"
 
#include "helpers.hpp"
 

	
 
Station::Station(TileIndex tile)
 
{
 
	DEBUG(station, cDebugCtorLevel, "I+%3d", index);
 

	
 
	xy = tile;
 
	airport_tile = dock_tile = train_tile = 0;
 
	bus_stops = truck_stops = NULL;
 
	had_vehicle_of_type = 0;
 
	time_since_load = 255;
 
	time_since_unload = 255;
 
	delete_ctr = 0;
 
	facilities = 0;
 

	
 
	last_vehicle_type = VEH_INVALID;
 

	
 
	random_bits = 0; // Random() must be called when station is really built (DC_EXEC)
 
	waiting_triggers = 0;
 
}
 

	
 
/**
 
 * Clean up a station by clearing vehicle orders and invalidating windows.
 
 * Aircraft-Hangar orders need special treatment here, as the hangars are
 
 * actually part of a station (tiletype is STATION), but the order type
 
 * is OT_GOTO_DEPOT.
 
 */
 
Station::~Station()
 
{
 
	DEBUG(station, cDebugCtorLevel, "I-%3d", index);
 

	
 
	DeleteName(this->string_id);
 
	free(this->speclist);
 

	
 
	if (CleaningPool()) return;
 

	
 
	MarkDirty();
 
	RebuildStationLists();
 
	InvalidateWindowClasses(WC_STATION_LIST);
 

	
 
	DeleteWindowById(WC_STATION_VIEW, index);
 

	
 
	/* Now delete all orders that go to the station */
 
	RemoveOrderFromAllVehicles(OT_GOTO_STATION, index);
 

	
 
	/* Subsidies need removal as well */
 
	DeleteSubsidyWithStation(index);
 

	
 
	xy = 0;
 

	
 
	for (CargoID c = 0; c < NUM_CARGO; c++) {
 
		goods[c].cargo.Truncate(0);
 
	}
 

	
 
	this->QuickFree();
 
}
 

	
 
void Station::QuickFree()
 
{
 
	DeleteName(this->string_id);
 
	free(this->speclist);
 
}
 

	
 
/** Called when new facility is built on the station. If it is the first facility
 
 * it initializes also 'xy' and 'random_bits' members */
 
void Station::AddFacility(byte new_facility_bit, TileIndex facil_xy)
 
{
 
	if (facilities == 0) {
 
		xy = facil_xy;
 
		random_bits = Random();
 
	}
 
	facilities |= new_facility_bit;
 
	owner = _current_player;
 
	build_date = _date;
 
}
 

	
 
void Station::MarkDirty() const
 
{
 
	if (sign.width_1 != 0) {
 
		InvalidateWindowWidget(WC_STATION_VIEW, index, 1);
 

	
 
		/* We use ZOOM_LVL_MAX here, as every viewport can have an other zoom,
 
		 *  and there is no way for us to know which is the biggest. So make the
 
		 *  biggest area dirty, and we are safe for sure. */
 
		MarkAllViewportsDirty(
 
			sign.left - 6,
 
			sign.top,
 
			sign.left + ScaleByZoom(sign.width_1 + 12, ZOOM_LVL_MAX),
 
			sign.top + ScaleByZoom(12, ZOOM_LVL_MAX));
 
	}
 
}
 

	
 
void Station::MarkTilesDirty(bool cargo_change) const
 
{
 
	TileIndex tile = train_tile;
 
	int w, h;
 

	
 
	/* XXX No station is recorded as 0, not INVALID_TILE... */
 
	if (tile == 0) return;
 

	
 
	/* cargo_change is set if we're refreshing the tiles due to cargo moving
 
	 * around. */
 
	if (cargo_change) {
 
		/* Don't waste time updating if there are no custom station graphics
 
		 * that might change. Even if there are custom graphics, they might
 
		 * not change. Unfortunately we have no way of telling. */
 
		if (this->num_specs == 0) return;
 
	}
 

	
src/station.h
Show inline comments
 
@@ -114,98 +114,96 @@ struct Station : PoolItem<Station, Stati
 
			return GetAirport(airport_type);
 
		}
 

	
 
	TileIndex xy;
 
	RoadStop *bus_stops;
 
	RoadStop *truck_stops;
 
	TileIndex train_tile;
 
	TileIndex airport_tile;
 
	TileIndex dock_tile;
 
	Town *town;
 
	uint16 string_id;
 

	
 
	ViewportSign sign;
 

	
 
	uint16 had_vehicle_of_type;
 

	
 
	byte time_since_load;
 
	byte time_since_unload;
 
	byte delete_ctr;
 
	PlayerByte owner;
 
	byte facilities;
 
	byte airport_type;
 

	
 
	/* trainstation width/height */
 
	byte trainst_w, trainst_h;
 

	
 
	/** List of custom stations (StationSpecs) allocated to the station */
 
	uint8 num_specs;
 
	StationSpecList *speclist;
 

	
 
	Date build_date;
 

	
 
	uint64 airport_flags;   ///< stores which blocks on the airport are taken. was 16 bit earlier on, then 32
 

	
 
	byte last_vehicle_type;
 
	std::list<Vehicle *> loading_vehicles;
 
	GoodsEntry goods[NUM_CARGO];
 

	
 
	uint16 random_bits;
 
	byte waiting_triggers;
 

	
 
	StationRect rect; ///< Station spread out rectangle (not saved) maintained by StationRect_xxx() functions
 

	
 
	static const int cDebugCtorLevel = 5;
 

	
 
	Station(TileIndex tile = 0);
 
	virtual ~Station();
 

	
 
	void QuickFree();
 

	
 
	void AddFacility(byte new_facility_bit, TileIndex facil_xy);
 
	void MarkDirty() const;
 
	void MarkTilesDirty(bool cargo_change) const;
 
	bool TileBelongsToRailStation(TileIndex tile) const;
 
	uint GetPlatformLength(TileIndex tile, DiagDirection dir) const;
 
	uint GetPlatformLength(TileIndex tile) const;
 
	bool IsBuoy() const;
 
	bool IsValid() const;
 
};
 

	
 
enum StationType {
 
	STATION_RAIL,
 
	STATION_AIRPORT,
 
	STATION_TRUCK,
 
	STATION_BUS,
 
	STATION_OILRIG,
 
	STATION_DOCK,
 
	STATION_BUOY
 
};
 

	
 
enum {
 
	FACIL_TRAIN      = 0x01,
 
	FACIL_TRUCK_STOP = 0x02,
 
	FACIL_BUS_STOP   = 0x04,
 
	FACIL_AIRPORT    = 0x08,
 
	FACIL_DOCK       = 0x10,
 
};
 

	
 
enum {
 
//	HVOT_PENDING_DELETE = 1 << 0, // not needed anymore
 
	HVOT_TRAIN    = 1 << 1,
 
	HVOT_BUS      = 1 << 2,
 
	HVOT_TRUCK    = 1 << 3,
 
	HVOT_AIRCRAFT = 1 << 4,
 
	HVOT_SHIP     = 1 << 5,
 
	/* This bit is used to mark stations. No, it does not belong here, but what
 
	 * can we do? ;-) */
 
	HVOT_BUOY     = 1 << 6
 
};
 

	
 
enum CatchmentArea {
 
	CA_NONE            =  0,
 
	CA_BUS             =  3,
 
	CA_TRUCK           =  3,
 
	CA_TRAIN           =  4,
 
	CA_DOCK            =  5
 
};
 

	
src/town.h
Show inline comments
 
@@ -115,98 +115,96 @@ struct Town : PoolItem<Town, TownID, &_T
 
	uint32 new_max_pass;
 
	uint32 new_max_mail;
 
	uint32 act_pass;
 
	uint32 act_mail;
 
	uint32 new_act_pass;
 
	uint32 new_act_mail;
 

	
 
	/* Amount of passengers that were transported. */
 
	byte pct_pass_transported;
 
	byte pct_mail_transported;
 

	
 
	/* Amount of food and paper that was transported. Actually a bit mask would be enough. */
 
	uint16 act_food;
 
	uint16 act_water;
 
	uint16 new_act_food;
 
	uint16 new_act_water;
 

	
 
	/* Time until we rebuild a house. */
 
	uint16 time_until_rebuild;
 

	
 
	/* When to grow town next time. */
 
	uint16 grow_counter;
 
	int16 growth_rate;
 

	
 
	/* Fund buildings program in action? */
 
	byte fund_buildings_months;
 

	
 
	/* Fund road reconstruction in action? */
 
	byte road_build_months;
 

	
 
	/* If this is a larger town, and should grow more quickly. */
 
	bool larger_town;
 

	
 
	/* NOSAVE: UpdateTownRadius updates this given the house count. */
 
	uint16 radius[5];
 

	
 
	/* NOSAVE: The number of each type of building in the town. */
 
	BuildingCounts building_counts;
 

	
 
	/**
 
	 * Creates a new town
 
	 */
 
	Town(TileIndex tile = 0);
 

	
 
	/** Destroy the town */
 
	~Town();
 

	
 
	bool IsValid() const { return this->xy != 0; }
 

	
 
	void QuickFree();
 
};
 

	
 
struct HouseSpec {
 
	/* Standard properties */
 
	Year min_date;                     ///< introduction year of the house
 
	Year max_date;                     ///< last year it can be built
 
	byte population;                   ///< population (Zero on other tiles in multi tile house.)
 
	byte removal_cost;                 ///< cost multiplier for removing it
 
	StringID building_name;            ///< building name
 
	uint16 remove_rating_decrease;     ///< rating decrease if removed
 
	byte mail_generation;              ///< mail generation multiplier (tile based, as the acceptances below)
 
	byte cargo_acceptance[3];          ///< acceptance level for the cargo slots
 
	CargoID accepts_cargo[3];          ///< 3 input cargo slots
 
	BuildingFlags building_flags;      ///< some flags that describe the house (size, stadium etc...)
 
	HouseZones building_availability;  ///< where can it be built (climates, zones)
 
	bool enabled;                      ///< the house is available to build (true by default, but can be disabled by newgrf)
 

	
 
	/* NewHouses properties */
 
	HouseID substitute_id;             ///< which original house this one is based on
 
	struct SpriteGroup *spritegroup;   ///< pointer to the different sprites of the house
 
	HouseID override;                  ///< which house this one replaces
 
	uint16 callback_mask;              ///< House callback flags
 
	byte random_colour[4];             ///< 4 "random" colours
 
	byte probability;                  ///< Relative probability of appearing (16 is the standard value)
 
	HouseExtraFlags extra_flags;       ///< some more flags
 
	HouseClassID class_id;             ///< defines the class this house has (grf file based) @See HouseGetVariable, prop 0x44
 
	byte animation_frames;             ///< number of animation frames
 
	byte animation_speed;              ///< amount of time between each of those frames
 
	byte processing_time;              ///< Periodic refresh multiplier
 
	byte minimum_life;                 ///< The minimum number of years this house will survive before the town rebuilds it
 

	
 
	/* grf file related properties*/
 
	uint8 local_id;                    ///< id defined by the grf file for this house
 
	const struct GRFFile *grffile;     ///< grf file that introduced this house
 
};
 

	
 
enum TownSizeMode {
 
	TSM_RANDOM,
 
	TSM_FIXED,
 
	TSM_CITY
 
};
 

	
 
VARDEF HouseSpec _house_specs[HOUSE_MAX];
 

	
 
uint32 GetWorldPopulation();
 

	
 
void UpdateTownVirtCoord(Town *t);
 
void InitializeTown();
src/town_cmd.cpp
Show inline comments
 
@@ -8,139 +8,137 @@
 
#include "debug.h"
 
#include "strings.h"
 
#include "road_map.h"
 
#include "table/strings.h"
 
#include "table/sprites.h"
 
#include "map.h"
 
#include "landscape.h"
 
#include "tile.h"
 
#include "town_map.h"
 
#include "tunnel_map.h"
 
#include "viewport.h"
 
#include "town.h"
 
#include "command.h"
 
#include "gfx.h"
 
#include "industry.h"
 
#include "station.h"
 
#include "vehicle.h"
 
#include "player.h"
 
#include "news.h"
 
#include "saveload.h"
 
#include "economy.h"
 
#include "gui.h"
 
#include "unmovable_map.h"
 
#include "water_map.h"
 
#include "variables.h"
 
#include "bridge.h"
 
#include "bridge_map.h"
 
#include "date.h"
 
#include "table/town_land.h"
 
#include "genworld.h"
 
#include "newgrf.h"
 
#include "newgrf_callbacks.h"
 
#include "newgrf_house.h"
 
#include "newgrf_commons.h"
 
#include "newgrf_townname.h"
 
#include "misc/autoptr.hpp"
 

	
 
/* Initialize the town-pool */
 
DEFINE_OLD_POOL_GENERIC(Town, Town)
 

	
 
Town::Town(TileIndex tile)
 
{
 
	if (tile != 0) _total_towns++;
 
	this->xy = tile;
 
}
 

	
 
Town::~Town()
 
{
 
	DeleteName(this->townnametype);
 

	
 
	if (CleaningPool()) return;
 

	
 
	Industry *i;
 

	
 
	/* Delete town authority window
 
	 * and remove from list of sorted towns */
 
	DeleteWindowById(WC_TOWN_VIEW, this->index);
 
	_town_sort_dirty = true;
 
	_total_towns--;
 

	
 
	/* Delete all industries belonging to the town */
 
	FOR_ALL_INDUSTRIES(i) if (i->town == this) delete i;
 

	
 
	/* Go through all tiles and delete those belonging to the town */
 
	for (TileIndex tile = 0; tile < MapSize(); ++tile) {
 
		switch (GetTileType(tile)) {
 
			case MP_HOUSE:
 
				if (GetTownByTile(tile) == this) DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
				break;
 

	
 
			case MP_ROAD:
 
			case MP_TUNNELBRIDGE:
 
				if (IsTileOwner(tile, OWNER_TOWN) &&
 
						ClosestTownFromTile(tile, (uint)-1) == this)
 
					DoCommand(tile, 0, 0, DC_EXEC, CMD_LANDSCAPE_CLEAR);
 
				break;
 

	
 
			default:
 
				break;
 
		}
 
	}
 

	
 
	DeleteSubsidyWithTown(this->index);
 

	
 
	MarkWholeScreenDirty();
 

	
 
	this->QuickFree();
 
	this->xy = 0;
 
}
 

	
 
void Town::QuickFree()
 
{
 
	DeleteName(this->townnametype);
 
}
 

	
 
// Local
 
static int _grow_town_result;
 

	
 
static bool BuildTownHouse(Town *t, TileIndex tile);
 
static void DoBuildTownHouse(Town *t, TileIndex tile);
 

	
 
static void TownDrawHouseLift(const TileInfo *ti)
 
{
 
	AddChildSpriteScreen(SPR_LIFT, PAL_NONE, 14, 60 - GetLiftPosition(ti->tile));
 
}
 

	
 
typedef void TownDrawTileProc(const TileInfo *ti);
 
static TownDrawTileProc * const _town_draw_tile_procs[1] = {
 
	TownDrawHouseLift
 
};
 

	
 
uint OriginalTileRandomiser(uint x, uint y)
 
{
 
	uint variant;
 
	variant  = x >> 4;
 
	variant ^= x >> 6;
 
	variant ^= y >> 4;
 
	variant -= y >> 6;
 
	variant &= 3;
 
	return variant;
 
}
 

	
 
/**
 
 * House Tile drawing handler.
 
 * Part of the tile loop process
 
 * @param ti TileInfo of the tile to draw
 
 */
 
static void DrawTile_Town(TileInfo *ti)
 
{
 
	const DrawBuildingsTileStruct *dcts;
 
	SpriteID image;
 
	SpriteID pal;
 
	HouseID house_id = GetHouseType(ti->tile);
 

	
 
	if (house_id >= NEW_HOUSE_OFFSET) {
 
		/* Houses don't necessarily need new graphics. If they don't have a
 
		 * spritegroup associated with them, then the sprite for the substitute
 
		 * house id is drawn instead. */
 
		if (GetHouseSpecs(house_id)->spritegroup != NULL) {
 
			DrawNewHouseTile(ti, house_id);
 
			return;
 
		} else {
 
			house_id = GetHouseSpecs(house_id)->substitute_id;
src/vehicle.cpp
Show inline comments
 
@@ -519,145 +519,145 @@ Vehicle *GetFirstVehicleInChain(const Ve
 
		}
 

	
 
		DEBUG(misc, 0, "v->first cache faulty. We shouldn't be here, rebuilding cache!");
 
	}
 

	
 
	/* It is the fact (currently) that newly built vehicles do not have
 
	 * their ->first pointer set. When this is the case, go up to the
 
	 * first engine and set the pointers correctly. Also the first pointer
 
	 * is not saved in a savegame, so this has to be fixed up after loading */
 

	
 
	/* Find the 'locomotive' or the first wagon in a chain */
 
	while ((u = GetPrevVehicleInChain_bruteforce(v)) != NULL) v = u;
 

	
 
	/* Set the first pointer of all vehicles in that chain to the first wagon */
 
	if ((v->type == VEH_TRAIN && (IsFrontEngine(v) || IsFreeWagon(v))) ||
 
			(v->type == VEH_ROAD && IsRoadVehFront(v))) {
 
		for (u = (Vehicle *)v; u != NULL; u = u->next) u->first = (Vehicle *)v;
 
	}
 

	
 
	return (Vehicle*)v;
 
}
 

	
 
uint CountVehiclesInChain(const Vehicle* v)
 
{
 
	uint count = 0;
 
	do count++; while ((v = v->next) != NULL);
 
	return count;
 
}
 

	
 
/** Check if a vehicle is counted in num_engines in each player struct
 
 * @param *v Vehicle to test
 
 * @return true if the vehicle is counted in num_engines
 
 */
 
bool IsEngineCountable(const Vehicle *v)
 
{
 
	switch (v->type) {
 
		case VEH_AIRCRAFT: return IsNormalAircraft(v); // don't count plane shadows and helicopter rotors
 
		case VEH_TRAIN:
 
			return !IsArticulatedPart(v) && // tenders and other articulated parts
 
			(!IsMultiheaded(v) || IsTrainEngine(v)); // rear parts of multiheaded engines
 
		case VEH_ROAD: return IsRoadVehFront(v);
 
		case VEH_SHIP: return true;
 
		default: return false; // Only count player buildable vehicles
 
	}
 
}
 

	
 
void Vehicle::PreDestructor()
 
{
 
	if (CleaningPool()) return;
 

	
 
	if (IsValidStationID(this->last_station_visited)) {
 
		GetStation(this->last_station_visited)->loading_vehicles.remove(this);
 

	
 
		HideFillingPercent(this->fill_percent_te_id);
 
		this->fill_percent_te_id = INVALID_TE_ID;
 
	}
 

	
 
	if (IsEngineCountable(this)) {
 
		GetPlayer(this->owner)->num_engines[this->engine_type]--;
 
		if (this->owner == _local_player) InvalidateAutoreplaceWindow(this->engine_type, this->group_id);
 

	
 
		if (IsValidGroupID(this->group_id)) GetGroup(this->group_id)->num_engines[this->engine_type]--;
 
		if (this->IsPrimaryVehicle()) DecreaseGroupNumVehicle(this->group_id);
 
	}
 

	
 
	this->QuickFree();
 
	if (this->type == VEH_ROAD) ClearSlot(this);
 

	
 
	if (this->type != VEH_TRAIN || (this->type == VEH_TRAIN && (IsFrontEngine(this) || IsFreeWagon(this)))) {
 
		InvalidateWindowData(WC_VEHICLE_DEPOT, this->tile);
 
	}
 

	
 
	this->cargo.Truncate(0);
 
	DeleteVehicleOrders(this);
 

	
 
	/* Now remove any artic part. This will trigger an other
 
	 *  destroy vehicle, which on his turn can remove any
 
	 *  other artic parts. */
 
	if ((this->type == VEH_TRAIN && EngineHasArticPart(this)) || (this->type == VEH_ROAD && RoadVehHasArticPart(this))) {
 
		delete this->next;
 
	}
 
}
 

	
 
Vehicle::~Vehicle()
 
{
 
	DeleteName(this->string_id);
 

	
 
	if (CleaningPool()) return;
 

	
 
	UpdateVehiclePosHash(this, INVALID_COORD, 0);
 
	this->next_hash = NULL;
 
	this->next_new_hash = NULL;
 

	
 
	DeleteVehicleNews(this->index, INVALID_STRING_ID);
 

	
 
	new (this) InvalidVehicle();
 
}
 

	
 
void Vehicle::QuickFree()
 
{
 
	DeleteName(this->string_id);
 
}
 

	
 
/**
 
 * Deletes all vehicles in a chain.
 
 * @param v The first vehicle in the chain.
 
 *
 
 * @warning This function is not valid for any vehicle containing articulated
 
 * parts.
 
 */
 
void DeleteVehicleChain(Vehicle *v)
 
{
 
	assert(v->type != VEH_TRAIN && v->type != VEH_ROAD);
 

	
 
	do {
 
		Vehicle *u = v;
 
		v = v->next;
 
		delete u;
 
	} while (v != NULL);
 
}
 

	
 
/** head of the linked list to tell what vehicles that visited a depot in a tick */
 
static Vehicle* _first_veh_in_depot_list;
 

	
 
/** Adds a vehicle to the list of vehicles, that visited a depot this tick
 
 * @param *v vehicle to add
 
 */
 
void VehicleEnteredDepotThisTick(Vehicle *v)
 
{
 
	/* we need to set v->leave_depot_instantly as we have no control of it's contents at this time */
 
	if (HASBIT(v->current_order.flags, OFB_HALT_IN_DEPOT) && !HASBIT(v->current_order.flags, OFB_PART_OF_ORDERS) && v->current_order.type == OT_GOTO_DEPOT) {
 
		/* we keep the vehicle in the depot since the user ordered it to stay */
 
		v->leave_depot_instantly = false;
 
	} else {
 
		/* the vehicle do not plan on stopping in the depot, so we stop it to ensure that it will not reserve the path
 
		 * out of the depot before we might autoreplace it to a different engine. The new engine would not own the reserved path
 
		 * we store that we stopped the vehicle, so autoreplace can start it again */
 
		v->vehstatus |= VS_STOPPED;
 
		v->leave_depot_instantly = true;
 
	}
 

	
 
	if (_first_veh_in_depot_list == NULL) {
 
		_first_veh_in_depot_list = v;
 
	} else {
 
		Vehicle *w = _first_veh_in_depot_list;
 
		while (w->depot_list != NULL) w = w->depot_list;
 
		w->depot_list = v;
 
	}
 
}
 

	
 
void CallVehicleTicks()
src/vehicle.h
Show inline comments
 
@@ -307,98 +307,96 @@ struct Vehicle : PoolItem<Vehicle, Vehic
 
	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
 

	
 
	uint16 load_unload_time_rem;
 
	byte vehicle_flags;         // Used for gradual loading and other miscellaneous things (@see VehicleFlags enum)
 

	
 
	Money profit_this_year;
 
	Money profit_last_year;
 
	Money value;
 

	
 
	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.
 

	
 
	union {
 
		VehicleRail rail;
 
		VehicleAir air;
 
		VehicleRoad road;
 
		VehicleSpecial special;
 
		VehicleDisaster disaster;
 
		VehicleShip ship;
 
	} u;
 

	
 

	
 
	/**
 
	 * Allocates a lot of vehicles.
 
	 * @param vl pointer to an array of vehicles to get allocated. Can be NULL if the vehicles aren't needed (makes it test only)
 
	 * @param num number of vehicles to allocate room for
 
	 * @return true if there is room to allocate all the vehicles
 
	 */
 
	static bool AllocateList(Vehicle **vl, int num);
 

	
 
	/** Create a new vehicle */
 
	Vehicle();
 

	
 
	/** Destroy all stuff that (still) needs the virtual functions to work properly */
 
	void PreDestructor();
 
	/** We want to 'destruct' the right class. */
 
	virtual ~Vehicle();
 

	
 
	void QuickFree();
 

	
 
	void BeginLoading();
 
	void LeaveStation();
 

	
 
	/**
 
	 * Handle the loading of the vehicle; when not it skips through dummy
 
	 * orders and does nothing in all other cases.
 
	 * @param mode is the non-first call for this vehicle in this tick?
 
	 */
 
	void HandleLoading(bool mode = false);
 

	
 
	/**
 
	 * Get a string 'representation' of the vehicle type.
 
	 * @return the string representation.
 
	 */
 
	virtual const char* GetTypeString() const { return "base vehicle"; }
 

	
 
	/**
 
	 * Marks the vehicles to be redrawn and updates cached variables
 
	 */
 
	virtual void MarkDirty() {}
 

	
 
	/**
 
	 * Updates the x and y offsets and the size of the sprite used
 
	 * for this vehicle.
 
	 * @param direction the direction the vehicle is facing
 
	 */
 
	virtual void UpdateDeltaXY(Direction direction) {}
 

	
 
	/**
 
	 * Sets the expense type associated to this vehicle type
 
	 * @param income whether this is income or (running) expenses of the vehicle
 
	 */
 
	virtual ExpensesType GetExpenseType(bool income) const { return EXPENSES_OTHER; }
 

	
 
	/**
 
	 * Invalidates the vehicle list window of this type of vehicle
 
	 */
 
	virtual WindowClass GetVehicleListWindowClass() const { return WC_NONE; }
 

	
 
	/**
 
	 * Play the sound associated with leaving the station
 
	 */
 
	virtual void PlayLeaveStationSound() const {}
 

	
 
	/**
 
	 * Whether this is the primary vehicle in the chain.
 
	 */
 
	virtual bool IsPrimaryVehicle() const { return false; }
src/waypoint.cpp
Show inline comments
 
@@ -359,107 +359,104 @@ CommandCost CmdRenameWaypoint(TileIndex 
 
}
 

	
 
/**
 
 * This hacks together some dummy one-shot Station structure for a waypoint.
 
 * @param tile on which to work
 
 * @return pointer to a Station
 
 */
 
Station *ComposeWaypointStation(TileIndex tile)
 
{
 
	Waypoint *wp = GetWaypointByTile(tile);
 

	
 
	/* instead of 'static Station stat' use byte array to avoid Station's destructor call upon exit. As
 
	 * a side effect, the station is not constructed now. */
 
	static byte stat_raw[sizeof(Station)];
 
	static Station &stat = *(Station*)stat_raw;
 

	
 
	stat.train_tile = stat.xy = wp->xy;
 
	stat.town = GetTown(wp->town_index);
 
	stat.string_id = wp->string;
 
	stat.build_date = wp->build_date;
 

	
 
	return &stat;
 
}
 

	
 
/**
 
 * Draw a waypoint
 
 * @param x coordinate
 
 * @param y coordinate
 
 * @param stat_id station id
 
 * @param railtype RailType to use for
 
 */
 
void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype)
 
{
 
	x += 33;
 
	y += 17;
 

	
 
	if (!DrawStationTile(x, y, railtype, AXIS_X, STAT_CLASS_WAYP, stat_id)) {
 
		DrawDefaultWaypointSprite(x, y, railtype);
 
	}
 
}
 

	
 
Waypoint::Waypoint(TileIndex tile)
 
{
 
	this->xy = tile;
 
}
 

	
 
Waypoint::~Waypoint()
 
{
 
	if (this->string != STR_NULL) DeleteName(this->string);
 

	
 
	if (CleaningPool()) return;
 

	
 
	RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, this->index);
 

	
 
	RedrawWaypointSign(this);
 
	this->xy = 0;
 

	
 
	this->QuickFree();
 
}
 

	
 
void Waypoint::QuickFree()
 
{
 
	if (this->string != STR_NULL) DeleteName(this->string);
 
}
 

	
 
bool Waypoint::IsValid() const
 
{
 
	return this->xy != 0;
 
}
 

	
 

	
 
/**
 
 * Fix savegames which stored waypoints in their old format
 
 */
 
void FixOldWaypoints()
 
{
 
	Waypoint *wp;
 

	
 
	/* Convert the old 'town_or_string', to 'string' / 'town' / 'town_cn' */
 
	FOR_ALL_WAYPOINTS(wp) {
 
		wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;
 
		wp->town_cn = 0;
 
		if (wp->string & 0xC000) {
 
			wp->town_cn = wp->string & 0x3F;
 
			wp->string = STR_NULL;
 
		}
 
	}
 
}
 

	
 
void InitializeWaypoints()
 
{
 
	_Waypoint_pool.CleanPool();
 
	_Waypoint_pool.AddBlockToPool();
 
}
 

	
 
static const SaveLoad _waypoint_desc[] = {
 
	SLE_CONDVAR(Waypoint, xy,         SLE_FILE_U16 | SLE_VAR_U32,  0, 5),
 
	SLE_CONDVAR(Waypoint, xy,         SLE_UINT32,                  6, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, town_index, SLE_UINT16,                 12, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, town_cn,    SLE_UINT8,                  12, SL_MAX_VERSION),
 
	    SLE_VAR(Waypoint, string,     SLE_UINT16),
 
	    SLE_VAR(Waypoint, deleted,    SLE_UINT8),
 

	
 
	SLE_CONDVAR(Waypoint, build_date, SLE_FILE_U16 | SLE_VAR_I32,  3, 30),
 
	SLE_CONDVAR(Waypoint, build_date, SLE_INT32,                  31, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, localidx,   SLE_UINT8,                   3, SL_MAX_VERSION),
 
	SLE_CONDVAR(Waypoint, grfid,      SLE_UINT32,                 17, SL_MAX_VERSION),
 

	
 
	SLE_END()
 
};
 

	
src/waypoint.h
Show inline comments
 
/* $Id$ */
 

	
 
/** @file waypoint.h */
 

	
 
#ifndef WAYPOINT_H
 
#define WAYPOINT_H
 

	
 
#include "oldpool.h"
 
#include "rail_map.h"
 

	
 
struct Waypoint;
 
DECLARE_OLD_POOL(Waypoint, Waypoint, 3, 8000)
 

	
 
struct Waypoint : PoolItem<Waypoint, WaypointID, &_Waypoint_pool> {
 
	TileIndex xy;      ///< Tile of waypoint
 

	
 
	TownID town_index; ///< Town associated with the waypoint
 
	byte town_cn;      ///< The Nth waypoint for this town (consecutive number)
 
	StringID string;   ///< If this is zero (i.e. no custom name), town + town_cn is used for naming
 

	
 
	ViewportSign sign; ///< Dimensions of sign (not saved)
 
	Date build_date;   ///< Date of construction
 

	
 
	byte stat_id;      ///< ID of waypoint within the waypoint class (not saved)
 
	uint32 grfid;      ///< ID of GRF file
 
	byte localidx;     ///< Index of station within GRF file
 

	
 
	byte deleted;      ///< Delete counter. If greater than 0 then it is decremented until it reaches 0; the waypoint is then is deleted.
 

	
 
	Waypoint(TileIndex tile = 0);
 
	~Waypoint();
 

	
 
	void QuickFree();
 

	
 
	bool IsValid() const;
 
};
 

	
 
static inline bool IsValidWaypointID(WaypointID index)
 
{
 
	return index < GetWaypointPoolSize() && GetWaypoint(index)->IsValid();
 
}
 

	
 
static inline void DeleteWaypoint(Waypoint *wp)
 
{
 
	wp->~Waypoint();
 
}
 

	
 
#define FOR_ALL_WAYPOINTS_FROM(wp, start) for (wp = GetWaypoint(start); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) if (wp->IsValid())
 
#define FOR_ALL_WAYPOINTS(wp) FOR_ALL_WAYPOINTS_FROM(wp, 0)
 

	
 

	
 
/**
 
 * Fetch a waypoint by tile
 
 * @param tile Tile of waypoint
 
 * @return Waypoint
 
 */
 
static inline Waypoint *GetWaypointByTile(TileIndex tile)
 
{
 
	assert(IsTileType(tile, MP_RAILWAY) && IsRailWaypoint(tile));
 
	return GetWaypoint(GetWaypointIndex(tile));
 
}
 

	
 
CommandCost RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove);
 
Station *ComposeWaypointStation(TileIndex tile);
 
void ShowRenameWaypointWindow(const Waypoint *cp);
 
void DrawWaypointSprite(int x, int y, int stat_id, RailType railtype);
 
void FixOldWaypoints();
 
void UpdateAllWaypointSigns();
 
void AfterLoadWaypoints();
 

	
 
#endif /* WAYPOINT_H */
0 comments (0 inline, 0 general)