]> git.zerfleddert.de Git - micropolis/blob - src/sim/w_tool.c
Makefile: Micropolis build fixes for recent macOS
[micropolis] / src / sim / w_tool.c
1 /* w_tool.c
2 *
3 * Micropolis, Unix Version. This game was released for the Unix platform
4 * in or about 1990 and has been modified for inclusion in the One Laptop
5 * Per Child program. Copyright (C) 1989 - 2007 Electronic Arts Inc. If
6 * you need assistance with this program, you may contact:
7 * http://wiki.laptop.org/go/Micropolis or email micropolis@laptop.org.
8 *
9 * This program is free software: you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or (at
12 * your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details. You should have received a
18 * copy of the GNU General Public License along with this program. If
19 * not, see <http://www.gnu.org/licenses/>.
20 *
21 * ADDITIONAL TERMS per GNU GPL Section 7
22 *
23 * No trademark or publicity rights are granted. This license does NOT
24 * give you any right, title or interest in the trademark SimCity or any
25 * other Electronic Arts trademark. You may not distribute any
26 * modification of this program using the trademark SimCity or claim any
27 * affliation or association with Electronic Arts Inc. or its employees.
28 *
29 * Any propagation or conveyance of this program must include this
30 * copyright notice and these terms.
31 *
32 * If you convey this program (or any modifications of it) and assume
33 * contractual liability for the program to recipients of it, you agree
34 * to indemnify Electronic Arts for any liability that those contractual
35 * assumptions impose on Electronic Arts.
36 *
37 * You may not misrepresent the origins of this program; modified
38 * versions of the program must be marked as such and not identified as
39 * the original program.
40 *
41 * This disclaimer supplements the one included in the General Public
42 * License. TO THE FULLEST EXTENT PERMISSIBLE UNDER APPLICABLE LAW, THIS
43 * PROGRAM IS PROVIDED TO YOU "AS IS," WITH ALL FAULTS, WITHOUT WARRANTY
44 * OF ANY KIND, AND YOUR USE IS AT YOUR SOLE RISK. THE ENTIRE RISK OF
45 * SATISFACTORY QUALITY AND PERFORMANCE RESIDES WITH YOU. ELECTRONIC ARTS
46 * DISCLAIMS ANY AND ALL EXPRESS, IMPLIED OR STATUTORY WARRANTIES,
47 * INCLUDING IMPLIED WARRANTIES OF MERCHANTABILITY, SATISFACTORY QUALITY,
48 * FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT OF THIRD PARTY
49 * RIGHTS, AND WARRANTIES (IF ANY) ARISING FROM A COURSE OF DEALING,
50 * USAGE, OR TRADE PRACTICE. ELECTRONIC ARTS DOES NOT WARRANT AGAINST
51 * INTERFERENCE WITH YOUR ENJOYMENT OF THE PROGRAM; THAT THE PROGRAM WILL
52 * MEET YOUR REQUIREMENTS; THAT OPERATION OF THE PROGRAM WILL BE
53 * UNINTERRUPTED OR ERROR-FREE, OR THAT THE PROGRAM WILL BE COMPATIBLE
54 * WITH THIRD PARTY SOFTWARE OR THAT ANY ERRORS IN THE PROGRAM WILL BE
55 * CORRECTED. NO ORAL OR WRITTEN ADVICE PROVIDED BY ELECTRONIC ARTS OR
56 * ANY AUTHORIZED REPRESENTATIVE SHALL CREATE A WARRANTY. SOME
57 * JURISDICTIONS DO NOT ALLOW THE EXCLUSION OF OR LIMITATIONS ON IMPLIED
58 * WARRANTIES OR THE LIMITATIONS ON THE APPLICABLE STATUTORY RIGHTS OF A
59 * CONSUMER, SO SOME OR ALL OF THE ABOVE EXCLUSIONS AND LIMITATIONS MAY
60 * NOT APPLY TO YOU.
61 */
62 #include "sim.h"
63
64
65 short specialBase = CHURCH;
66 int OverRide = 0;
67 int Expensive = 1000;
68 int Players = 1;
69 int Votes = 0;
70 int PendingTool = -1;
71 int PendingX;
72 int PendingY;
73
74
75 QUAD CostOf[] = {
76 100, 100, 100, 500,
77 0, 500, 5, 1,
78 20, 10, 0, 0,
79 5000, 10, 3000, 3000,
80 5000, 10000, 100, 0,
81 };
82
83
84 short toolSize[] = {
85 3, 3, 3, 3,
86 1, 3, 1, 1,
87 1, 1, 0, 0,
88 4, 1, 4, 4,
89 4, 6, 1, 0,
90 };
91
92
93 short toolOffset[] = {
94 1, 1, 1, 1,
95 0, 1, 0, 0,
96 0, 0, 0, 0,
97 1, 0, 1, 1,
98 1, 1, 0, 0,
99 };
100
101
102 QUAD toolColors[] = {
103 COLOR_LIGHTGREEN | (COLOR_LIGHTGREEN << 8), /* residentialState */
104 COLOR_LIGHTBLUE | (COLOR_LIGHTBLUE << 8), /* commercialState */
105 COLOR_YELLOW | (COLOR_YELLOW << 8), /* industrialState */
106 COLOR_LIGHTGREEN | (COLOR_RED << 8), /* fireState */
107 COLOR_ORANGE | (COLOR_ORANGE << 8), /* queryState */
108 COLOR_LIGHTGREEN | (COLOR_LIGHTBLUE << 8), /* policeState */
109 COLOR_DARKGRAY | (COLOR_YELLOW << 8), /* wireState */
110 COLOR_LIGHTBROWN | (COLOR_LIGHTBROWN << 8), /* dozeState */
111 COLOR_DARKGRAY | (COLOR_OLIVE << 8), /* rrState */
112 COLOR_DARKGRAY | (COLOR_WHITE << 8), /* roadState */
113 COLOR_LIGHTGRAY | (COLOR_LIGHTGRAY << 8), /* chalkState */
114 COLOR_DARKGRAY | (COLOR_DARKGRAY << 8), /* eraserState */
115 COLOR_LIGHTGRAY | (COLOR_LIGHTGREEN << 8), /* stadiumState */
116 COLOR_LIGHTBROWN | (COLOR_LIGHTGREEN << 8), /* parkState */
117 COLOR_LIGHTGRAY | (COLOR_LIGHTBLUE << 8), /* seaportState */
118 COLOR_LIGHTGRAY | (COLOR_YELLOW << 8), /* powerState */
119 COLOR_LIGHTGRAY | (COLOR_YELLOW << 8), /* nuclearState */
120 COLOR_LIGHTGRAY | (COLOR_LIGHTBROWN << 8), /* airportState */
121 COLOR_LIGHTGRAY | (COLOR_RED << 8), /* networkState */
122 };
123
124
125 Ink *NewInk();
126
127 void DoSetWandState(SimView *view, short state);
128 void DoPendTool(SimView *view, int tool, int x, int y);
129 void EraserTo(SimView *view, int x, int y);
130 void EraserStart(SimView *view, int x, int y);
131 void DoShowZoneStatus(char *str, char *s0, char *s1, char *s2, char *s3, char *s4, int x, int y);
132
133
134 /*************************************************************************/
135 /* UTILITIES */
136
137
138 void
139 setWandState(SimView *view, short state)
140 {
141 #if 0
142 if (state < 0) {
143 specialBase = -state;
144 state = specialState;
145 }
146 #endif
147
148 view->tool_state = state;
149 DoUpdateHeads();
150 DoSetWandState(view, state);
151 }
152
153
154 int
155 putDownPark(SimView *view, short mapH, short mapV)
156 {
157 short value, tile;
158
159 if (TotalFunds - CostOf[parkState] >= 0) {
160 value = Rand(4);
161
162 if (value == 4)
163 tile = FOUNTAIN | BURNBIT | BULLBIT | ANIMBIT;
164 else
165 tile = (value + WOODS2) | BURNBIT | BULLBIT;
166
167 if (Map[mapH][mapV] == 0) {
168 Spend(CostOf[parkState]);
169 UpdateFunds();
170 Map[mapH][mapV] = tile;
171 return 1;
172 }
173 return -1;
174 }
175 return -2;
176 }
177
178
179 int
180 putDownNetwork(SimView *view, short mapH, short mapV)
181 {
182 int tile = Map[mapH][mapV] & LOMASK;
183
184 if ((TotalFunds > 0) && tally(tile)) {
185 Map[mapH][mapV] = tile = 0;
186 Spend(1);
187 }
188
189 if (tile == 0) {
190 if ((TotalFunds - CostOf[view->tool_state]) >= 0) {
191 Map[mapH][mapV] = TELEBASE | CONDBIT | BURNBIT | BULLBIT | ANIMBIT;
192 Spend(CostOf[view->tool_state]);
193 return 1;
194 } else {
195 return -2;
196 }
197 } else {
198 return -1;
199 }
200 }
201
202
203 short
204 checkBigZone(short id, short *deltaHPtr, short *deltaVPtr)
205 {
206 switch (id) {
207 case POWERPLANT: /* check coal plant */
208 case PORT: /* check sea port */
209 case NUCLEAR: /* check nuc plant */
210 case STADIUM: /* check stadium */
211 *deltaHPtr = 0; *deltaVPtr = 0; return (4);
212
213 case POWERPLANT + 1: /* check coal plant */
214 case COALSMOKE3: /* check coal plant, smoke */
215 case COALSMOKE3 + 1: /* check coal plant, smoke */
216 case COALSMOKE3 + 2: /* check coal plant, smoke */
217 case PORT + 1: /* check sea port */
218 case NUCLEAR + 1: /* check nuc plant */
219 case STADIUM + 1: /* check stadium */
220 *deltaHPtr = -1; *deltaVPtr = 0; return (4);
221
222 case POWERPLANT + 4: /* check coal plant */
223 case PORT + 4: /* check sea port */
224 case NUCLEAR + 4: /* check nuc plant */
225 case STADIUM + 4: /* check stadium */
226 *deltaHPtr = 0; *deltaVPtr = -1; return (4);
227
228 case POWERPLANT + 5: /* check coal plant */
229 case PORT + 5: /* check sea port */
230 case NUCLEAR + 5: /* check nuc plant */
231 case STADIUM + 5: /* check stadium */
232 *deltaHPtr = -1; *deltaVPtr = -1; return (4);
233
234 /* check airport */
235 /*** first row ***/
236 case AIRPORT:
237 *deltaHPtr = 0; *deltaVPtr = 0; return (6);
238 case AIRPORT + 1:
239 *deltaHPtr = -1; *deltaVPtr = 0; return (6);
240 case AIRPORT + 2:
241 *deltaHPtr = -2; *deltaVPtr = 0; return (6);
242 case AIRPORT + 3:
243 *deltaHPtr = -3; *deltaVPtr = 0; return (6);
244
245 /*** second row ***/
246 case AIRPORT + 6:
247 *deltaHPtr = 0; *deltaVPtr = -1; return (6);
248 case AIRPORT + 7:
249 *deltaHPtr = -1; *deltaVPtr = -1; return (6);
250 case AIRPORT + 8:
251 *deltaHPtr = -2; *deltaVPtr = -1; return (6);
252 case AIRPORT + 9:
253 *deltaHPtr = -3; *deltaVPtr = -1; return (6);
254
255 /*** third row ***/
256 case AIRPORT + 12:
257 *deltaHPtr = 0; *deltaVPtr = -2; return (6);
258 case AIRPORT + 13:
259 *deltaHPtr = -1; *deltaVPtr = -2; return (6);
260 case AIRPORT + 14:
261 *deltaHPtr = -2; *deltaVPtr = -2; return (6);
262 case AIRPORT + 15:
263 *deltaHPtr = -3; *deltaVPtr = -2; return (6);
264
265 /*** fourth row ***/
266 case AIRPORT + 18:
267 *deltaHPtr = 0; *deltaVPtr = -3; return (6);
268 case AIRPORT + 19:
269 *deltaHPtr = -1; *deltaVPtr = -3; return (6);
270 case AIRPORT + 20:
271 *deltaHPtr = -2; *deltaVPtr = -3; return (6);
272 case AIRPORT + 21:
273 *deltaHPtr = -3; *deltaVPtr = -3; return (6);
274
275 default:
276 *deltaHPtr = 0; *deltaVPtr = 0; return (0);
277 }
278 }
279
280
281 short
282 tally(short tileValue)
283 {
284 /* can we autobulldoze this tile? */
285 if (((tileValue >= FIRSTRIVEDGE) &&
286 (tileValue <= LASTRUBBLE)) ||
287 ((tileValue >= (POWERBASE + 2)) &&
288 (tileValue <= (POWERBASE + 12))) ||
289 ((tileValue >= TINYEXP) &&
290 (tileValue <= (LASTTINYEXP + 2)))) { /* ??? */
291 return (1);
292 } else {
293 return (0);
294 }
295 }
296
297
298 short
299 checkSize(short temp)
300 {
301 /* check for the normal com, resl, ind 3x3 zones & the fireDept & PoliceDept */
302 if (((temp >= (RESBASE - 1)) && (temp <= (PORTBASE - 1))) ||
303 ((temp >= (LASTPOWERPLANT + 1)) && (temp <= (POLICESTATION + 4)))) {
304 return (3);
305 } else if (((temp >= PORTBASE) && (temp <= LASTPORT)) ||
306 ((temp >= COALBASE) && (temp <= LASTPOWERPLANT)) ||
307 ((temp >= STADIUMBASE) && (temp <= LASTZONE))) {
308 return (4);
309 }
310 return (0);
311 }
312
313
314 /* 3x3 */
315
316
317 void
318 check3x3border(short xMap, short yMap)
319 {
320 short xPos, yPos;
321 short cnt;
322
323 xPos = xMap; yPos = yMap - 1;
324 for (cnt = 0; cnt < 3; cnt++) {
325 /*** this will do the upper bordering row ***/
326 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
327 xPos++;
328 }
329
330 xPos = xMap - 1; yPos = yMap;
331 for (cnt = 0; cnt < 3; cnt++) {
332 /*** this will do the left bordering row ***/
333 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
334 yPos++;
335 }
336
337 xPos = xMap; yPos = yMap + 3;
338 for (cnt = 0; cnt < 3; cnt++) {
339 /*** this will do the bottom bordering row ***/
340 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
341 xPos++;
342 }
343
344 xPos = xMap + 3; yPos = yMap;
345 for (cnt = 0; cnt < 3; cnt++) {
346 /*** this will do the right bordering row ***/
347 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
348 yPos++;
349 }
350 }
351
352
353 int
354 check3x3(SimView *view, short mapH, short mapV, short base, short tool)
355 {
356 register short rowNum, columnNum;
357 register short holdMapH, holdMapV;
358 short xPos, yPos;
359 short cost = 0;
360 short tileValue;
361 short flag;
362
363 mapH--; mapV--;
364 if ((mapH < 0) || (mapH > (WORLD_X - 3)) ||
365 (mapV < 0) || (mapV > (WORLD_Y - 3))) {
366 return -1;
367 }
368
369 xPos = holdMapH = mapH;
370 yPos = holdMapV = mapV;
371
372 flag = 1;
373
374 for (rowNum = 0; rowNum <= 2; rowNum++) {
375 mapH = holdMapH;
376
377 for (columnNum = 0; columnNum <= 2; columnNum++) {
378 tileValue = Map[mapH++][mapV] & LOMASK;
379
380 if (autoBulldoze) {
381 /* if autoDoze is enabled, add up the cost of bulldozed tiles */
382 if (tileValue != 0) {
383 if (tally(tileValue)) {
384 cost++;
385 } else {
386 flag = 0;
387 }
388 }
389 } else {
390 /* check and see if the tile is clear or not */
391 if (tileValue != 0) {
392 flag = 0;
393 }
394 }
395 }
396 mapV++;
397 }
398
399 if (flag == 0) {
400 return -1;
401 }
402
403 cost += CostOf[tool];
404
405 if ((TotalFunds - cost) < 0) {
406 return -2;
407 }
408
409 if ((Players > 1) &&
410 (OverRide == 0) &&
411 (cost >= Expensive) &&
412 (view != NULL) &&
413 (view->super_user == 0)) {
414 return -3;
415 }
416
417 /* take care of the money situtation here */
418 Spend(cost);
419 UpdateFunds();
420
421 mapV = holdMapV;
422
423 for (rowNum = 0; rowNum <= 2; rowNum++) {
424 mapH = holdMapH;
425
426 for (columnNum = 0; columnNum <= 2; columnNum++) {
427 if (columnNum == 1 && rowNum == 1) {
428 Map[mapH++][mapV] = base + BNCNBIT + ZONEBIT;
429 } else {
430 Map[mapH++][mapV] = base + BNCNBIT;
431 }
432 base++;
433 }
434 mapV++;
435 }
436 check3x3border(xPos, yPos);
437 return 1;
438 }
439
440
441 /* 4x4 */
442
443
444 void
445 check4x4border(short xMap, short yMap)
446 {
447 short *tilePtr;
448 short xPos, yPos;
449 short cnt;
450
451 xPos = xMap; yPos = yMap - 1;
452 for (cnt = 0; cnt < 4; cnt++) {
453 /* this will do the upper bordering row */
454 tilePtr = &Map[xPos][yPos];
455 ConnecTile(xPos, yPos, tilePtr, 0);
456 xPos++;
457 }
458
459 xPos = xMap - 1; yPos = yMap;
460 for (cnt = 0; cnt < 4; cnt++) {
461 /* this will do the left bordering row */
462 tilePtr = &Map[xPos][yPos];
463 ConnecTile(xPos, yPos, tilePtr, 0);
464 yPos++;
465 }
466
467 xPos = xMap; yPos = yMap + 4;
468 for (cnt = 0; cnt < 4;cnt++) {
469 /* this will do the bottom bordering row */
470 tilePtr = &Map[xPos][yPos];
471 ConnecTile(xPos, yPos, tilePtr, 0);
472 xPos++;
473 }
474
475 xPos = xMap + 4; yPos = yMap;
476 for (cnt = 0; cnt < 4; cnt++) {
477 /* this will do the right bordering row */
478 tilePtr = &Map[xPos][yPos];
479 ConnecTile(xPos, yPos, tilePtr, 0);
480 yPos++;
481 }
482 }
483
484
485 short
486 check4x4(SimView *view, short mapH, short mapV,
487 short base, short aniFlag, short tool)
488 {
489 register short rowNum, columnNum;
490 short h, v;
491 short holdMapH;
492 short xMap, yMap;
493 short tileValue;
494 short flag;
495 short cost = 0;
496
497 mapH--; mapV--;
498 if ((mapH < 0) || (mapH > (WORLD_X - 4)) ||
499 (mapV < 0) || (mapV > (WORLD_Y - 4))) {
500 return -1;
501 }
502
503 h = xMap = holdMapH = mapH;
504 v = yMap = mapV;
505
506 flag = 1;
507
508 for (rowNum = 0; rowNum <= 3; rowNum++) {
509 mapH = holdMapH;
510
511 for (columnNum = 0; columnNum <= 3; columnNum++) {
512 tileValue = Map[mapH++][mapV] & LOMASK;
513
514 if (autoBulldoze) {
515 /* if autoDoze is enabled, add up the cost of bulldozed tiles */
516 if (tileValue != 0) {
517 if (tally(tileValue)) {
518 cost++;
519 } else {
520 flag = 0;
521 }
522 }
523 } else {
524 /* check and see if the tile is clear or not */
525 if (tileValue != 0) {
526 flag = 0;
527 }
528 }
529 }
530 mapV++;
531 }
532
533 if (flag == 0) {
534 return -1;
535 }
536
537 cost += CostOf[tool];
538
539 if ((TotalFunds - cost) < 0) {
540 return -2;
541 }
542
543 if ((Players > 1) &&
544 (OverRide == 0) &&
545 (cost >= Expensive) &&
546 (view != NULL) &&
547 (view->super_user == 0)) {
548 return -3;
549 }
550
551 /* take care of the money situtation here */
552 Spend(cost);
553 UpdateFunds();
554
555 mapV = v; holdMapH = h;
556
557 for (rowNum = 0; rowNum <= 3; rowNum++) {
558 mapH = holdMapH;
559
560 for (columnNum = 0; columnNum <= 3; columnNum++) {
561 if (columnNum == 1 && rowNum == 1)
562 Map[mapH++][mapV] = base + BNCNBIT + ZONEBIT;
563 else if (columnNum == 1 && rowNum == 2 && aniFlag)
564 Map[mapH++][mapV] = base + BNCNBIT + ANIMBIT;
565 else
566 Map[mapH++][mapV] = base + BNCNBIT;
567 base++;
568 }
569 mapV++;
570 }
571 check4x4border(xMap, yMap);
572 return 1;
573 }
574
575
576 /* 6x6 */
577
578
579 void
580 check6x6border(short xMap, short yMap)
581 {
582 short xPos, yPos;
583 short cnt;
584
585 xPos = xMap; yPos = yMap - 1;
586 for (cnt = 0; cnt < 6; cnt++) {
587 /* this will do the upper bordering row */
588 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
589 xPos++;
590 }
591
592 xPos = xMap - 1; yPos = yMap;
593 for (cnt=0; cnt < 6; cnt++) {
594 /* this will do the left bordering row */
595 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
596 yPos++;
597 }
598
599 xPos = xMap; yPos = yMap + 6;
600 for (cnt = 0; cnt < 6; cnt++) {
601 /* this will do the bottom bordering row */
602 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
603 xPos++;
604 }
605
606 xPos = xMap + 6; yPos = yMap;
607 for (cnt = 0; cnt < 6; cnt++) {
608 /* this will do the right bordering row */
609 ConnecTile(xPos, yPos, &Map[xPos][yPos], 0);
610 yPos++;
611 }
612 }
613
614
615 short
616 check6x6(SimView *view, short mapH, short mapV, short base, short tool)
617 {
618 register short rowNum, columnNum;
619 short h, v;
620 short holdMapH;
621 short xMap, yMap;
622 short flag;
623 short tileValue;
624 short cost = 0;
625
626 mapH--; mapV--;
627 if ((mapH < 0) || (mapH > (WORLD_X - 6)) ||
628 (mapV < 0) || (mapV > (WORLD_Y - 6)))
629 return -1;
630
631 h = xMap = holdMapH = mapH;
632 v = yMap = mapV;
633
634 flag = 1;
635
636 for (rowNum = 0; rowNum <= 5; rowNum++) {
637 mapH = holdMapH;
638
639 for (columnNum = 0; columnNum <= 5; columnNum++) {
640 tileValue = Map[mapH++][mapV] & LOMASK;
641
642 if (autoBulldoze) {
643 /* if autoDoze is enabled, add up the cost of bulldozed tiles */
644 if (tileValue != 0) {
645 if (tally(tileValue)) {
646 cost++;
647 } else {
648 flag = 0;
649 }
650 }
651 } else {
652 /* check and see if the tile is clear or not */
653 if (tileValue != 0) {
654 flag = 0;
655 }
656 }
657 }
658 mapV++;
659 }
660
661 if (flag == 0) {
662 return -1;
663 }
664
665 cost += CostOf[tool];
666
667 if ((TotalFunds - cost) < 0) {
668 return -2;
669 }
670
671 if ((Players > 1) &&
672 (OverRide == 0) &&
673 (cost >= Expensive) &&
674 (view != NULL) &&
675 (view->super_user == 0)) {
676 return -3;
677 }
678
679 /* take care of the money situtation here */
680 Spend(cost);
681 UpdateFunds();
682
683 mapV = v; holdMapH = h;
684
685 for (rowNum = 0; rowNum <= 5; rowNum++) {
686 mapH = holdMapH;
687
688 for (columnNum = 0; columnNum <= 5; columnNum++) {
689 if (columnNum == 1 && rowNum == 1) {
690 Map[mapH++][mapV] = base + BNCNBIT + ZONEBIT;
691 } else {
692 Map[mapH++][mapV] = base + BNCNBIT;
693 }
694 base++;
695 }
696 mapV++;
697 }
698 check6x6border(xMap, yMap);
699 return 1;
700 }
701
702
703 /* QUERY */
704
705
706 /* search table for zone status string match */
707 static short idArray[28] = {
708 DIRT, RIVER, TREEBASE, RUBBLE,
709 FLOOD, RADTILE, FIRE, ROADBASE,
710 POWERBASE, RAILBASE, RESBASE, COMBASE,
711 INDBASE, PORTBASE, AIRPORTBASE, COALBASE,
712 FIRESTBASE, POLICESTBASE, STADIUMBASE, NUCLEARBASE,
713 827, 832, FOUNTAIN, INDBASE2,
714 FOOTBALLGAME1, VBRDG0, 952, 956
715 };
716
717 /*
718 0, 2, 21, 44,
719 48, 52, 53, 64,
720 208, 224, 240, 423,
721 612, 693, 709, 745,
722 761, 770, 779, 811,
723 827, 832, 840, 844,
724 932, 948, 952, 956
725
726 Clear, Water, Trees, Rubble,
727 Flood, Radioactive Waste, Fire, Road,
728 Power, Rail, Residential, Commercial,
729 Industrial, Port, AirPort, Coal Power,
730 Fire Department, Police Department, Stadium, Nuclear Power,
731 Draw Bridge, Radar Dish, Fountain, Industrial,
732 49er's 38 Bears 3, Draw Bridge, Ur 238
733 */
734
735
736 int getDensityStr(short catNo, short mapH, short mapV)
737 {
738 int z;
739
740 switch(catNo) {
741 case 0:
742 z = PopDensity[mapH >>1][mapV >>1];
743 z = z >> 6;
744 z = z & 3;
745 return (z);
746 case 1:
747 z = LandValueMem[mapH >>1][mapV >>1];
748 if (z < 30) return (4);
749 if (z < 80) return (5);
750 if (z < 150) return (6);
751 return (7);
752 case 2:
753 z = CrimeMem[mapH >>1][mapV >>1];
754 z = z >> 6;
755 z = z & 3;
756 return (z + 8);
757 case 3:
758 z = PollutionMem[mapH >>1][mapV >>1];
759 if ((z < 64) && (z > 0)) return (13);
760 z = z >> 6;
761 z = z & 3;
762 return (z + 12);
763 case 4:
764 z = RateOGMem[mapH >>3][mapV >>3];
765 if (z < 0) return (16);
766 if (z == 0) return (17);
767 if (z > 100) return (19);
768 return (18);
769 }
770 return 0;
771 }
772
773
774 void
775 doZoneStatus(short mapH, short mapV)
776 {
777 char localStr[256];
778 char statusStr[5][256];
779 short id;
780 short x;
781 short tileNum;
782 short found;
783
784 tileNum = Map[mapH][mapV] & LOMASK;
785
786 if (tileNum >= COALSMOKE1 && tileNum < FOOTBALLGAME1)
787 tileNum = COALBASE;
788
789 found = 1;
790 for (x = 1; x < 29 && found; x++) {
791 if (tileNum < idArray[x]) {
792 found = 0;
793 }
794 }
795 x--;
796
797 if (x < 1 || x > 28)
798 x = 28;
799
800 GetIndString(localStr, 219, x);
801
802 for (x = 0; x < 5; x++) {
803 id = getDensityStr(x, mapH, mapV);
804 id++;
805 if (id <= 0) id = 1;
806 if (id > 20) id = 20;
807 GetIndString(statusStr[x], 202, id);
808 }
809
810 DoShowZoneStatus(localStr, statusStr[0], statusStr[1],
811 statusStr[2], statusStr[3], statusStr[4], mapH, mapV);
812 }
813
814
815 void
816 DoShowZoneStatus(char *str, char *s0, char *s1, char *s2, char *s3, char *s4,
817 int x, int y)
818 {
819 char buf[1024];
820
821 sprintf(buf, "UIShowZoneStatus {%s} {%s} {%s} {%s} {%s} {%s} %d %d",
822 str, s0, s1, s2, s3, s4, x, y);
823 Eval(buf);
824 }
825
826
827 /* comefrom: processWand */
828 void
829 put3x3Rubble(short x, short y)
830 {
831 register int xx, yy, zz;
832
833 for (xx = x - 1; xx < x + 2; xx++) {
834 for (yy = y - 1; yy < y + 2; yy++) {
835 if (TestBounds(xx, yy)) {
836 zz = Map[xx][yy] & LOMASK;
837 if ((zz != RADTILE) && (zz != 0)) {
838 Map[xx][yy] =
839 (DoAnimation
840 ? (TINYEXP + Rand(2))
841 : SOMETINYEXP)
842 | ANIMBIT | BULLBIT;
843 }
844 }
845 }
846 }
847 }
848
849
850 /* comefrom: processWand */
851 void
852 put4x4Rubble(short x, short y)
853 {
854 register int xx, yy, zz;
855
856 for (xx = x - 1; xx < x + 3; xx++) {
857 for (yy = y - 1; yy < y + 3; yy++) {
858 if (TestBounds(xx, yy)) {
859 zz = Map[xx][yy] & LOMASK;
860 if ((zz != RADTILE) && (zz != 0)) {
861 Map[xx][yy] =
862 (DoAnimation
863 ? (TINYEXP + Rand(2))
864 : SOMETINYEXP)
865 | ANIMBIT | BULLBIT;
866 }
867 }
868 }
869 }
870 }
871
872
873 /* comefrom: processWand */
874 void
875 put6x6Rubble(short x, short y)
876 {
877 register int xx, yy, zz;
878
879 for (xx = x - 1; xx < x + 5; xx++) {
880 for (yy = y - 1; yy < y + 5; yy++) {
881 if (TestBounds(xx, yy)) {
882 zz = Map[xx][yy] & LOMASK;
883 if ((zz != RADTILE) && (zz != 0)) {
884 Map[xx][yy] =
885 (DoAnimation
886 ? (TINYEXP + Rand(2))
887 : SOMETINYEXP)
888 | ANIMBIT | BULLBIT;
889 }
890 }
891 }
892 }
893 }
894
895
896 void
897 DidTool(SimView *view, char *name, short x, short y)
898 {
899 char buf[256];
900
901 if (view != NULL) {
902 sprintf(buf, "UIDidTool%s %s %d %d",
903 name, Tk_PathName(view->tkwin), x, y);
904 Eval(buf);
905 }
906 }
907
908
909 void
910 DoSetWandState(SimView *view, short state)
911 {
912 char buf[256];
913
914 sprintf(buf, "UISetToolState %s %d", Tk_PathName(view->tkwin), state);
915 Eval(buf);
916 }
917
918
919 /************************************************************************/
920 /* TOOLS */
921
922
923 int
924 query_tool(SimView *view, short x, short y)
925 {
926 if ((x < 0) || (x > (WORLD_X - 1)) ||
927 (y < 0) || (y > (WORLD_Y - 1))) {
928 return -1;
929 }
930
931 doZoneStatus(x, y);
932 DidTool(view, "Qry", x, y);
933 return 1;
934 }
935
936
937 int
938 bulldozer_tool(SimView *view, short x, short y)
939 {
940 unsigned short currTile, temp;
941 short zoneSize, deltaH, deltaV;
942 int result = 1;
943
944 if ((x < 0) || (x > (WORLD_X - 1)) ||
945 (y < 0) || (y > (WORLD_Y - 1))) {
946 return -1;
947 }
948
949 currTile = Map[x][y];
950 temp = currTile & LOMASK;
951
952 if (currTile & ZONEBIT) { /* zone center bit is set */
953 if (TotalFunds > 0) {
954 Spend(1);
955 switch (checkSize(temp)) {
956 case 3:
957 MakeSound("city", "Explosion-High");
958 put3x3Rubble(x, y);
959 break;
960
961 case 4:
962 put4x4Rubble(x, y);
963 MakeSound("city", "Explosion-Low");
964 break;
965
966 case 6:
967 MakeSound("city", "Explosion-High");
968 MakeSound("city", "Explosion-Low");
969 put6x6Rubble(x, y);
970 break;
971
972 default:
973 break;
974 }
975 }
976 } else if ((zoneSize = checkBigZone(temp, &deltaH, &deltaV))) {
977 if (TotalFunds > 0) {
978 Spend(1);
979 switch (zoneSize) {
980 case 3:
981 MakeSound("city", "Explosion-High");
982 break;
983
984 case 4:
985 MakeSound("city", "Explosion-Low");
986 put4x4Rubble(x + deltaH, y + deltaV);
987 break;
988
989 case 6:
990 MakeSound("city", "Explosion-High");
991 MakeSound("city", "Explosion-Low");
992 put6x6Rubble(x + deltaH, y + deltaV);
993 break;
994 }
995 }
996 } else {
997 if (temp == RIVER || temp == REDGE || temp == CHANNEL) {
998 if (TotalFunds >= 6) {
999 result = ConnecTile(x, y, &Map[x][y], 1);
1000 if (temp != (Map[x][y] & LOMASK)) {
1001 Spend(5);
1002 }
1003 } else {
1004 result = 0;
1005 }
1006 } else {
1007 result = ConnecTile(x, y, &Map[x][y], 1);
1008 }
1009 }
1010 UpdateFunds();
1011 if (result == 1) {
1012 DidTool(view, "Dozr", x, y);
1013 }
1014 return result;
1015 }
1016
1017
1018 int
1019 road_tool(SimView *view, short x, short y)
1020 {
1021 int result;
1022
1023 if ((x < 0) || (x > (WORLD_X - 1)) ||
1024 (y < 0) || (y > (WORLD_Y - 1))) {
1025 return -1;
1026 }
1027
1028 result = ConnecTile(x, y, &Map[x][y], 2);
1029 UpdateFunds();
1030 if (result == 1) {
1031 DidTool(view, "Road", x, y);
1032 }
1033 return result;
1034 }
1035
1036
1037 int
1038 rail_tool(SimView *view, short x, short y)
1039 {
1040 int result;
1041
1042 if ((x < 0) || (x > (WORLD_X - 1)) ||
1043 (y < 0) || (y > (WORLD_Y - 1))) {
1044 return -1;
1045 }
1046
1047 result = ConnecTile(x, y, &Map[x][y], 3);
1048 UpdateFunds();
1049 if (result == 1) {
1050 DidTool(view, "Rail", x, y);
1051 }
1052 return result;
1053 }
1054
1055
1056 int
1057 wire_tool(SimView *view, short x, short y)
1058 {
1059 int result;
1060
1061 if ((x < 0) || (x > (WORLD_X - 1)) ||
1062 (y < 0) || (y > (WORLD_Y - 1))) {
1063 return -1;
1064 }
1065
1066 result = ConnecTile(x, y, &Map[x][y], 4);
1067 UpdateFunds();
1068 if (result == 1) {
1069 DidTool(view, "Wire", x, y);
1070 }
1071 return result;
1072 }
1073
1074
1075 int
1076 park_tool(SimView *view, short x, short y)
1077 {
1078 int result;
1079
1080 if ((x < 0) || (x > (WORLD_X - 1)) ||
1081 (y < 0) || (y > (WORLD_Y - 1)))
1082 return -1;
1083
1084 result = putDownPark(view, x, y);
1085 if (result == 1) {
1086 DidTool(view, "Park", x, y);
1087 }
1088 return result;
1089 }
1090
1091
1092 int
1093 residential_tool(SimView *view, short x, short y)
1094 {
1095 int result;
1096
1097 if ((x < 0) || (x > (WORLD_X - 1)) ||
1098 (y < 0) || (y > (WORLD_Y - 1))) {
1099 return -1;
1100 }
1101
1102 result = check3x3(view, x, y, RESBASE, residentialState);
1103 if (result == 1) {
1104 DidTool(view, "Res", x, y);
1105 }
1106 return result;
1107 }
1108
1109
1110 int
1111 commercial_tool(SimView *view, short x, short y)
1112 {
1113 int result;
1114
1115 if ((x < 0) || (x > (WORLD_X - 1)) ||
1116 (y < 0) || (y > (WORLD_Y - 1))) {
1117 return -1;
1118 }
1119
1120 result = check3x3(view, x, y, COMBASE, commercialState);
1121 if (result == 1) {
1122 DidTool(view, "Com", x, y);
1123 }
1124 return result;
1125 }
1126
1127
1128 int
1129 industrial_tool(SimView *view, short x, short y)
1130 {
1131 int result;
1132
1133 if ((x < 0) || (x > (WORLD_X - 1)) ||
1134 (y < 0) || (y > (WORLD_Y - 1))) {
1135 return -1;
1136 }
1137
1138 result = check3x3(view, x, y, INDBASE, industrialState);
1139 if (result == 1) {
1140 DidTool(view, "Ind", x, y);
1141 }
1142 return result;
1143 }
1144
1145
1146 int
1147 police_dept_tool(SimView *view, short x, short y)
1148 {
1149 int result;
1150
1151 if ((x < 0) || (x > (WORLD_X - 1)) ||
1152 (y < 0) || (y > (WORLD_Y - 1))) {
1153 return -1;
1154 }
1155
1156 result = check3x3(view, x, y, POLICESTBASE, policeState);
1157 if (result == 1) {
1158 DidTool(view, "Pol", x, y);
1159 }
1160 return result;
1161 }
1162
1163
1164 int
1165 fire_dept_tool(SimView *view, short x, short y)
1166 {
1167 int result;
1168
1169 if ((x < 0) || (x > (WORLD_X - 1)) ||
1170 (y < 0) || (y > (WORLD_Y - 1))) {
1171 return -1;
1172 }
1173
1174 result = check3x3(view, x, y, FIRESTBASE, fireState);
1175 if (result == 1) {
1176 DidTool(view, "Fire", x, y);
1177 }
1178 return result;
1179 }
1180
1181
1182 int
1183 stadium_tool(SimView *view, short x, short y)
1184 {
1185 int result;
1186
1187 if ((x < 0) || (x > (WORLD_X - 1)) ||
1188 (y < 0) || (y > (WORLD_Y - 1))) {
1189 return -1;
1190 }
1191
1192 result = check4x4(view, x, y, STADIUMBASE, 0, stadiumState);
1193 if (result == 1) {
1194 DidTool(view, "Stad", x, y);
1195 }
1196 return result;
1197 }
1198
1199
1200 int
1201 coal_power_plant_tool(SimView *view, short x, short y)
1202 {
1203 int result;
1204
1205 if ((x < 0) || (x > (WORLD_X - 1)) ||
1206 (y < 0) || (y > (WORLD_Y - 1))) {
1207 return -1;
1208 }
1209
1210 result = check4x4(view, x, y, COALBASE, 1, powerState);
1211 if (result == 1) {
1212 DidTool(view, "Coal", x, y);
1213 }
1214 return result;
1215 }
1216
1217
1218 int
1219 nuclear_power_plant_tool(SimView *view, short x, short y)
1220 {
1221 int result;
1222
1223 if ((x < 0) || (x > (WORLD_X - 1)) ||
1224 (y < 0) || (y > (WORLD_Y - 1))) {
1225 return -1;
1226 }
1227
1228 result = check4x4(view, x, y, NUCLEARBASE, 1, nuclearState);
1229 if (result == 1) {
1230 DidTool(view, "Nuc", x, y);
1231 }
1232 return result;
1233 }
1234
1235
1236 int
1237 seaport_tool(SimView *view, short x, short y)
1238 {
1239 int result;
1240
1241 if ((x < 0) || (x > (WORLD_X - 1)) ||
1242 (y < 0) || (y > (WORLD_Y - 1))) {
1243 return -1;
1244 }
1245
1246 result = check4x4(view, x, y, PORTBASE, 0, seaportState);
1247 if (result == 1) {
1248 DidTool(view, "Seap", x, y);
1249 }
1250 return result;
1251 }
1252
1253
1254 int
1255 airport_tool(SimView *view, short x, short y)
1256 {
1257 int result;
1258
1259 if ((x < 0) || (x > (WORLD_X - 1)) ||
1260 (y < 0) || (y > (WORLD_Y - 1))) {
1261 return -1;
1262 }
1263
1264 result = check6x6(view, x, y, AIRPORTBASE, airportState);
1265 if (result == 1) {
1266 DidTool(view, "Airp", x, y);
1267 }
1268 return result;
1269 }
1270
1271
1272 int
1273 network_tool(SimView *view, short x, short y)
1274 {
1275 int result;
1276
1277 if ((x < 0) || (x > (WORLD_X - 1)) ||
1278 (y < 0) || (y > (WORLD_Y - 1))) {
1279 return -1;
1280 }
1281
1282 result = putDownNetwork(view, x, y);
1283 if (result == 1) {
1284 DidTool(view, "Net", x, y);
1285 }
1286 return result;
1287 }
1288
1289
1290 #if 0
1291 int
1292 special_tool(SimView *view, short x, short y)
1293 {
1294 int result;
1295
1296 if ((x < 0) || (x > (WORLD_X - 1)) ||
1297 (y < 0) || (y > (WORLD_Y - 1))) {
1298 return -1;
1299 }
1300
1301 result = check3x3(view, x, y, specialBase, specialState);
1302 if (result == 1) {
1303 DidTool(view, "Special", x, y);
1304 }
1305 return result;
1306 }
1307 #endif
1308
1309 int
1310 ChalkTool(SimView *view, short x, short y, short color, short first)
1311 {
1312 if (first) {
1313 ChalkStart(view, x, y, color);
1314 } else {
1315 ChalkTo(view, x, y);
1316 }
1317 DidTool(view, "Chlk", x, y);
1318 return 1;
1319 }
1320
1321
1322 void
1323 ChalkStart(SimView *view, int x, int y, int color)
1324 {
1325 Ink *ink;
1326 Ink **ip;
1327
1328 for (ip = &sim->overlay; *ip != NULL; ip = &((*ip)->next)) ;
1329
1330 *ip = ink = NewInk();
1331 ink->x = x; ink->y = y;
1332 ink->color = color;
1333 StartInk(ink, x, y);
1334 view->track_info = (char *)ink;
1335 view->last_x = x;
1336 view->last_y = y;
1337 view->tool_event_time = view->tool_last_event_time =
1338 ((TkWindow *)view->tkwin)->dispPtr->lastEventTime;
1339 }
1340
1341
1342 void
1343 ChalkTo(SimView *view, int x, int y)
1344 {
1345 #ifdef MOTIONBUFFER
1346 int x0, y0, lx, ly;
1347 #endif
1348 Ink *ink = (Ink *)view->track_info;
1349
1350 #ifdef MOTIONBUFFER
1351 if (view->x->dpy->motion_buffer) {
1352 XTimeCoord *coords = NULL, *coord;
1353 int n = 0, i;
1354
1355 view->tool_last_event_time = view->tool_event_time;
1356 view->tool_event_time =
1357 ((TkWindow *)view->tkwin)->dispPtr->lastEventTime;
1358
1359 coords = XGetMotionEvents(view->x->dpy,
1360 Tk_WindowId(view->tkwin),
1361 view->tool_last_event_time,
1362 view->tool_event_time,
1363 &n);
1364 #if 0
1365 printf("got %d events at %x from %d to %d (%d elapsed)\n",
1366 n, coords,
1367 view->tool_last_event_time, view->tool_event_time,
1368 view->tool_event_time - view->tool_last_event_time);
1369 #endif
1370 if (n) {
1371 lx = ink->last_x; ly = ink->last_y;
1372
1373 for (i = 0, coord = coords; i < n; i++, coord++) {
1374 ViewToPixelCoords(view, coord->x, coord->y, &x0, &y0);
1375 lx = (lx + lx + lx + x0) >>2;
1376 ly = (ly + ly + ly + y0) >>2;
1377 #if 0
1378 printf("adding %d %d => %d %d => %d %d\n",
1379 coord->x, coord->y, x0, y0, lx, ly);
1380 #endif
1381 AddInk(ink, lx, ly);
1382 }
1383 }
1384
1385 if (coords) {
1386 XFree((char *)coords);
1387 }
1388 }
1389 #endif
1390
1391 AddInk(ink, x, y);
1392 view->last_x = x;
1393 view->last_y = y;
1394 }
1395
1396
1397 int
1398 EraserTool(SimView *view, short x, short y, short first)
1399 {
1400 if (first) {
1401 EraserStart(view, x, y);
1402 } else {
1403 EraserTo(view, x, y);
1404 }
1405 DidTool(view, "Eraser", x, y);
1406 return 1;
1407 }
1408
1409
1410 int
1411 InkInBox(Ink *ink, int left, int top, int right, int bottom)
1412 {
1413 if ((left <= ink->right) &&
1414 (right >= ink->left) &&
1415 (top <= ink->bottom) &&
1416 (bottom >= ink->top)) {
1417 int x, y, lx, ly, i;
1418
1419 if (ink->length == 1) {
1420 return 1;
1421 }
1422
1423 x = ink->x; y = ink->y;
1424 for (i = 1; i < ink->length; i++) {
1425 int ileft, iright, itop, ibottom;
1426
1427 lx = x; ly = y;
1428 x += ink->points[i].x; y += ink->points[i].y;
1429 if (x < lx) { ileft = x; iright = lx; }
1430 else { ileft = lx; iright = x; }
1431 if (y < ly) { itop = y; ibottom = ly; }
1432 else { itop = ly; ibottom = y; }
1433 if ((left <= iright) &&
1434 (right >= ileft) &&
1435 (top <= ibottom) &&
1436 (bottom >= itop)) {
1437 return 1;
1438 }
1439 }
1440 }
1441 return 0;
1442 }
1443
1444
1445 void
1446 EraserStart(SimView *view, int x, int y)
1447 {
1448 EraserTo(view, x, y);
1449 }
1450
1451
1452 void
1453 EraserTo(SimView *view, int x, int y)
1454 {
1455 Ink **ip, *ink;
1456
1457 for (ip = &sim->overlay; *ip != NULL;) {
1458 ink = *ip;
1459 if (InkInBox(ink, x - 8, y - 8, x + 8, y + 8)) {
1460
1461 for (view = sim->editor; view != NULL; view = view->next) {
1462 int vleft, vtop;
1463
1464 if ((ink->right >= (vleft = (view->pan_x - (view->w_width / 2)))) &&
1465 (ink->left <= (vleft + view->w_width)) &&
1466 (ink->bottom >= (vtop = (view->pan_y - (view->w_height / 2)))) &&
1467 (ink->top <= (vtop + view->w_height))) {
1468 view->overlay_mode = 0;
1469 EventuallyRedrawView(view);
1470 }
1471 }
1472
1473 *ip = ink->next;
1474
1475 FreeInk(ink);
1476 } else {
1477 ip = &((*ip)->next);
1478 }
1479 }
1480 }
1481
1482
1483 int
1484 do_tool(SimView *view, short state, short x, short y, short first)
1485 {
1486 int result = 0;
1487
1488 switch (state) {
1489 case residentialState:
1490 result = residential_tool(view, x >>4, y >>4);
1491 break;
1492 case commercialState:
1493 result = commercial_tool(view, x >>4, y >>4);
1494 break;
1495 case industrialState:
1496 result = industrial_tool(view, x >>4, y >>4);
1497 break;
1498 case fireState:
1499 result = fire_dept_tool(view, x >>4, y >>4);
1500 break;
1501 case queryState:
1502 result = query_tool(view, x >>4, y >>4);
1503 break;
1504 case policeState:
1505 result = police_dept_tool(view, x >>4, y >>4);
1506 break;
1507 case wireState:
1508 result = wire_tool(view, x >>4, y >>4);
1509 break;
1510 case dozeState:
1511 result = bulldozer_tool(view, x >>4, y >>4);
1512 break;
1513 case rrState:
1514 result = rail_tool(view, x >>4, y >>4);
1515 break;
1516 case roadState:
1517 result = road_tool(view, x >>4, y >>4);
1518 break;
1519 case chalkState:
1520 result = ChalkTool(view, x - 5, y + 11, COLOR_WHITE, first);
1521 break;
1522 case eraserState:
1523 result = EraserTool(view, x, y, first);
1524 break;
1525 case stadiumState:
1526 result = stadium_tool(view, x >>4, y >>4);
1527 break;
1528 case parkState:
1529 result = park_tool(view, x >>4, y >>4);
1530 break;
1531 case seaportState:
1532 result = seaport_tool(view, x >>4, y >>4);
1533 break;
1534 case powerState:
1535 result = coal_power_plant_tool(view, x >>4, y >>4);
1536 break;
1537 case nuclearState:
1538 result = nuclear_power_plant_tool(view, x >>4, y >>4);
1539 break;
1540 case airportState:
1541 result = airport_tool(view, x >>4, y >>4);
1542 break;
1543 case networkState:
1544 result = network_tool(view, x >>4, y >>4);
1545 break;
1546
1547 default:
1548 result = 0;
1549 break;
1550 }
1551
1552 return result;
1553 }
1554
1555
1556 int
1557 current_tool(SimView *view, short x, short y, short first)
1558 {
1559 return do_tool(view, view->tool_state, x, y, first);
1560 }
1561
1562
1563 void
1564 DoTool(SimView *view, short tool, short x, short y)
1565 {
1566 int result;
1567
1568 result = do_tool(view, tool, x <<4, y <<4, 1);
1569
1570 if (result == -1) {
1571 ClearMes();
1572 SendMes(34);
1573 MakeSoundOn(view, "edit", "UhUh");
1574 } else if (result == -2) {
1575 ClearMes();
1576 SendMes(33);
1577 MakeSoundOn(view, "edit", "Sorry");
1578 }
1579
1580 sim_skip = 0;
1581 view->skip = 0;
1582 InvalidateEditors();
1583 }
1584
1585
1586 void
1587 ToolDown(SimView *view, int x, int y)
1588 {
1589 int result;
1590
1591 ViewToPixelCoords(view, x, y, &x, &y);
1592 view->last_x = x;
1593 view->last_y = y;
1594
1595 result = current_tool(view, x, y, 1);
1596
1597 if (result == -1) {
1598 ClearMes();
1599 SendMes(34);
1600 MakeSoundOn(view, "edit", "UhUh");
1601 } else if (result == -2) {
1602 ClearMes();
1603 SendMes(33);
1604 MakeSoundOn(view, "edit", "Sorry");
1605 } else if (result == -3) {
1606 DoPendTool(view, view->tool_state, x >>4, y >>4);
1607 }
1608
1609 sim_skip = 0;
1610 view->skip = 0;
1611 view->invalid = 1;
1612 }
1613
1614
1615 void
1616 ToolUp(SimView *view, int x, int y)
1617 {
1618 ToolDrag(view, x, y);
1619 }
1620
1621
1622 void
1623 ToolDrag(SimView *view, int px, int py)
1624 {
1625 int x, y, dx, dy, adx, ady, lx, ly, dist;
1626 float i, step, tx, ty, dtx, dty, rx, ry;
1627
1628 ViewToPixelCoords(view, px, py, &x, &y);
1629 view->tool_x = x; view->tool_y = y;
1630
1631 if ((view->tool_state == chalkState) ||
1632 (view->tool_state == eraserState)) {
1633
1634 current_tool(view, x, y, 0);
1635 view->last_x = x; view->last_y = y;
1636
1637 } else {
1638
1639 dist = toolSize[view->tool_state];
1640
1641 x >>= 4; y >>= 4;
1642 lx = view->last_x >> 4;
1643 ly = view->last_y >> 4;
1644
1645 dx = x - lx;
1646 dy = y - ly;
1647
1648 if (dx == 0 && dy == 0) {
1649 return;
1650 }
1651
1652 adx = ABS(dx); ady = ABS(dy);
1653
1654 if (adx > ady) {
1655 step = .3 / adx;
1656 } else {
1657 step = .3 / ady;
1658 }
1659
1660 rx = (dx < 0 ? 1 : 0);
1661 ry = (dy < 0 ? 1 : 0);
1662
1663 if (dist == 1) {
1664 for (i = 0.0; i <= 1 + step; i += step) {
1665 tx = (view->last_x >>4) + i * dx;
1666 ty = (view->last_y >>4) + i * dy;
1667 dtx = ABS(tx - lx);
1668 dty = ABS(ty - ly);
1669 if (dtx >= 1 || dty >= 1) {
1670 /* fill in corners */
1671 if ((dtx >= 1) && (dty >= 1)) {
1672 if (dtx > dty) {
1673 current_tool(view, ((int)(tx + rx)) <<4, ly <<4, 0);
1674 } else {
1675 current_tool(view, lx <<4, ((int)(ty + ry)) <<4, 0);
1676 }
1677 }
1678 lx = (int)(tx + rx);
1679 ly = (int)(ty + ry);
1680 current_tool(view, lx <<4, ly <<4, 0);
1681 }
1682 }
1683 } else {
1684 for (i = 0.0; i <= 1 + step; i += step) {
1685 tx = (view->last_x >>4) + i * dx;
1686 ty = (view->last_y >>4) + i * dy;
1687 dtx = ABS(tx - lx);
1688 dty = ABS(ty - ly);
1689 lx = (int)(tx + rx);
1690 ly = (int)(ty + ry);
1691 current_tool(view, lx <<4, ly <<4, 0);
1692 }
1693 }
1694
1695 view->last_x = (lx <<4) + 8;
1696 view->last_y = (ly <<4) + 8;
1697 }
1698 sim_skip = 0; /* update editors overlapping this one */
1699 view->skip = 0;
1700 view->invalid = 1;
1701 }
1702
1703
1704 void
1705 DoPendTool(SimView *view, int tool, int x, int y)
1706 {
1707 char buf[256];
1708
1709 sprintf(buf, "DoPendTool %s %d %d %d",
1710 Tk_PathName(view->tkwin), tool, x, y);
1711 Eval(buf);
1712 }
Impressum, Datenschutz