Methapolis  0.27
 All Classes Namespaces Files Functions Variables Enumerator
RoadLikeTool.java
Go to the documentation of this file.
1 // This file is part of MicropolisJ.
2 // Copyright (C) 2013 Jason Long
3 // Portions Copyright (C) 1989-2007 Electronic Arts Inc.
4 //
5 // MicropolisJ is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU GPLv3, with additional terms.
7 // See the README file, included in this distribution, for details.
8 
9 package micropolisj.engine;
10 
11 import static micropolisj.engine.TileConstants.*;
12 
13 class RoadLikeTool extends ToolStroke
14 {
15  RoadLikeTool(Micropolis city, MicropolisTool tool, int xpos, int ypos)
16  {
17  super(city, tool, xpos, ypos);
18  }
19 
20  @Override
21  protected void applyArea(ToolEffectIfc eff)
22  {
23  for (;;) {
24  if (!applyForward(eff)) {
25  break;
26  }
27  if (!applyBackward(eff)) {
28  break;
29  }
30  }
31  }
32 
33  boolean applyBackward(ToolEffectIfc eff)
34  {
35  boolean anyChange = false;
36 
37  CityRect b = getBounds();
38  for (int i = b.height - 1; i >= 0; i--) {
39  for (int j = b.width - 1; j >= 0; j--) {
40  TranslatedToolEffect tte = new TranslatedToolEffect(eff, b.x+j, b.y+i);
41  anyChange = anyChange || applySingle(tte);
42  }
43  }
44  return anyChange;
45  }
46 
47  boolean applyForward(ToolEffectIfc eff)
48  {
49  boolean anyChange = false;
50 
51  CityRect b = getBounds();
52  for (int i = 0; i < b.height; i++) {
53  for (int j = 0; j < b.width; j++) {
54  TranslatedToolEffect tte = new TranslatedToolEffect(eff, b.x+j, b.y+i);
55  anyChange = anyChange || applySingle(tte);
56  }
57  }
58  return anyChange;
59  }
60 
61  @Override
62  public CityRect getBounds()
63  {
64  // constrain bounds to be a rectangle with
65  // either width or height equal to one.
66 
67  assert tool.getWidth() == 1;
68  assert tool.getHeight() == 1;
69 
70  if (Math.abs(xdest-xpos) >= Math.abs(ydest-ypos)) {
71  // horizontal line
72  CityRect r = new CityRect();
73  r.x = Math.min(xpos, xdest);
74  r.width = Math.abs(xdest-xpos) + 1;
75  r.y = ypos;
76  r.height = 1;
77  return r;
78  }
79  else {
80  // vertical line
81  CityRect r = new CityRect();
82  r.x = xpos;
83  r.width = 1;
84  r.y = Math.min(ypos, ydest);
85  r.height = Math.abs(ydest-ypos) + 1;
86  return r;
87  }
88  }
89 
90  boolean applySingle(ToolEffectIfc eff)
91  {
92  switch (tool)
93  {
94  case RAIL:
95  return applyRailTool(eff);
96 
97  case ROADS:
98  return applyRoadTool(eff);
99 
100  case WIRE:
101  return applyWireTool(eff);
102 
103  default:
104  throw new Error("Unexpected tool: " + tool);
105  }
106  }
107 
108  boolean applyRailTool(ToolEffectIfc eff)
109  {
110  if (layRail(eff)) {
111  fixZone(eff);
112  return true;
113  }
114  else {
115  return false;
116  }
117  }
118 
119  boolean applyRoadTool(ToolEffectIfc eff)
120  {
121  if (layRoad(eff)) {
122  fixZone(eff);
123  return true;
124  }
125  else {
126  return false;
127  }
128  }
129 
130  boolean applyWireTool(ToolEffectIfc eff)
131  {
132  if (layWire(eff)) {
133  fixZone(eff);
134  return true;
135  }
136  else {
137  return false;
138  }
139  }
140 
141  private boolean layRail(ToolEffectIfc eff)
142  {
143  final int RAIL_COST = 20;
144  final int TUNNEL_COST = 100;
145 
146  int cost = RAIL_COST;
147 
148  char tile = (char) eff.getTile(0, 0);
149  tile = neutralizeRoad(tile);
150 
151  switch (tile)
152  {
153  case RIVER: // rail on water
154  case REDGE:
155  case CHANNEL:
156 
157  cost = TUNNEL_COST;
158 
159  // check east
160  {
161  char eTile = neutralizeRoad(eff.getTile(1, 0));
162  if (eTile == RAILHPOWERV ||
163  eTile == HRAIL ||
164  (eTile >= LHRAIL && eTile <= HRAILROAD))
165  {
166  eff.setTile(0, 0, HRAIL);
167  break;
168  }
169  }
170 
171  // check west
172  {
173  char wTile = neutralizeRoad(eff.getTile(-1, 0));
174  if (wTile == RAILHPOWERV ||
175  wTile == HRAIL ||
176  (wTile > VRAIL && wTile < VRAILROAD))
177  {
178  eff.setTile(0, 0, HRAIL);
179  break;
180  }
181  }
182 
183  // check south
184  {
185  char sTile = neutralizeRoad(eff.getTile(0, 1));
186  if (sTile == RAILVPOWERH ||
187  sTile == VRAILROAD ||
188  (sTile > HRAIL && sTile < HRAILROAD))
189  {
190  eff.setTile(0, 0, VRAIL);
191  break;
192  }
193  }
194 
195  // check north
196  {
197  char nTile = neutralizeRoad(eff.getTile(0, -1));
198  if (nTile == RAILVPOWERH ||
199  nTile == VRAILROAD ||
200  (nTile > HRAIL && nTile < HRAILROAD))
201  {
202  eff.setTile(0, 0, VRAIL);
203  break;
204  }
205  }
206 
207  // cannot do road here
208  return false;
209 
210  case LHPOWER: // rail on power
211  eff.setTile(0, 0, RAILVPOWERH);
212  break;
213 
214  case LVPOWER: // rail on power
215  eff.setTile(0, 0, RAILHPOWERV);
216  break;
217 
218  case TileConstants.ROADS: // rail on road (case 1)
219  eff.setTile(0, 0, VRAILROAD);
220  break;
221 
222  case ROADS2: // rail on road (case 2)
223  eff.setTile(0, 0, HRAILROAD);
224  break;
225 
226  default:
227  if (tile != DIRT) {
228  if (city.autoBulldoze && canAutoBulldozeRRW(tile)) {
229  cost += 1; //autodoze cost
230  }
231  else {
232  // cannot do rail here
233  return false;
234  }
235  }
236 
237  //rail on dirt
238  eff.setTile(0, 0, LHRAIL);
239  break;
240  }
241 
242  eff.spend(cost);
243  return true;
244  }
245 
246  private boolean layRoad(ToolEffectIfc eff)
247  {
248  final int ROAD_COST = 10;
249  final int BRIDGE_COST = 50;
250 
251  int cost = ROAD_COST;
252 
253  char tile = (char) eff.getTile(0, 0);
254  switch (tile)
255  {
256  case RIVER: // road on water
257  case REDGE:
258  case CHANNEL: // check how to build bridges, if possible.
259 
260  cost = BRIDGE_COST;
261 
262  // check east
263  {
264  char eTile = neutralizeRoad(eff.getTile(1, 0));
265  if (eTile == VRAILROAD ||
266  eTile == HBRIDGE ||
267  (eTile >= TileConstants.ROADS && eTile <= HROADPOWER))
268  {
269  eff.setTile(0, 0, HBRIDGE);
270  break;
271  }
272  }
273 
274  // check west
275  {
276  char wTile = neutralizeRoad(eff.getTile(-1, 0));
277  if (wTile == VRAILROAD ||
278  wTile == HBRIDGE ||
279  (wTile >= TileConstants.ROADS && wTile <= INTERSECTION))
280  {
281  eff.setTile(0, 0, HBRIDGE);
282  break;
283  }
284  }
285 
286  // check south
287  {
288  char sTile = neutralizeRoad(eff.getTile(0, 1));
289  if (sTile == HRAILROAD ||
290  sTile == VROADPOWER ||
291  (sTile >= VBRIDGE && sTile <= INTERSECTION))
292  {
293  eff.setTile(0, 0, VBRIDGE);
294  break;
295  }
296  }
297 
298  // check north
299  {
300  char nTile = neutralizeRoad(eff.getTile(0, -1));
301  if (nTile == HRAILROAD ||
302  nTile == VROADPOWER ||
303  (nTile >= VBRIDGE && nTile <= INTERSECTION))
304  {
305  eff.setTile(0, 0, VBRIDGE);
306  break;
307  }
308  }
309 
310  // cannot do road here
311  return false;
312 
313  case LHPOWER: //road on power
314  eff.setTile(0, 0, VROADPOWER);
315  break;
316 
317  case LVPOWER: //road on power #2
318  eff.setTile(0, 0, HROADPOWER);
319  break;
320 
321  case LHRAIL: //road on rail
322  eff.setTile(0, 0, HRAILROAD);
323  break;
324 
325  case LVRAIL: //road on rail #2
326  eff.setTile(0, 0, VRAILROAD);
327  break;
328 
329  default:
330  if (tile != DIRT) {
331  if (city.autoBulldoze && canAutoBulldozeRRW(tile)) {
332  cost += 1; //autodoze cost
333  }
334  else {
335  // cannot do road here
336  return false;
337  }
338  }
339 
340  // road on dirt;
341  // just build a plain road, fixZone will fix it.
342  eff.setTile(0, 0, TileConstants.ROADS);
343  break;
344  }
345 
346  eff.spend(cost);
347  return true;
348  }
349 
350  private boolean layWire(ToolEffectIfc eff)
351  {
352  final int WIRE_COST = 5;
353  final int UNDERWATER_WIRE_COST = 25;
354 
355  int cost = WIRE_COST;
356 
357  char tile = (char) eff.getTile(0, 0);
358  tile = neutralizeRoad(tile);
359 
360  switch (tile)
361  {
362  case RIVER: // wire on water
363  case REDGE:
364  case CHANNEL:
365 
366  cost = UNDERWATER_WIRE_COST;
367 
368  // check east
369  {
370  int tmp = eff.getTile(1, 0);
371  char tmpn = neutralizeRoad(tmp);
372 
373  if (isConductive(tmp) &&
374  tmpn != HROADPOWER &&
375  tmpn != RAILHPOWERV &&
376  tmpn != HPOWER)
377  {
378  eff.setTile(0, 0, VPOWER);
379  break;
380  }
381  }
382 
383  // check west
384  {
385  int tmp = eff.getTile(-1, 0);
386  char tmpn = neutralizeRoad(tmp);
387 
388  if (isConductive(tmp) &&
389  tmpn != HROADPOWER &&
390  tmpn != RAILHPOWERV &&
391  tmpn != HPOWER)
392  {
393  eff.setTile(0, 0, VPOWER);
394  break;
395  }
396  }
397 
398  // check south
399  {
400  int tmp = eff.getTile(0, 1);
401  char tmpn = neutralizeRoad(tmp);
402 
403  if (isConductive(tmp) &&
404  tmpn != VROADPOWER &&
405  tmpn != RAILVPOWERH &&
406  tmpn != VPOWER)
407  {
408  eff.setTile(0, 0, HPOWER);
409  break;
410  }
411  }
412 
413  // check north
414  {
415  int tmp = eff.getTile(0, -1);
416  char tmpn = neutralizeRoad(tmp);
417 
418  if (isConductive(tmp) &&
419  tmpn != VROADPOWER &&
420  tmpn != RAILVPOWERH &&
421  tmpn != VPOWER)
422  {
423  eff.setTile(0, 0, HPOWER);
424  break;
425  }
426  }
427 
428  // cannot do wire here
429  return false;
430 
431  case TileConstants.ROADS: // wire on E/W road
432  eff.setTile(0, 0, HROADPOWER);
433  break;
434 
435  case ROADS2: // wire on N/S road
436  eff.setTile(0, 0, VROADPOWER);
437  break;
438 
439  case LHRAIL: // wire on E/W railroad tracks
440  eff.setTile(0, 0, RAILHPOWERV);
441  break;
442 
443  case LVRAIL: // wire on N/S railroad tracks
444  eff.setTile(0, 0, RAILVPOWERH);
445  break;
446 
447  default:
448  if (tile != DIRT) {
449  if (city.autoBulldoze && canAutoBulldozeRRW(tile)) {
450  cost += 1; //autodoze cost
451  }
452  else {
453  //cannot do wire here
454  return false;
455  }
456  }
457 
458  //wire on dirt
459  eff.setTile(0, 0, LHPOWER);
460  break;
461  }
462 
463  eff.spend(cost);
464  return true;
465  }
466 }