Files @ r5407:8687f42a7985
Branch filter:

Location: cpp/openttd-patchpack/source/waypoint.c - annotation

rubidium
(svn r7603) -Codechange (FS#481): update the Polish Town Name generator with Unicode characters (DDream).
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
r2186:5ee653b1b5e1
r2186:5ee653b1b5e1
r1542:6bae7041e7bc
r1891:c5c5466afa35
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2163:ae001e2aa5b0
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r3101:528c6b45c2fa
r5385:1c8ef6521bf2
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2159:2c706fe6b0a7
r1542:6bae7041e7bc
r3578:fa96f4cd9eaa
r3900:1c2675abec23
r4261:8c2d0c75e37a
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4984:6ebf51f02b56
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4346:fa4ac6b6f852
r4346:fa4ac6b6f852
r4984:6ebf51f02b56
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r5216:bdd3aa57475e
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2752:65f0a677c814
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4346:fa4ac6b6f852
r4346:fa4ac6b6f852
r4984:6ebf51f02b56
r4346:fa4ac6b6f852
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4984:6ebf51f02b56
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2817:7ad46034031f
r1542:6bae7041e7bc
r3422:cca72d7a228c
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2752:65f0a677c814
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4346:fa4ac6b6f852
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4390:5bab99565ca2
r4390:5bab99565ca2
r4390:5bab99565ca2
r4527:4b01e6756ce8
r4390:5bab99565ca2
r4390:5bab99565ca2
r4390:5bab99565ca2
r4390:5bab99565ca2
r4390:5bab99565ca2
r4390:5bab99565ca2
r1542:6bae7041e7bc
r2752:65f0a677c814
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1977:1f8b99c96041
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4346:fa4ac6b6f852
r4077:259c4c4aacad
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r5350:c8874719b8c6
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r3676:3002164413eb
r3676:3002164413eb
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r1782:0fd68043a2ea
r1782:0fd68043a2ea
r3491:10ed78e15d31
r2625:27ad3b929a5b
r1782:0fd68043a2ea
r2085:757cdc338c24
r2085:757cdc338c24
r2085:757cdc338c24
r1782:0fd68043a2ea
r3491:10ed78e15d31
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r3636:a8e0c73aca96
r3101:528c6b45c2fa
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1782:0fd68043a2ea
r2625:27ad3b929a5b
r1782:0fd68043a2ea
r3267:f0ddcd9d96b3
r3792:deb3c0493c60
r3267:f0ddcd9d96b3
r3267:f0ddcd9d96b3
r3101:528c6b45c2fa
r1542:6bae7041e7bc
r3101:528c6b45c2fa
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r4077:259c4c4aacad
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r5385:1c8ef6521bf2
r5385:1c8ef6521bf2
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1782:0fd68043a2ea
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4051:6d591941fb66
r4051:6d591941fb66
r3242:4dca345fd1dd
r3101:528c6b45c2fa
r2670:992f15ff9b56
r4051:6d591941fb66
r2670:992f15ff9b56
r3676:3002164413eb
r4051:6d591941fb66
r3676:3002164413eb
r3676:3002164413eb
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r2670:992f15ff9b56
r1542:6bae7041e7bc
r2670:992f15ff9b56
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4000:702cb45b8eab
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r5348:47fcb8058c81
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4500:67f3c4af0f2b
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1977:1f8b99c96041
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r4077:259c4c4aacad
r4077:259c4c4aacad
r4077:259c4c4aacad
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r5348:47fcb8058c81
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r3242:4dca345fd1dd
r3101:528c6b45c2fa
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r5348:47fcb8058c81
r1542:6bae7041e7bc
r5348:47fcb8058c81
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1782:0fd68043a2ea
r3491:10ed78e15d31
r1782:0fd68043a2ea
r1782:0fd68043a2ea
r1782:0fd68043a2ea
r3491:10ed78e15d31
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1782:0fd68043a2ea
r3491:10ed78e15d31
r1782:0fd68043a2ea
r1782:0fd68043a2ea
r1782:0fd68043a2ea
r3491:10ed78e15d31
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4352:460a517b040f
r1782:0fd68043a2ea
r1820:335b057adac7
r4077:259c4c4aacad
r4077:259c4c4aacad
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2026:25935f6b221a
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4077:259c4c4aacad
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1977:1f8b99c96041
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r2520:1767662fb229
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r3764:4a2ca18ddafd
r2261:e6fb9fd7ed61
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4984:6ebf51f02b56
r4984:6ebf51f02b56
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1881:ce1fe6a2816a
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r1542:6bae7041e7bc
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r4344:bff007ae1fd1
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4346:fa4ac6b6f852
r4346:fa4ac6b6f852
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r4984:6ebf51f02b56
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
r1542:6bae7041e7bc
/* $Id$ */

#include "stdafx.h"
#include "openttd.h"

#include "command.h"
#include "functions.h"
#include "gfx.h"
#include "map.h"
#include "order.h"
#include "rail_map.h"
#include "bridge_map.h"
#include "saveload.h"
#include "station.h"
#include "tile.h"
#include "town.h"
#include "waypoint.h"
#include "variables.h"
#include "table/strings.h"
#include "vehicle.h"
#include "yapf/yapf.h"
#include "date.h"

enum {
	MAX_WAYPOINTS_PER_TOWN = 64,
};

/**
 * Called if a new block is added to the waypoint-pool
 */
static void WaypointPoolNewBlock(uint start_item)
{
	Waypoint *wp;

	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
	 * TODO - This is just a temporary stage, this will be removed. */
	for (wp = GetWaypoint(start_item); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) wp->index = start_item++;
}

DEFINE_OLD_POOL(Waypoint, Waypoint, WaypointPoolNewBlock, NULL)

/* Create a new waypoint */
static Waypoint* AllocateWaypoint(void)
{
	Waypoint *wp;

	/* We don't use FOR_ALL here, because FOR_ALL skips invalid items.
	 * TODO - This is just a temporary stage, this will be removed. */
	for (wp = GetWaypoint(0); wp != NULL; wp = (wp->index + 1U < GetWaypointPoolSize()) ? GetWaypoint(wp->index + 1U) : NULL) {
		if (!IsValidWaypoint(wp)) {
			uint index = wp->index;

			memset(wp, 0, sizeof(*wp));
			wp->index = index;

			return wp;
		}
	}

	/* Check if we can add a block to the pool */
	if (AddBlockToPool(&_Waypoint_pool)) return AllocateWaypoint();

	return NULL;
}

/* Update the sign for the waypoint */
static void UpdateWaypointSign(Waypoint* wp)
{
	Point pt = RemapCoords2(TileX(wp->xy) * TILE_SIZE, TileY(wp->xy) * TILE_SIZE);
	SetDParam(0, wp->index);
	UpdateViewportSignPos(&wp->sign, pt.x, pt.y - 0x20, STR_WAYPOINT_VIEWPORT);
}

/* Redraw the sign of a waypoint */
static void RedrawWaypointSign(const Waypoint* wp)
{
	MarkAllViewportsDirty(
		wp->sign.left - 6,
		wp->sign.top,
		wp->sign.left + (wp->sign.width_1 << 2) + 12,
		wp->sign.top + 48);
}

/* Update all signs */
void UpdateAllWaypointSigns(void)
{
	Waypoint *wp;

	FOR_ALL_WAYPOINTS(wp) {
		UpdateWaypointSign(wp);
	}
}

/* Internal handler to delete a waypoint */
void DestroyWaypoint(Waypoint *wp)
{
	RemoveOrderFromAllVehicles(OT_GOTO_WAYPOINT, wp->index);

	if (wp->string != STR_NULL) DeleteName(wp->string);

	RedrawWaypointSign(wp);
}

/* Set the default name for a waypoint */
static void MakeDefaultWaypointName(Waypoint* wp)
{
	Waypoint *local_wp;
	bool used_waypoint[MAX_WAYPOINTS_PER_TOWN];
	int i;

	wp->town_index = ClosestTownFromTile(wp->xy, (uint)-1)->index;

	memset(used_waypoint, 0, sizeof(used_waypoint));

	/* Find an unused waypoint number belonging to this town */
	FOR_ALL_WAYPOINTS(local_wp) {
		if (wp == local_wp) continue;

		if (local_wp->xy && local_wp->string == STR_NULL && local_wp->town_index == wp->town_index)
			used_waypoint[local_wp->town_cn] = true;
	}

	/* Find an empty spot */
	for (i = 0; used_waypoint[i] && i < MAX_WAYPOINTS_PER_TOWN; i++) {}

	wp->string = STR_NULL;
	wp->town_cn = i;
}

/* Find a deleted waypoint close to a tile. */
static Waypoint *FindDeletedWaypointCloseTo(TileIndex tile)
{
	Waypoint *wp, *best = NULL;
	uint thres = 8;

	FOR_ALL_WAYPOINTS(wp) {
		if (wp->deleted) {
			uint cur_dist = DistanceManhattan(tile, wp->xy);

			if (cur_dist < thres) {
				thres = cur_dist;
				best = wp;
			}
		}
	}

	return best;
}

/**
 * Update waypoint graphics id against saved GRFID/localidx.
 * This is to ensure the chosen graphics are correct if GRF files are changed.
 */
void AfterLoadWaypoints(void)
{
	Waypoint *wp;

	FOR_ALL_WAYPOINTS(wp) {
		uint i;

		if (wp->grfid == 0) continue;

		for (i = 0; i < GetNumCustomStations(STAT_CLASS_WAYP); i++) {
			const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, i);
			if (statspec != NULL && statspec->grfid == wp->grfid && statspec->localidx == wp->localidx) {
				wp->stat_id = i;
				break;
			}
		}
	}
}

