]>
Commit | Line | Data |
---|---|---|
6a5fa4e0 MG |
1 | /* terra.c: Terrain editor |
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 | ||
63 | /* terra.c - terrain editor for Sim City | |
64 | by Paul Schmidt, 1989 | |
65 | Raxsoft, Inc. | |
66 | 1194 Spring Valley Commons | |
67 | Livermore, CA 94550 | |
68 | (415) 449-9079 | |
69 | */ | |
70 | ||
71 | #include "..\sim\sim.h" | |
72 | #include "..\gr\menu.h" | |
73 | #include "..\gr\grdef.h" | |
74 | #include "..\terra\tmenu.h" | |
75 | #include "..\ed\eddef.h" | |
76 | #include "..\ed\edext.h" | |
77 | #include <setjmp.h> | |
78 | #include <dos.h> | |
79 | #include <stdio.h> | |
80 | #include <fcntl.h> | |
81 | #include <sys\types.h> | |
82 | #include <sys\stat.h> | |
83 | #include <direct.h> | |
84 | ||
85 | char *GSaveRect(); | |
86 | ||
87 | extern MOUSESTATE near mouse_state; | |
88 | extern FILE *demoFP; | |
89 | extern char realMouseFlag; | |
90 | ||
91 | extern long lastEvent, TickCount(); /* from ..\sim\main.c */ | |
92 | extern long policeFund, fireFund, transFund; | |
93 | ||
94 | char CreateWithIsland; | |
95 | ||
96 | #define UMaps 4 | |
97 | #define URecs 5000 | |
98 | int UndoMapBuffer1[WORLD_X*WORLD_Y]; | |
99 | int UndoMapBuffer2[WORLD_X*WORLD_Y]; | |
100 | int UndoMapBuffer3[WORLD_X*WORLD_Y]; | |
101 | int UndoMapBuffer4[WORLD_X*WORLD_Y]; | |
102 | int *UndoMap[UMaps]={UndoMapBuffer1,UndoMapBuffer2,UndoMapBuffer3,UndoMapBuffer4}; /* maps for fill undos */ | |
103 | int UndoMaps; /* number of occupied undo maps */ | |
104 | struct { | |
105 | char x,y; /* coordinate of undo */ | |
106 | int val; /* cell value */ | |
107 | } UndoRec[URecs]; /* putdown undos */ | |
108 | int UndoHead=0,UndoTail=0; | |
109 | ||
110 | char fillState=0; /* flag telling if fill mode is on or off */ | |
111 | ||
112 | int treeLevel=50; /* level for tree creation */ | |
113 | int lakeLevel=50; /* level for lake creation */ | |
114 | int curvLevel=50; /* level for river curviness */ | |
115 | ||
116 | /* ========================================================== */ | |
117 | ||
118 | void ClearUndo() /* clear all undo records */ | |
119 | { | |
120 | UndoMaps=UndoHead=UndoTail=0; /* kill undo pointers */ | |
121 | DrawAllEdIcons(UPDATE); /* update undo icon */ | |
122 | } | |
123 | ||
124 | void AddUndo(pos) /* add undo record */ | |
125 | Point pos; /* position to add to undo */ | |
126 | { | |
127 | ||
128 | if(pos.h != -1 || pos.v != -1) { /* if they're not setting to undo the entire map */ | |
129 | if(pos.h > WORLD_X || pos.v > WORLD_Y || pos.h < 0 || pos.v < 0) { /* if out of bounds */ | |
130 | return; /* do nothing */ | |
131 | } | |
132 | } | |
133 | if(pos.h == -1 && pos.v == -1) { /* if undo entire map */ | |
134 | register int tem; /* temporary counter */ | |
135 | register int x,y; /* temporary coordinates */ | |
136 | ||
137 | if(UndoMaps == UMaps) { /* if there are already five undo maps */ | |
138 | while(UndoRec[UndoTail].x != -1 || UndoRec[UndoTail].y != -1) { /* until we find the last map undo */ | |
139 | UndoTail=Bound(0,UndoTail+1,URecs-1); /* move tail */ | |
140 | } | |
141 | UndoTail=Bound(0,UndoTail+1,URecs-1); /* move tail to kill the last map */ | |
142 | UndoMaps--; | |
143 | for(tem=0;tem < UndoMaps;tem++) { /* for each map */ | |
144 | for(x=0;x < WORLD_X*WORLD_Y;x++) { | |
145 | *(UndoMap[tem]+x)=*(UndoMap[tem+1]+x); | |
146 | } | |
147 | } | |
148 | } | |
149 | for(x=0;x < WORLD_X*WORLD_Y;x++) { | |
150 | *(UndoMap[UndoMaps]+x)=*((int*)Map+x); /* save current map */ | |
151 | } | |
152 | UndoMaps++; /* one more map saved */ | |
153 | } | |
154 | UndoRec[UndoHead].x=pos.h; /* set x and y position */ | |
155 | UndoRec[UndoHead].y=pos.v; | |
156 | UndoRec[UndoHead].val=Map[pos.h][pos.v]; /* set map value */ | |
157 | UndoHead=Bound(0,UndoHead+1,URecs-1); /* move head */ | |
158 | if(UndoHead == UndoTail) { /* if we pushed the tail up */ | |
159 | UndoTail=Bound(0,UndoTail+1,URecs-1); /* move tail */ | |
160 | } | |
161 | } | |
162 | ||
163 | void Undo() /* undo one map operation */ | |
164 | { | |
165 | register int x,y; | |
166 | ||
167 | if(UndoHead == UndoTail) { /* if there's nothing to undo */ | |
168 | MakeSound(7); /* bad sound */ | |
169 | return; /* do nothing */ | |
170 | } | |
171 | UndoHead=Bound(0,UndoHead-1,URecs-1); /* set new head */ | |
172 | if(UndoRec[UndoHead].x == -1) { /* if the entire map changed */ | |
173 | register int tem; /* temporary counter */ | |
174 | register int x,y; /* temporary coordinates */ | |
175 | ||
176 | for(x=0;x < WORLD_X*WORLD_Y;x++) { | |
177 | *((int*)Map+x)=*(UndoMap[UndoMaps-1]+x); /* set undo map */ | |
178 | } | |
179 | UndoMaps--; /* one less map */ | |
180 | } else { | |
181 | Map[UndoRec[UndoHead].x][UndoRec[UndoHead].y]=UndoRec[UndoHead].val; /* set old value */ | |
182 | } | |
183 | ||
184 | UpdateOurMaps(); /* update big and small maps */ | |
185 | } | |
186 | ||
187 | /* ======================================================================== */ | |
188 | ||
189 | DoEvent() | |
190 | { | |
191 | ||
192 | int object; | |
193 | EVENT event; | |
194 | ||
195 | #if DEBUG && 0 | |
196 | PrintLock("DoEvent - get event "); | |
197 | #endif | |
198 | GetMouseEvent(&event); | |
199 | object=event.object; | |
200 | #if DEBUG && 0 | |
201 | PrintLock("DoEvent "); | |
202 | #endif | |
203 | ||
204 | switch(object&0xff00) | |
205 | { | |
206 | case 0: DoMenu(object); | |
207 | break; | |
208 | case 0x100: | |
209 | DoEdEvent(&event); | |
210 | break; | |
211 | case 0x200: | |
212 | DoKeyDown(object); | |
213 | break; | |
214 | case 0x300: | |
215 | MenuEvent(&event); | |
216 | break; | |
217 | case 0x400: | |
218 | DoMapEvent(&event); | |
219 | break; | |
220 | case 0x600: | |
221 | DoScreen(&event); | |
222 | break; | |
223 | } | |
224 | } | |
225 | ||
226 | UpdateOurSmallMap() /* update small map */ | |
227 | { | |
228 | register int tem; /* temporary counter */ | |
229 | ||
230 | MouseHide(); /* hide mouse */ | |
231 | DrawSmallMap(); /* updates small map */ | |
232 | for(tem=0;tem < WORLD_X*WORLD_Y;tem++) { | |
233 | *((int*)lastSmallMap+tem)=(*((int*)Map+tem))&LOMASK; /* copy map */ | |
234 | } | |
235 | MouseShow(); /* show mouse */ | |
236 | } | |
237 | ||
238 | UpdateOurMaps() /* update edit and map widnows */ | |
239 | { | |
240 | UpdateMapCursorOff(); /* turn off map cursor */ | |
241 | MouseHide(); /* hide mouse */ | |
242 | DrawBigMap(); /* updates large map */ | |
243 | MouseShow(); /* show mouse */ | |
244 | UpdateOurSmallMap(); | |
245 | DrawAllEdIcons(UPDATE); /* update icons */ | |
246 | UpdateMapCursorOn(); /* turn map cursor on */ | |
247 | } | |
248 | ||
249 | /* ======================================================================== */ | |
250 | DoMenu(itemNum) | |
251 | int itemNum; | |
252 | { | |
253 | static char far *popGameLevelStrs[]={"Easy","Medium","Hard",NULL}; | |
254 | int cur_windowActive; /* current active window */ | |
255 | register int x,y; /* temporary integers */ | |
256 | Rect msgBox; | |
257 | Rect msgRect; | |
258 | char *savePtr; /* pointer to saved rectangle */ | |
259 | int smoothFlag; | |
260 | long tmpFunds; | |
261 | int virginCity=YES; | |
262 | ||
263 | switch(itemNum) | |
264 | { | |
265 | /* case MNUSCNO: | |
266 | /* /* Load a scenario - if it fails we need to redraw the */ | |
267 | /* /* screen */ | |
268 | /* if (!LoadScenario()) { | |
269 | /* InitWindows(); | |
270 | /* } else { | |
271 | /* ClearUndo(); /* clear undo records */ | |
272 | /* } | |
273 | /* SelectNewWindow(EDWINDOW); /* enable edit window */ | |
274 | /* SelectNewWindow(MAPWINDOW); /* enable map window */ | |
275 | /* break; /**/ | |
276 | case MNUQUIT: | |
277 | if (Verify("EXIT")) | |
278 | Quit("Micropolis Terrain Editor"); | |
279 | break; | |
280 | case MNU_SoundToggle: /* sound on/off */ | |
281 | userSoundOn^=YES; | |
282 | sso: | |
283 | ShowSelectedOptions(); | |
284 | break; | |
285 | case MNUABOUT: | |
286 | DoAbout(); | |
287 | break; | |
288 | case MNULOAD: | |
289 | if (LoadGame(NULL,NO)) | |
290 | virginCity=NO; | |
291 | SelectNewWindow(EDWINDOW); /* enable edit window */ | |
292 | SelectNewWindow(MAPWINDOW); /* enable map window */ | |
293 | ClearUndo(); /* clear undo records */ | |
294 | break; | |
295 | case MNUSAVE: | |
296 | SaveGame(lastFileName); | |
297 | break; | |
298 | case MNUSVAS: | |
299 | SaveGame(NULL); | |
300 | break; | |
301 | case MNUNEW: /* Start new game */ | |
302 | if (Verify("NEW GAME")) { | |
303 | totalFunds=20000L; | |
304 | NewGame(NO); | |
305 | transFund=policeFund=fireFund=65535L; | |
306 | CityTax=7; | |
307 | virginCity=YES; | |
308 | ClearUndo(); /* clear undo records */ | |
309 | } | |
310 | SelectNewWindow(EDWINDOW); /* enable edit window */ | |
311 | SelectNewWindow(MAPWINDOW); /* enable map window */ | |
312 | break; | |
313 | case MNUPRINT: | |
314 | PrintCity(); | |
315 | break; | |
316 | case MNU_SmoothTrees: | |
317 | smoothFlag=1; | |
318 | goto dosmooth; | |
319 | case MNU_ClearMap: /* if map is to be cleared */ | |
320 | AddUndo(-1,-1); /* save map */ | |
321 | rax_ClearMap(); /* clear map (..\sim\mapgener.c) */ | |
322 | GameLevel=0; /* assume game is easy */ | |
323 | goto updateBoth; | |
324 | break; | |
325 | case MNU_ClearUnnatural: /* if unnatural objects are to be cleared */ | |
326 | AddUndo(-1,-1); /* save map */ | |
327 | for(x=0;x < WORLD_X;x++) { | |
328 | for(y=0;y < WORLD_Y;y++) { | |
329 | if((Map[x][y]&LOMASK) > 37) { /* get rid of everything unnatural */ | |
330 | Map[x][y]=0; /* turn it into dirt */ | |
331 | } | |
332 | } | |
333 | } | |
334 | updateBoth: | |
335 | UpdateOurMaps(); /* update both windows */ | |
336 | break; | |
337 | case MNU_GenerateRandom: /* if random map is to be generated */ | |
338 | if(SetTerrainParameters()) { /* allow user to set terrain generation parameters */ | |
339 | CenterRect(&msgBox, 20, 5); | |
340 | msgRect=*AdjRect(&msgBox); | |
341 | savePtr=GSaveRect(&msgRect); /* save rectangle */ | |
342 | GRectFill(&msgRect, WHITE|PWHITE); | |
343 | GSetAttrib(DGREEN, DGREEN, PBLACK); | |
344 | GRectOutline(&msgRect, 4); | |
345 | GSetAttrib(LGREEN, LGREEN, PMGREY); | |
346 | GRectOutline(&msgRect, 2); | |
347 | GSetAttrib(DBLUE, WHITE, PWHITE|PINV); | |
348 | CenterPrint(&msgBox, msgBox.top+2, "Now terraforming"); | |
349 | ||
350 | AddUndo(-1,-1); /* save map */ | |
351 | rax_ClearMap(); /* make river map */ | |
352 | rax_GetRandStart(); | |
353 | if(CreateWithIsland) { /* if we're creating an island */ | |
354 | rax_MakeIsland(); /* make an island */ | |
355 | } | |
356 | if(curvLevel) { /* if we're supposedly creating an island */ | |
357 | rax_DoRivers(); /* create river */ | |
358 | } | |
359 | if(lakeLevel) { /* if there are to be lakes */ | |
360 | rax_MakeLakes(); /* add lakes */ | |
361 | } | |
362 | rax_SmoothRiver(); /* smooth out river */ | |
363 | if(treeLevel) { /* if we're creating a woodsy terrain */ | |
364 | rax_DoTrees(); /* add trees */ | |
365 | } | |
366 | rax_SmoothTrees(); /* smooth trees */ | |
367 | rax_SmoothTrees(); /* smooth trees */ | |
368 | ||
369 | GRestoreRect(&msgRect,savePtr); /* restore rectangle */ | |
370 | MapX=MapY=0; | |
371 | goto updateBoth; | |
372 | } | |
373 | break; | |
374 | case MNU_SmoothRiver: /* if water is to be smoothed */ | |
375 | smoothFlag=2; | |
376 | goto dosmooth; | |
377 | case MNU_SmoothBoth: /* if both are to be smoothed */ | |
378 | smoothFlag=3; /* Both */ | |
379 | dosmooth: | |
380 | CenterRect(&msgBox, 16, 5); | |
381 | msgRect=*AdjRect(&msgBox); | |
382 | savePtr=GSaveRect(&msgRect); /* save rectangle */ | |
383 | GRectFill(&msgRect, WHITE|PWHITE); | |
384 | GSetAttrib(DGREEN, DGREEN, PBLACK); | |
385 | GRectOutline(&msgRect, 4); | |
386 | GSetAttrib(LGREEN, LGREEN, PMGREY); | |
387 | GRectOutline(&msgRect, 2); | |
388 | GSetAttrib(DBLUE, WHITE, PWHITE|PINV); | |
389 | CenterPrint(&msgBox, msgBox.top+2, "Smoothing..."); | |
390 | ||
391 | AddUndo(-1,-1); /* save map */ | |
392 | if (smoothFlag & 2) /* If water smooth flag set */ | |
393 | { | |
394 | rax_WaterEdges(); /* make sure water edges are ok */ | |
395 | rax_SmoothRiver(); | |
396 | } | |
397 | if (smoothFlag & 1) | |
398 | { | |
399 | rax_SmoothTrees(); | |
400 | rax_SmoothTrees(); | |
401 | } | |
402 | ||
403 | GRestoreRect(&msgRect,savePtr); /* restore rectangle */ | |
404 | goto updateBoth; | |
405 | ||
406 | case MNU_RandomIsland: /* if random Island toggle */ | |
407 | CreateWithIsland^=1; /* toggle state of flag */ | |
408 | ShowSelectedOptions(); /* update menu flag status */ | |
409 | break; | |
410 | ||
411 | case MNU_GameLevel: /* if game level */ | |
412 | /* GameLevel++; /* add one for PopUpMenuBox */ | |
413 | /* PopUpMenuBox(&GameLevel, popGameLevelStrs); | |
414 | /* GameLevel--; /**/ | |
415 | ||
416 | tmpFunds=totalFunds; /* Don't alter the amount of funds! */ | |
417 | ChooseGameLevel(); /* get city name & level from user */ | |
418 | if (!virginCity) | |
419 | totalFunds=tmpFunds; | |
420 | NewName(); /* set the name of the city */ | |
421 | break; | |
422 | case MNU_GameYear: /* if game year */ | |
423 | SetGameYear(); /* allow user to set the game year */ | |
424 | break; | |
425 | ||
426 | case MNU_EditWindow: /* if edit window */ | |
427 | SelectNewWindow(EDWINDOW); /* bring the edit window to the foreground */ | |
428 | break; | |
429 | case MNU_MapWindow: /* if map window */ | |
430 | SelectNewWindow(MAPWINDOW); /* bring the map window to the foreground */ | |
431 | break; | |
432 | ||
433 | default: | |
434 | /* unimplemented option */ | |
435 | break; | |
436 | } | |
437 | } | |
438 | ||
439 | long messageTime; | |
440 | ||
441 | DoEdEvent(ePtr) | |
442 | EVENT *ePtr; | |
443 | { | |
444 | int object; | |
445 | ||
446 | object=ePtr->object&0xff; | |
447 | ||
448 | if (object & 0xf0) | |
449 | { /* Must be an icon */ | |
450 | SetWandState(object&0xf, YES); | |
451 | } | |
452 | switch (object) | |
453 | { | |
454 | case 0: DoEdMapEvent(ePtr); | |
455 | break; | |
456 | case 2: DoMoveWindow(ePtr, edWinList); | |
457 | break; | |
458 | case 8: ResizeEdWindow(ePtr); | |
459 | break; | |
460 | } | |
461 | } | |
462 | ||
463 | /* ======================================================================== */ | |
464 | DoMapEvent(ePtr) | |
465 | EVENT *ePtr; | |
466 | { | |
467 | int object; | |
468 | ||
469 | object=ePtr->object&0xff; | |
470 | ||
471 | { | |
472 | switch (object) | |
473 | { case 0: DoMapWindowEvent(ePtr); /* move locus of edit window */ | |
474 | break; | |
475 | case 2: DoMoveMap(ePtr); /* move window */ | |
476 | break; | |
477 | } | |
478 | } | |
479 | } | |
480 | ||
481 | void EditTerra() /* main program entry point */ | |
482 | { | |
483 | int updateWait=0, updateWait2=0; | |
484 | ||
485 | CreateWithIsland=0; | |
486 | ShowSelectedOptions(); /* update menu flag status */ | |
487 | GameLevel=0; /* assume game is easy */ | |
488 | totalFunds=20000L; | |
489 | transFund=policeFund=fireFund=65535L; | |
490 | CityTax=7; | |
491 | ||
492 | EnableMenus(); /* make sure menus are enabled */ | |
493 | for (;;) | |
494 | { | |
495 | long lastMapCursor; /* time value for map window cursor flashing */ | |
496 | ||
497 | if (WaitedEnough(&lastMapCursor,2)) | |
498 | { /* if we should flash the map cursor */ | |
499 | UpdateMapCursor(); /* update the map cursor */ | |
500 | } | |
501 | ||
502 | ||
503 | if (!menuActive) /* if no menus are active */ | |
504 | { | |
505 | char moveFlag; | |
506 | if (CheckKeyState(CNTRLSCAN)) /* Is the control key hit? */ | |
507 | { | |
508 | int dx, dy; | |
509 | dx=joyMoveX; | |
510 | dy=joyMoveY; | |
511 | ||
512 | if (CheckKeyState(HOMESCAN)) /* Home arrow */ | |
513 | { dx--; dy--; | |
514 | } | |
515 | if (CheckKeyState(PGUPSCAN)) /* PgUp arrow */ | |
516 | { dx++; dy--; | |
517 | } | |
518 | if (CheckKeyState(ENDSCAN)) /* End arrow */ | |
519 | { dx--; dy++; | |
520 | } | |
521 | if (CheckKeyState(PGDNSCAN)) /* PgDn arrow */ | |
522 | { dx++; dy++; | |
523 | } | |
524 | if (CheckKeyState(RIGHTSCAN)) /* Right arrow */ | |
525 | dx++; | |
526 | if (CheckKeyState(LEFTSCAN)) /* Left arrow */ | |
527 | dx--; | |
528 | if (CheckKeyState(UPSCAN)) /* Up arrow */ | |
529 | dy--; | |
530 | if (CheckKeyState(DOWNSCAN)) /* Down arrow */ | |
531 | dy++; | |
532 | if (dx || dy) | |
533 | { | |
534 | DisableMenus(); | |
535 | freeze=YES; | |
536 | EdScroll(dx,dy); | |
537 | freeze=NO; | |
538 | } | |
539 | } | |
540 | if (!ScrollLock()) | |
541 | { | |
542 | moveagn: | |
543 | moveFlag=NO; | |
544 | if (mouse_state.x <= 1) | |
545 | { | |
546 | if (MapX > 0) | |
547 | { | |
548 | MapX--; | |
549 | moveFlag=YES; | |
550 | } | |
551 | } else if (mouse_state.x >= screenWidth-6) | |
552 | { | |
553 | if (MapX+edWinWid < WORLD_X) | |
554 | { | |
555 | MapX++; | |
556 | moveFlag=YES; | |
557 | } | |
558 | } | |
559 | if (mouse_state.y < 1 ) | |
560 | { | |
561 | if (MapY > 0) | |
562 | { | |
563 | MapY--; | |
564 | moveFlag=YES; | |
565 | } | |
566 | } | |
567 | else if (mouse_state.y >= screenHeight-6) | |
568 | { | |
569 | if (MapY+edWinLen < WORLD_Y) | |
570 | { | |
571 | MapY++; | |
572 | moveFlag=YES; | |
573 | } | |
574 | } | |
575 | ||
576 | if (moveFlag == YES) | |
577 | { | |
578 | DisableMenus(); /* locks to current process */ | |
579 | newMapFlags[CYMAP]=0; | |
580 | DrawBigMap(); | |
581 | #if 0 | |
582 | DrawObjects(); | |
583 | #endif | |
584 | EnableMenus(); | |
585 | goto moveagn; | |
586 | } | |
587 | ||
588 | } /* End of "if (!ScrollLock" */ | |
589 | } /* End if if (!menuActive) */ | |
590 | if (KBHit() || CheckMouseEvents()) /* if an event happened */ | |
591 | { | |
592 | DisableMenus(); | |
593 | while(KBHit()) | |
594 | { DoKey(); | |
595 | } | |
596 | while (CheckMouseEvents()) | |
597 | { DoEvent(); | |
598 | } | |
599 | lastEvent=TickCount(); | |
600 | } | |
601 | if (simSpeed == 0) | |
602 | { | |
603 | if (WaitedEnough(&updateWait, 18*3)) | |
604 | { DisableMenus(); | |
605 | UpdateEdWindow(); | |
606 | } | |
607 | } | |
608 | #if DEBUGINI | |
609 | OutStr("\nMAIN: re-enable"); | |
610 | #endif | |
611 | ||
612 | EnableMenus(); /* Make sure the menus are enabled */ | |
613 | copyOK=YES; | |
614 | #if DEBUGINI | |
615 | OutStr("\nMAIN: copyok, pass"); | |
616 | #endif | |
617 | Pass(); | |
618 | copyOK=NO; | |
619 | #if DEBUGINI | |
620 | OutStr("\nMAIN: copy not OK"); | |
621 | #endif | |
622 | } | |
623 | } | |
624 | ||
625 | SetGameYear() /* get game year */ | |
626 | { | |
627 | Rect verBox; | |
628 | static char *label="Enter Game Year:"; /* label for window */ | |
629 | ||
630 | char dateBuffer[10]; /* buffer for date */ | |
631 | EVENT event; | |
632 | char *savePtr; | |
633 | int len, x, y, i,c, optLens[8]; | |
634 | Rect tmpBox; | |
635 | Size strSize; | |
636 | const char **optPtr; | |
637 | int posIndex=(-1); | |
638 | long tmpTime; | |
639 | ||
640 | FlushKeys(); | |
641 | ||
642 | CenterRect(&verBox,18,5); | |
643 | ||
644 | tmpBox=*AdjRect(&verBox); | |
645 | savePtr=GSaveRect(&tmpBox); | |
646 | ||
647 | GRectFill(&tmpBox,BUDGFC+PMGREY); | |
648 | GSetAttrib(BUDGBC,BUDGBC,PWHITE); | |
649 | GRectOutline(&tmpBox, 4); | |
650 | /* Outline outline in BLACK */ | |
651 | GSetAttrib(BLACK,BLACK,PBLACK); | |
652 | GRectOutline(&tmpBox,1); | |
653 | GSetAttrib(BUDGBC,BUDGFC,PINV|PWHITE); | |
654 | PrintRectLines(&verBox,verBox.top,label); | |
655 | i=20; | |
656 | x=verBox.left+i; | |
657 | y=verBox.bottom-2; | |
658 | GSetAttrib(BUDGBC,BUDBOXC,PINV|PWHITE); | |
659 | ||
660 | /* GSetAttrib(BUDGBC,BUDBOXC,0); */ | |
661 | /* TempFullScreenCursor(); */ | |
662 | ||
663 | sprintf(dateBuffer,"%4d",(CityTime/48)+1900); /* set date */ | |
664 | GetStrSetNum(); /* Numbers only */ | |
665 | GetStrn(verBox.left+6,verBox.top+3,dateBuffer,5,1); /* allow user to edit the date and set eos */ | |
666 | GetStrSetAll(); /* allow any alphnum input */ | |
667 | if(strlen(dateBuffer) == 4) { /* if they entered a good date */ | |
668 | tmpTime=(atoi(dateBuffer)-1900)*48L; /* set new date */ | |
669 | if (tmpTime > 0) | |
670 | CityTime=tmpTime; | |
671 | } else { /* if not the correct length */ | |
672 | MakeSound(7); /* this should be CANTSND for bad date */ | |
673 | } | |
674 | for(i=0;i < 100;i++) { /* kill any and all events */ | |
675 | GetMouseEvent(&event); /* get event */ | |
676 | } | |
677 | /* RemoveTempCursor(); */ | |
678 | GRestoreRect(&tmpBox,savePtr); | |
679 | DoDate(); /* update the date in the edit window */ | |
680 | } | |
681 | ||
682 | int PSBound(a,n,b) /* return number between a and b */ | |
683 | { | |
684 | if(n < a) n=a; | |
685 | if(n > b) n=b; | |
686 | return n; | |
687 | } | |
688 | ||
689 | /* here is the concept for SetTerrainParameters(): | |
690 | ZDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD? | |
691 | 3 3 | |
692 | 3 Terrain Creation Parameters 3 | |
693 | 3 3 | |
694 | 3 Number Number River 3 | |
695 | 3 of Trees of Lakes Curviness 3 | |
696 | 3 3 | |
697 | 3 \11 xxx% \10 \11 xxx% \10 \11 xxx% \10 3 | |
698 | 3 3 | |
699 | 3 ZDDDDDDDD? ZDDDDDDDD? 3 | |
700 | 3 3 Go 3 3 Cancel 3 3 | |
701 | 3 @DDDDDDDDY @DDDDDDDDY 3 | |
702 | @DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDY | |
703 | */ | |
704 | SetTerrainParameters() /* allow user to set up terrain grneration parameters */ | |
705 | { | |
706 | char *savePtr; /* pointer to saved screen data */ | |
707 | char temStr[20]; /* temporary string for percentages */ | |
708 | EVENT event; /* temporary event */ | |
709 | int atButton=0; /* current button we're at */ | |
710 | int buttonDown=0; /* flag telling if mouse button is down */ | |
711 | int goFlag=0; /* flag telling if terrain is to be generated */ | |
712 | long startTime; /* temporary timer value */ | |
713 | int tem; /* temporary counter */ | |
714 | int x,y; /* temporary positions */ | |
715 | Rect wRect; /* rectangle showing extents of window */ | |
716 | Rect tmpRect; /* temporary rectangle for adjusted window rectangle */ | |
717 | Point buttonPos[8]; /* positions of buttons */ | |
718 | ||
719 | FlushKeys(); /* do something...flush keyboard buffer? */ | |
720 | ||
721 | CenterRect(&wRect,36,10); /* center our window */ | |
722 | ||
723 | tmpRect=*AdjRect(&wRect); | |
724 | savePtr=GSaveRect(&tmpRect); | |
725 | ||
726 | GRectFill(&tmpRect,BUDGFC+PMGREY); | |
727 | GSetAttrib(BUDGBC,BUDGBC,PWHITE); | |
728 | GRectOutline(&tmpRect,4); | |
729 | /* Outline outline in BLACK */ | |
730 | GSetAttrib(BLACK,BLACK,PBLACK); | |
731 | GRectOutline(&tmpRect,1); | |
732 | GSetAttrib(BUDGBC,BUDGFC,PINV|PWHITE); | |
733 | PrintRectLines(&wRect,wRect.top,"Terrain Creation Parameters"); | |
734 | x=(wRect.left+2)*8; | |
735 | y=(wRect.top+2)*fontHeight; | |
736 | GPPrintf(x+(1*8),y+(1*fontHeight)-3," Number Number River "); | |
737 | GPPrintf(x+(1*8),y+(2*fontHeight)-3,"of Trees of Lakes Curviness"); | |
738 | ||
739 | buttonPos[0].h=wRect.left+3; /* positions of buttons */ | |
740 | buttonPos[1].h=wRect.left+10; | |
741 | buttonPos[2].h=wRect.left+14; | |
742 | buttonPos[3].h=wRect.left+21; | |
743 | buttonPos[4].h=wRect.left+25; | |
744 | buttonPos[5].h=wRect.left+32; | |
745 | for(tem=0;tem < 6;tem++) { | |
746 | buttonPos[tem].v=wRect.top+5; /* set vertical position */ | |
747 | } | |
748 | buttonPos[6].h=wRect.left+3; | |
749 | buttonPos[7].h=wRect.left+25; | |
750 | buttonPos[6].v=buttonPos[7].v=wRect.top+8; | |
751 | ||
752 | GSetAttrib(BUDGBC,BUDBOXC,PINV|PWHITE); | |
753 | for(tem=0;tem < 3;tem++) { /* for each set of value buttons */ | |
754 | AddTextButton(buttonPos[tem*2],"\11",0x800+tem*2); /* add button */ | |
755 | AddTextButton(buttonPos[tem*2+1],"\10",0x801+tem*2); /* add button */ | |
756 | } | |
757 | AddTextButton(buttonPos[6]," Go ",0x806); /* add 'go' button */ | |
758 | AddTextButton(buttonPos[7]," Cancel ",0x807); /* add 'cancel' button */ | |
759 | ||
760 | /* output initial values */ | |
761 | GSetAttrib(BUDGBC,BUDGFC,PINV|PWHITE); | |
762 | sprintf(temStr,"%3d%%%%",treeLevel); /* get string for tree level */ | |
763 | GPPrintf(x+(3*8),y+(3*fontHeight),temStr); /* output string */ | |
764 | sprintf(temStr,"%3d%%%%",lakeLevel); /* get string for lake level */ | |
765 | GPPrintf(x+(14*8),y+(3*fontHeight),temStr); /* output string */ | |
766 | sprintf(temStr,"%3d%%%%",curvLevel); /* get string for curviness level */ | |
767 | GPPrintf(x+(25*8),y+(3*fontHeight),temStr); /* output string */ | |
768 | ||
769 | /* GSetAttrib(BUDGBC,BUDBOXC,0); */ | |
770 | TempFullScreenCursor(); /* give us a cursor */ | |
771 | ||
772 | while(1) { /* until break */ | |
773 | if(0) { /* never unless below code calls it */ | |
774 | repos: | |
775 | SetMouseAtButton(atButton+0x800); | |
776 | } | |
777 | while (KBHit()) /* Clear any keys pressed */ | |
778 | { | |
779 | switch (GetECH()) | |
780 | { case 27: /* if escape */ | |
781 | case 'C': /* (or 'cancel') */ | |
782 | case 'c': | |
783 | goFlag=0; /* don't create random terrain */ | |
784 | goto xit; | |
785 | case 13: /* if carriage return */ | |
786 | case 'G': /* (or 'go') */ | |
787 | case 'g': | |
788 | goFlag=1; /* create random terrain */ | |
789 | goto xit; | |
790 | case '+': atButton=((atButton+1) % 8); /* for each button */ | |
791 | goto repos; | |
792 | case '-': | |
793 | atButton=(atButton)?(atButton-1):7; | |
794 | goto repos; | |
795 | } | |
796 | } | |
797 | if(CheckMouseEvents()) { /* if there's an activity */ | |
798 | GetMouseEvent(&event); /* get event */ | |
799 | downAgain: | |
800 | switch(event.object) { /* get event id */ | |
801 | case 0x800: /* if - trees */ | |
802 | treeLevel=PSBound(0,treeLevel-1,100); | |
803 | goto updateValues; /* update values */ | |
804 | case 0x801: /* if + trees */ | |
805 | treeLevel=PSBound(0,treeLevel+1,100); | |
806 | goto updateValues; /* update values */ | |
807 | case 0x802: /* if - lakes */ | |
808 | lakeLevel=PSBound(0,lakeLevel-1,100); | |
809 | goto updateValues; /* update values */ | |
810 | case 0x803: /* if + lakes */ | |
811 | lakeLevel=PSBound(0,lakeLevel+1,100); | |
812 | goto updateValues; /* update values */ | |
813 | case 0x804: /* if - curviness */ | |
814 | curvLevel=PSBound(0,curvLevel-1,100); | |
815 | goto updateValues; /* update values */ | |
816 | case 0x805: /* if + curviness */ | |
817 | curvLevel=PSBound(0,curvLevel+1,100); | |
818 | goto updateValues; /* update values */ | |
819 | case 0x806: /* if 'go' */ | |
820 | goFlag=1; /* return flag telling to create terrain */ | |
821 | break; | |
822 | case 0x807: /* if 'cancel' */ | |
823 | goFlag=0; /* return flag telling to create terrain */ | |
824 | break; | |
825 | } | |
826 | if(0) { /* only if above code calls us */ | |
827 | updateValues: | |
828 | RemoveTempCursor(); /* remove cursor from screen */ | |
829 | GSetAttrib(BUDGBC,BUDGFC,PINV|PWHITE); | |
830 | sprintf(temStr,"%3d%%%%",treeLevel); /* get string for tree level */ | |
831 | GPPrintf(x+(3*8),y+(3*fontHeight),temStr); /* output string */ | |
832 | sprintf(temStr,"%3d%%%%",lakeLevel); /* get string for lake level */ | |
833 | GPPrintf(x+(14*8),y+(3*fontHeight),temStr); /* output string */ | |
834 | sprintf(temStr,"%3d%%%%",curvLevel); /* get string for curviness level */ | |
835 | GPPrintf(x+(25*8),y+(3*fontHeight),temStr); /* output string */ | |
836 | TempFullScreenCursor(); /* put cursor back */ | |
837 | if(!buttonDown) { /* if button was not down */ | |
838 | buttonDown=1; /* set button down flag */ | |
839 | startTime=TickCount(); /* get current time */ | |
840 | while(StillDown()) { /* while a button is down */ | |
841 | if(TickCount()-startTime > 5) { /* if autorepeat is up */ | |
842 | goto downAgain; | |
843 | } | |
844 | } | |
845 | buttonDown=0; /* button is no longer down */ | |
846 | } else { /* if button is already down */ | |
847 | if(StillDown()) { /* if button is still down */ | |
848 | startTime=TickCount(); /* get current time */ | |
849 | while(startTime == TickCount()) ; /* wait for 1/18th of a second */ | |
850 | goto downAgain; | |
851 | } | |
852 | buttonDown=0; /* no button is down */ | |
853 | } | |
854 | } | |
855 | if(event.object == 0x806 || event.object == 0x807) { /* if one of the exit buttons */ | |
856 | xit: | |
857 | break; /* exit loop */ | |
858 | } | |
859 | } | |
860 | } | |
861 | ||
862 | for(tem=0x800;tem <= 0x809;tem++) { /* remove buttons from hot list */ | |
863 | DelButtonHot(tem); | |
864 | } | |
865 | RemoveTempCursor(); /* remove our cursor */ | |
866 | GRestoreRect(&tmpRect,savePtr); | |
867 | return goFlag; /* return flag telling if terrain is to be created */ | |
868 | } |