/** Convert existing rail to waypoint. Eg build a waypoint station over
 * piece of rail
 * @param tile tile where waypoint will be built
 * @param p1 graphics for waypoint type, 0 indicates standard graphics
 * @param p2 unused
 *
 * @todo When checking for the tile slope,
 * distingush between "Flat land required" and "land sloped in wrong direction"
 */
int32 CmdBuildTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
	Waypoint *wp;
	Slope tileh;
	Axis axis;

	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);

	/* if custom gfx are used, make sure it is within bounds */
	if (p1 >= GetNumCustomStations(STAT_CLASS_WAYP)) return CMD_ERROR;

	if (!IsTileType(tile, MP_RAILWAY) ||
			GetRailTileType(tile) != RAIL_TILE_NORMAL || (
				(axis = AXIS_X, GetTrackBits(tile) != TRACK_BIT_X) &&
				(axis = AXIS_Y, GetTrackBits(tile) != TRACK_BIT_Y)
			)) {
		return_cmd_error(STR_1005_NO_SUITABLE_RAILROAD_TRACK);
	}

	if (!CheckTileOwnership(tile)) return CMD_ERROR;
	if (!EnsureNoVehicle(tile)) return CMD_ERROR;

	tileh = GetTileSlope(tile, NULL);
	if (tileh != SLOPE_FLAT &&
			(!_patches.build_on_slopes || IsSteepSlope(tileh) || !(tileh & (0x3 << axis)) || !(tileh & ~(0x3 << axis)))) {
		return_cmd_error(STR_0007_FLAT_LAND_REQUIRED);
	}

	if (MayHaveBridgeAbove(tile) && IsBridgeAbove(tile)) return_cmd_error(STR_5007_MUST_DEMOLISH_BRIDGE_FIRST);

	/* Check if there is an already existing, deleted, waypoint close to us that we can reuse. */
	wp = FindDeletedWaypointCloseTo(tile);
	if (wp == NULL) {
		wp = AllocateWaypoint();
		if (wp == NULL) return CMD_ERROR;

		wp->town_index = 0;
		wp->string = STR_NULL;
		wp->town_cn = 0;
	}

	if (flags & DC_EXEC) {
		const StationSpec* statspec;

		MakeRailWaypoint(tile, GetTileOwner(tile), axis, GetRailType(tile), wp->index);
		MarkTileDirtyByTile(tile);

		statspec = GetCustomStationSpec(STAT_CLASS_WAYP, p1);

		if (statspec != NULL) {
			wp->stat_id = p1;
			wp->grfid = statspec->grfid;
			wp->localidx = statspec->localidx;
		} else {
			// Specified custom graphics do not exist, so use default.
			wp->stat_id = 0;
			wp->grfid = 0;
			wp->localidx = 0;
		}

		wp->deleted = 0;
		wp->xy = tile;
		wp->build_date = _date;

		if (wp->town_index == 0) MakeDefaultWaypointName(wp);

		UpdateWaypointSign(wp);
		RedrawWaypointSign(wp);
		YapfNotifyTrackLayoutChange(tile, AxisToTrack(axis));
	}

	return _price.build_train_depot;
}

/* Daily loop for waypoints */
void WaypointsDailyLoop(void)
{
	Waypoint *wp;

	/* Check if we need to delete a waypoint */
	FOR_ALL_WAYPOINTS(wp) {
		if (wp->deleted != 0 && --wp->deleted == 0) DeleteWaypoint(wp);
	}
}

/* Remove a waypoint */
int32 RemoveTrainWaypoint(TileIndex tile, uint32 flags, bool justremove)
{
	Waypoint *wp;

	/* Make sure it's a waypoint */
	if (!IsTileType(tile, MP_RAILWAY) ||
			!IsRailWaypoint(tile) ||
			(!CheckTileOwnership(tile) && _current_player != OWNER_WATER) ||
			!EnsureNoVehicle(tile)) {
		return CMD_ERROR;
	}

	if (flags & DC_EXEC) {
		Track track = GetRailWaypointTrack(tile);
		wp = GetWaypointByTile(tile);

		wp->deleted = 30; // let it live for this many days before we do the actual deletion.
		RedrawWaypointSign(wp);

		if (justremove) {
			MakeRailNormal(tile, GetTileOwner(tile), GetRailWaypointBits(tile), GetRailType(tile));
			MarkTileDirtyByTile(tile);
		} else {
			DoClearSquare(tile);
			SetSignalsOnBothDir(tile, track);
		}
		YapfNotifyTrackLayoutChange(tile, track);
	}

	return _price.remove_train_depot;
}

/** Delete a waypoint
 * @param tile tile where waypoint is to be deleted
 * @param p1 unused
 * @param p2 unused
 */
int32 CmdRemoveTrainWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
	SET_EXPENSES_TYPE(EXPENSES_CONSTRUCTION);
	return RemoveTrainWaypoint(tile, flags, true);
}

/** Rename a waypoint.
 * @param tile unused
 * @param p1 id of waypoint
 * @param p2 unused
 */
int32 CmdRenameWaypoint(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
{
	Waypoint *wp;

	if (!IsValidWaypointID(p1)) return CMD_ERROR;

	if (_cmd_text[0] != '\0') {
		StringID str = AllocateNameUnique(_cmd_text, 0);

		if (str == 0) return CMD_ERROR;

		if (flags & DC_EXEC) {
			wp = GetWaypoint(p1);
			if (wp->string != STR_NULL) DeleteName(wp->string);

			wp->string = str;
			wp->town_cn = 0;

			UpdateWaypointSign(wp);
			MarkWholeScreenDirty();
		} else {
			DeleteName(str);
		}
	} else {
		if (flags & DC_EXEC) {
			wp = GetWaypoint(p1);
			if (wp->string != STR_NULL) DeleteName(wp->string);

			MakeDefaultWaypointName(wp);
			UpdateWaypointSign(wp);
			MarkWholeScreenDirty();
		}
	}
	return 0;
}

/* This hacks together some dummy one-shot Station structure for a waypoint. */
Station *ComposeWaypointStation(TileIndex tile)
{
	Waypoint *wp = GetWaypointByTile(tile);
	static Station stat;

	stat.train_tile = stat.xy = wp->xy;
	stat.town = GetTown(wp->town_index);
	stat.string_id = wp->string == STR_NULL ? /* FIXME? */ 0 : wp->string;
	stat.build_date = wp->build_date;

	return &stat;
}

/* Draw a waypoint */
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);
	}
}

/* Fix savegames which stored waypoints in their old format */
void FixOldWaypoints(void)
{
	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(void)
{
	CleanPool(&_Waypoint_pool);
	AddBlockToPool(&_Waypoint_pool);
}

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()
};

static void Save_WAYP(void)
{
	Waypoint *wp;

	FOR_ALL_WAYPOINTS(wp) {
		SlSetArrayIndex(wp->index);
		SlObject(wp, _waypoint_desc);
	}
}

static void Load_WAYP(void)
{
	int index;

	while ((index = SlIterateArray()) != -1) {
		Waypoint *wp;

		if (!AddBlockIfNeeded(&_Waypoint_pool, index))
			error("Waypoints: failed loading savegame: too many waypoints");

		wp = GetWaypoint(index);
		SlObject(wp, _waypoint_desc);
	}
}

const ChunkHandler _waypoint_chunk_handlers[] = {
	{ 'CHKP', Save_WAYP, Load_WAYP, CH_ARRAY | CH_LAST},
};