PageRenderTime 51ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/src/creation.c

https://gitlab.com/german-atlantis/mainline
C | 1222 lines | 832 code | 229 blank | 161 comment | 220 complexity | 54c0dde52f4008d339b1a465e92a31ad MD5 | raw file
  1. /*
  2. * German Atlantis PB(E)M host Copyright (C) 1995-1999 Alexander Schroeder
  3. *
  4. * based on:
  5. *
  6. * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
  7. *
  8. * This program may be freely used, modified and distributed. It may
  9. * not be sold or used commercially without prior written permission
  10. * from the author.
  11. */
  12. #include "atlantis.h"
  13. /* Liste von Regionennamen, wird nur hier eingebaut. */
  14. #include "names.inc"
  15. #define INIT_PASSWORD_LENGTH 5
  16. /* Eine Insel pro 9x9 Feld. Das erste Feld von (0,0) bis (8,8). */
  17. #define BLOCKSIZE 9
  18. /* Entweder eine grosse Insel (Chance 2/3) mit 31 bis 40 Felder oder eine
  19. kleine Insel (Chance 1/3) mit 11 bis 39 Feldern. */
  20. #define ISLANDSIZE ((rnd()%3)?(31+rnd()%10):(11+rnd()%20))
  21. /* Ozean und Grasland wird automatisch generiert (ein Ozean, darin
  22. eine Insel aus Grasland). Jedes Seed generiert ein Feld des
  23. entsprechenden Terrains, und max. 3 angrenzende Felder. Details in
  24. der Funktion seed () und transmute () in REGIONS.C. Die Anzahl
  25. Inseln auf der Welt (falls sie sphaerisch ist) bestimmt man in
  26. spericalx () und sphericaly (). Dabei climate (/) nicht vergessen,
  27. dort wird bestimmt, zu welcher y Koordinate welches Klima gehoert.
  28. Das Klima bestimmt das Verhaeltniss der einzelnen Terrains auf der
  29. Insel. */
  30. /* ------------------------------------------------------------- */
  31. enum
  32. {
  33. C_PACIFIC,
  34. C_TROPIC,
  35. C_DRY,
  36. C_TEMPERATE,
  37. C_COOL,
  38. C_ARCTIC,
  39. MAXCLIMATES,
  40. };
  41. /* OCEAN, PLAIN, FOREST, SWAMP, DESERT, HIGHLAND, MOUNTAIN, GLACIER,
  42. MAXTERRAINS */
  43. static char maxseeds[MAXCLIMATES][MAXTERRAINS] =
  44. {
  45. {3, 0, 4, 0, 0, 1, 0, 0,},
  46. {0, 0, 6, 4, 0, 2, 2, 0,},
  47. {0, 0, 1, 0, 6, 2, 2, 0,},
  48. {0, 0, 3, 2, 0, 2, 3, 1,},
  49. {0, 0, 3, 3, 0, 1, 4, 5,},
  50. {0, 0, 0, 2, 0, 0, 5,12,},
  51. };
  52. static int
  53. climate (int y)
  54. {
  55. /* Abfolge: y/BLOCKSIZE +2 abs %10 -5 abs
  56. TEMPERATE -4 -2 2 2 -3 3
  57. COOL -3 -1 1 1 -4 4
  58. > ARCTIC -2 0 0 0 -5 5
  59. COOL -1 1 1 1 -4 4
  60. TEMPERATE (0,0) 0 2 2 2 -3 3
  61. DRY 1 3 3 3 -2 2
  62. TROPIC 2 4 4 4 -1 1
  63. < PACIFIC 3 5 5 5 0 0
  64. TROPIC 4 6 6 6 1 1
  65. DRY 5 7 7 7 2 2 */
  66. return abs( abs( (y/BLOCKSIZE) + 2) % 10 - 5);
  67. }
  68. static unsigned int random_monster[MAXTYPES] =
  69. {
  70. 0,
  71. 10, /* U_UNDEAD */
  72. 0,
  73. 30, /* U_FIREDRAGON */
  74. 20, /* U_DRAGON */
  75. 10, /* U_WYRM */
  76. 30, /* U_GUARDS */
  77. };
  78. /* Transformiert die Koordinaten in Koordinaten auf einer runden Welt.
  79. Soll Atlantis nicht rund sein, dann kann man hier einfach ein
  80. inline `return coord;' machen. Die Klimazonen Verteilung im
  81. Origignal GA hatte Grenzen von -4 bis 5, dh. die Ecken lagen bei
  82. (-36,-36) und (53,53). In diesem Fall sind lb=-36 (-4x9) und ub=54
  83. ((5+1)x9). */
  84. int
  85. sphericalx (int coord)
  86. {
  87. int lb=-4 * BLOCKSIZE; /* lower boundary. */
  88. int ub=(5 +1) * BLOCKSIZE; /* upper boundary. */
  89. if (coord < lb)
  90. /* coord=-37 -> (54)-[(-36)-(-37)]=53. */
  91. /* Falls lb=0 und ub=9, coord=-1 -> (9)-[(0)-(-1)]=8. */
  92. coord = ub - (lb - coord);
  93. else if (coord >= ub)
  94. /* coord=54 -> (-36)+[(54)-(54)]=-36. */
  95. /* coord=55 -> (-36)+[(55)-(54)]=-35. */
  96. /* Falls lb=0 und ub=9, coord=9 -> (0)+[(9)-(9)]=0. */
  97. /* Falls lb=0 und ub=9, coord=10 -> (0)+[(10)-(9)]=1. */
  98. coord = lb + (coord - ub);
  99. return coord;
  100. }
  101. int
  102. sphericaly (int coord)
  103. {
  104. /* Die Welt ist torsoidal (dh. wenn man oben ueber den Rand faehrt
  105. kommt man unten wieder heraus, dasselbe mit links und rechts),
  106. und die gesamte Karte ist quadratisch, also sind sphericalx ()
  107. und sphericaly () im Moment noch gleich. */
  108. return sphericalx (coord);
  109. }
  110. /* ------------------------------------------------------------- */
  111. static region *
  112. inputregion (void)
  113. {
  114. region *r;
  115. int x, y, z;
  116. printf ("X? ");
  117. (void)gets (buf);
  118. if (buf[0] == 0)
  119. return 0;
  120. x = atoi (buf);
  121. printf ("Y? ");
  122. (void)gets (buf);
  123. if (buf[0] == 0)
  124. return 0;
  125. y = atoi (buf);
  126. printf ("Z? ");
  127. (void)gets (buf);
  128. if (buf[0] == 0)
  129. return 0;
  130. z = atoi (buf);
  131. r = findregion (x, y, z);
  132. if (!r)
  133. {
  134. puts ("Diese Region existiert nicht.");
  135. return 0;
  136. }
  137. return r;
  138. }
  139. /* ------------------------------------------------------------- */
  140. void
  141. createmonsters (void)
  142. {
  143. faction *f;
  144. if (findfaction (0))
  145. {
  146. puts ("Die Monster Partei gibt es schon.");
  147. return;
  148. }
  149. f = cmalloc (sizeof (faction));
  150. memset (f, 0, sizeof (faction));
  151. /* alles ist auf null gesetzt, ausser dem folgenden. achtung - partei no 0
  152. muss keine orders einreichen! */
  153. mnstrcpy (&f->name, "Monster", NAMESIZE);
  154. f->alive = 1;
  155. f->options = 1 << O_REPORT;
  156. addlist (&factions, f);
  157. }
  158. /* ------------------------------------------------------------- */
  159. static void
  160. generate_password (faction *f)
  161. {
  162. int i;
  163. for (i = 0; i != INIT_PASSWORD_LENGTH; i++)
  164. buf[i] = 'a' + ( random () % 26 );
  165. buf[i] = 0;
  166. mnstrcpy (&f->passw, buf, INIT_PASSWORD_LENGTH);
  167. }
  168. static void
  169. addaplayerat (region * r)
  170. {
  171. faction *f;
  172. unit *u;
  173. int mon;
  174. f = cmalloc (sizeof (faction));
  175. memset (f, 0, sizeof (faction));
  176. /* Die Adresse steht in buf (vgl. fkt. addplayers) */
  177. mnstrcpy (&f->addr, buf, DISPLAYSIZE);
  178. /* Passwort auf ein Zufallscode setzen, letzter Befehl diese Runde
  179. und am leben */
  180. generate_password (f);
  181. f->lastorders = turn;
  182. f->alive = 1;
  183. f->newbie = 1;
  184. f->options = (1 << O_REPORT) + (1 << O_COMPUTER) + (1 << O_STATISTICS)
  185. + (1 << O_ZINE) + (1 << O_COMMENTS) + (1 << O_COMPRESS);
  186. /* Setze die Nummer und den Namen fuer die Partei auf die erste freie
  187. Nummer */
  188. do
  189. f->no++;
  190. while (findfaction (f->no));
  191. sprintf (buf, "Nummer %d", f->no);
  192. mnstrcpy (&f->name, buf, NAMESIZE);
  193. addlist (&factions, f);
  194. /* erzeuge zugehoerige Einheit */
  195. u = createunit (r);
  196. u->number = 1;
  197. mon = STARTMONEY;
  198. mon = max( mon, (STARTMONEY + (turn - 155) * STARTBONUS * 8 ) );
  199. mon = min( mon, (STARTMONEY + turn * STARTBONUS ));
  200. u->money = mon;
  201. u->faction = f;
  202. /* Newbie-Bonus hier einfuegen */
  203. }
  204. void
  205. addplayers (void)
  206. {
  207. region *r;
  208. FILE *D;
  209. r = inputregion ();
  210. /* Die Spieler erscheinen auf dieser Stelle im Spiel */
  211. /* falls keine Region eingegeben wurde */
  212. if (!r)
  213. return;
  214. /* falls die Region ein Ozean ist */
  215. if (r->terrain == T_OCEAN)
  216. {
  217. puts ("Diese Gegend liegt unter dem Meeresspiegel!");
  218. return;
  219. }
  220. printf ("Datei mit den Spieleradressen? ");
  221. (void)gets (buf);
  222. /* wenn buf nirgendswohin zeigt, wurde keine Datei angegeben. */
  223. if (!buf[0])
  224. {
  225. /* und deswegen fragen wir nun einfach direkt nach dem Namen. */
  226. printf ("OK. Name bzw. Adresse des Spielers? ");
  227. (void)gets (buf);
  228. /* wieder ohne Antwort, beenden wir die Funktion */
  229. if (!buf[0])
  230. return;
  231. else
  232. addaplayerat (r);
  233. }
  234. else
  235. {
  236. D = cfopen (buf, "r");
  237. if (D == NULL)
  238. return;
  239. for (;;)
  240. {
  241. getbuf (D);
  242. if (buf[0] == 0 || buf[0] == EOF)
  243. {
  244. fclose (D);
  245. break;
  246. }
  247. addaplayerat (r);
  248. }
  249. puts ("Es empfiehlt sich, hier noch Wachen aufzustellen!");
  250. addunit (U_GUARDS);
  251. }
  252. }
  253. /* ------------------------------------------------------------- */
  254. /*
  255. void
  256. connecttothis (region * r, int x, int y, int z, int from, int to)
  257. {
  258. region *r2;
  259. r2 = findregion (x, y, z);
  260. if (r2)
  261. {
  262. r->connect[from] = r2;
  263. r2->connect[to] = r;
  264. }
  265. }
  266. */
  267. void
  268. connectregions (void)
  269. {
  270. region *r;
  271. region *r2;
  272. int i;
  273. for (r = regions; r != NULL; r = r->next)
  274. for (r2 = r; r2 != NULL; r2 = r2->next)
  275. for (i = 0; i != MAXDIRECTIONS; i++)
  276. {
  277. if ( (r2->x == sphericalx (r->x + delta_x[i]) )
  278. && (r2->y == sphericaly (r->y + delta_y[i] ) )
  279. && (r2->z == r->z) )
  280. {
  281. r->connect[i] = r2;
  282. r2->connect[back[i]] = r;
  283. }
  284. }
  285. }
  286. /* ------------------------------------------------------------- */
  287. void
  288. listnames (void)
  289. {
  290. region *r;
  291. int i;
  292. puts ("Die Liste der benannten Regionen ist:");
  293. i = 0;
  294. for (r = regions; r; r = r->next)
  295. if (r->terrain != T_OCEAN)
  296. {
  297. printf ("%s,", r->name ? r->name : "Das unbenannte Land");
  298. i += strlen (r->name) + 1;
  299. while (i % 15)
  300. {
  301. printf (" ");
  302. i++;
  303. }
  304. if (i > 60)
  305. {
  306. printf ("\n");
  307. i = 0;
  308. }
  309. }
  310. printf ("\n");
  311. }
  312. static int
  313. regionnameinuse (char *s)
  314. {
  315. region *r;
  316. for (r = regions; r; r = r->next)
  317. /* hier darf es case-insensitive sein, da die Namen nie vom Benutzer
  318. eingegeben werden. */
  319. if (r->name && !strcmp (r->name, s))
  320. return 1;
  321. return 0;
  322. }
  323. static void
  324. nameregion (region * r)
  325. {
  326. /* Zaehlt die benutzten Namen */
  327. int i, n;
  328. region *r2;
  329. n = 0;
  330. for (r2 = regions; r2; r2 = r2->next)
  331. if (r2->name)
  332. n++;
  333. /* Vergibt einen Namen */
  334. i = rnd () % (sizeof regionnames / sizeof (char *));
  335. /* Falls es noch genug unbenutzte Namen gibt, wird solange ein weiterer
  336. genommen, bis einer der unbenutzten gefunden wurde. */
  337. if ((double)n < 0.8 * sizeof regionnames / sizeof (char *))
  338. while (regionnameinuse (regionnames[i]))
  339. i = rnd () % (sizeof regionnames / sizeof (char *));
  340. mnstrcpy (&r->name, regionnames[i], NAMESIZE);
  341. }
  342. static void
  343. terraform (region * r, int terrain)
  344. {
  345. /* defaults: */
  346. r->terrain = terrain;
  347. r->trees = 0;
  348. r->horses = 0;
  349. r->peasants = 0;
  350. r->money = 0;
  351. if (terrain != T_OCEAN)
  352. {
  353. /* jede r ausser ozean hat einen namen. */
  354. nameregion (r);
  355. switch (terrain)
  356. {
  357. case T_PLAIN:
  358. /* 0-200 pferde in Ebenen */
  359. r->horses = (rnd () % (production[terrain] / 5));
  360. break;
  361. case T_FOREST:
  362. /* waelder per se gibt es nicht, das ist eine Ebene mit vielen
  363. baeumen. 600-900 baueme max. */
  364. r->terrain = T_PLAIN;
  365. r->trees = production[T_PLAIN] * (60 + rnd () % 30) / 100;
  366. break;
  367. }
  368. /* 50-80% der maximalen Anzahl an Bauern, in einer Ebene also
  369. 5000-8000. */
  370. r->peasants = MAXPEASANTS_PER_AREA * production[terrain] *
  371. (50 + rnd () % 30) / 100;
  372. }
  373. }
  374. /* ------------------------------------------------------------- */
  375. static char newblock[BLOCKSIZE][BLOCKSIZE];
  376. static void
  377. transmute (int from, int to, int n, int count)
  378. {
  379. int i, x, y;
  380. /* insgesamt werden also n felder geaendert */
  381. do
  382. {
  383. i = 0;
  384. do
  385. {
  386. x = rnd () % BLOCKSIZE;
  387. y = rnd () % BLOCKSIZE;
  388. i += count;
  389. }
  390. while (i <= 10 && !(newblock[x][y] == from &&
  391. ((x != 0 && newblock[x - 1][y] == to) ||
  392. (x != BLOCKSIZE - 1 && newblock[x + 1][y] == to) ||
  393. (y != 0 && newblock[x][y - 1] == to) ||
  394. (y != BLOCKSIZE - 1 && newblock[x][y + 1] == to))));
  395. /* Wenn von seed aus gerufen: zehn versuche, um ein feld zu
  396. finden, welches =from ist, und neben einem feld liegt, das
  397. =to ist. Wenn von makeblock aus gerufen, hat man unendlich
  398. lange zeit, um danach zu suchen. Aufpassen, dass ISLANDSIZE
  399. n nie groesser als BLOCKSIZE^2 wird! */
  400. /* Wurde 10 mal erfolglos probiert, ein seed zu machen, brechen
  401. wir ab. */
  402. if (i > 10)
  403. break;
  404. /* ansonsten aendern wir ein feld */
  405. newblock[x][y] = to;
  406. }
  407. while (--n);
  408. }
  409. static void
  410. seed (int to, int n)
  411. {
  412. int x, y, i = 0;
  413. /* hier setzen wir ein T_PLAIN feld =to (20 Versuche), und rufen
  414. nachher transmute auf, um neben eines der =to felder n weitere
  415. =to felder zu setzen. Wird hier also ein wald gesaeht, wird ein
  416. neues wald-feld gesezt, und entweder an diesem oder an anderen
  417. werden n neue waldfelder angehaengt. um diese n zu setzten, hat
  418. man nur 10 versuche (4. parameter 1) */
  419. do
  420. {
  421. x = rnd () % BLOCKSIZE;
  422. y = rnd () % BLOCKSIZE;
  423. i++;
  424. }
  425. while (newblock[x][y] != T_PLAIN && i < 20);
  426. newblock[x][y] = to;
  427. transmute (T_PLAIN, to, n, 1);
  428. }
  429. static int
  430. blockcoord (int x)
  431. {
  432. return (x / BLOCKSIZE) * BLOCKSIZE;
  433. }
  434. static void
  435. upper_left (int *x1, int *y1)
  436. {
  437. int x = *x1, y = *y1;
  438. /* negative Koordinaten: Runterzaehlen */
  439. if (x < 0)
  440. while (x != blockcoord (x))
  441. x--;
  442. if (y < 0)
  443. while (y != blockcoord (y))
  444. y--;
  445. /* positive Koordinaten: Runden. Negative Koord. stimmen schon. */
  446. *x1 = blockcoord (x);
  447. *y1 = blockcoord (y);
  448. }
  449. void
  450. makeblock (int x1, int y1, int z)
  451. {
  452. /* Die z-Koordinate ist insofern speziell, als dass sie konstant
  453. ist. Die x und y Koordinaten werden benoetigt, um einen block
  454. auf der Landkarte zu bezeichnen. Auf diesem Block werden dann
  455. Regionen erzeugt -- alle auf derselben z-Ebene. */
  456. int i, j, x, y, p1, p2, local_climate;
  457. region *r;
  458. /* Zuerst werden die Koordinaten auf eine Sphaere projeziert. */
  459. x1 = sphericalx (x1);
  460. y1 = sphericaly (y1);
  461. local_climate = climate (y1);
  462. /* Links-Oben Koordinate des Quadrates, in dem sich (x1,y1)
  463. befinden. */
  464. upper_left (&x1, &y1);
  465. /* ein Kontinent wird erzeugt und in newblock abgespeichert die Mitte von
  466. newblock wird zu Weideland. Diese Insel wird vergroessert, und dann
  467. werden Terrains "gesaeht" */
  468. memset (newblock, T_OCEAN, sizeof newblock);
  469. newblock[BLOCKSIZE / 2][BLOCKSIZE / 2] = T_PLAIN;
  470. transmute (T_OCEAN, T_PLAIN, ISLANDSIZE, 0);
  471. for (i = 0; i != MAXTERRAINS; i++)
  472. for (j = 0; j != maxseeds[local_climate][i]; j++)
  473. seed (i, 3);
  474. /* newblock wird innerhalb der Rahmen in die Karte kopiert, die Landstriche
  475. werden benannt und bevoelkert, und die produkte p1 und p2 des kontinentes
  476. werden gesetzt. */
  477. p1 = rnd () % MAXLUXURIES;
  478. do
  479. p2 = rnd () % MAXLUXURIES;
  480. while (p2 == p1);
  481. for (x = 0; x != BLOCKSIZE; x++)
  482. for (y = 0; y != BLOCKSIZE; y++)
  483. {
  484. r = cmalloc (sizeof (region));
  485. memset (r, 0, sizeof (region));
  486. r->x = sphericalx (x1 + x);
  487. r->y = sphericaly (y1 + y);
  488. r->z = z;
  489. terraform (r, newblock[x][y]);
  490. for (i = 0; i != MAXLUXURIES; i++)
  491. r->demand[i] = MINDEMAND + rnd () % 500;
  492. r->produced_good = (rnd () & 1) ? p1 : p2;
  493. r->demand[r->produced_good] = MINDEMAND;
  494. addlist (&regions, r);
  495. }
  496. connectregions ();
  497. }
  498. /* Drachen werden ausgesetzt, wenn die Region automatisch (durch
  499. einreisende Spieler) erzeugt wurde. Dies geschieht bei Bewegungen.
  500. Wenn der Spielleiter Inseln erzeugt, werden Drachen *nicht*
  501. automatisch ausgesetzt. */
  502. void
  503. seed_monsters (int x1, int y1, int z)
  504. {
  505. region *r;
  506. int i, m, x, y;
  507. /* Zuerst werden die x und y Koordinaten auf eine Sphaere
  508. projeziert. */
  509. x1 = sphericalx (x1);
  510. y1 = sphericaly (y1);
  511. upper_left (&x1, &y1);
  512. for (i=0; i != MAXTYPES; i++)
  513. {
  514. if (rnd () % 100 < random_monster[i])
  515. {
  516. do
  517. {
  518. x = rnd () % BLOCKSIZE;
  519. y = rnd () % BLOCKSIZE;
  520. r = findregion (x1 + x, y1 + y, z);
  521. }
  522. while (r->terrain == T_OCEAN);
  523. printf (" %s in %s ausgesetzt.\n",
  524. strings[types[i].names[1]][0], regionid(r));
  525. switch (i)
  526. {
  527. case U_UNDEAD:
  528. (void)make_undead_unit (r, findfaction (0), lovar (20));
  529. break;
  530. case U_FIREDRAGON:
  531. (void)make_firedragon_unit (r, findfaction (0), 1);
  532. break;
  533. case U_DRAGON:
  534. (void)make_dragon_unit (r, findfaction (0), 1);
  535. break;
  536. case U_WYRM:
  537. (void)make_wyrm_unit (r, findfaction (0), 1);
  538. break;
  539. case U_GUARDS:
  540. m = lovar (20);
  541. (void)make_guarded_tower_unit (r, findfaction (0), m, m);
  542. break;
  543. default:
  544. assert (0);
  545. }
  546. break;
  547. }
  548. }
  549. }
  550. /* ------------------------------------------------------------- */
  551. static char
  552. factionsymbols (region * r)
  553. {
  554. faction *f;
  555. unit *u;
  556. int i = 0;
  557. for (f = factions; f; f = f->next)
  558. for (u = r->units; u; u = u->next)
  559. if (u->faction == f)
  560. {
  561. i++;
  562. break;
  563. }
  564. assert (i);
  565. if (i > 9)
  566. return 'x';
  567. else
  568. return '1' - 1 + i;
  569. }
  570. static char
  571. armedsymbols (region * r)
  572. {
  573. unit *u;
  574. int i = 0;
  575. for (u = r->units; u; u = u->next)
  576. if (armedmen (u))
  577. return 'X';
  578. else
  579. i += u->number;
  580. assert (i);
  581. if (i > 9)
  582. return 'x';
  583. else
  584. return '1' - 1 + i;
  585. }
  586. static void
  587. output_map (FILE *D, int mode)
  588. {
  589. int x, y, z, minx, miny, maxx, maxy, minz, maxz;
  590. region *r;
  591. minz = INT_MAX;
  592. maxz = INT_MIN;
  593. for (r = regions; r; r = r->next)
  594. {
  595. minz = min (minz, r->z);
  596. maxz = max (maxz, r->z);
  597. }
  598. for (z = minz; z <= maxz; z++)
  599. {
  600. minx = INT_MAX;
  601. maxx = INT_MIN;
  602. miny = INT_MAX;
  603. maxy = INT_MIN;
  604. for (r = regions; r; r = r->next)
  605. if (r->z == z)
  606. {
  607. minx = min (minx, r->x);
  608. maxx = max (maxx, r->x);
  609. miny = min (miny, r->y);
  610. maxy = max (maxy, r->y);
  611. }
  612. fprintf (D, "Koordinaten von (%d,%d) bis (%d,%d) der Ebene %d:\n\n",
  613. minx, miny, maxx, maxy, z);
  614. for (y = miny; y <= maxy; y++)
  615. {
  616. memset (buf, ' ', sizeof buf);
  617. buf[maxx - minx + 1] = 0;
  618. for (r = regions; r; r = r->next)
  619. if (r->y == y && r->z == z)
  620. {
  621. if (r->units && mode == M_FACTIONS)
  622. buf[r->x - minx] = factionsymbols (r);
  623. else if (r->units && mode == M_UNARMED)
  624. buf[r->x - minx] = armedsymbols (r);
  625. else /* default: terrain */
  626. buf[r->x - minx] = terrainsymbols[mainterrain (r)];
  627. }
  628. for (x = 0; buf[x]; x++)
  629. {
  630. if (y == 0 && x == -minx)
  631. fputc ('(', D);
  632. else if (y == 0 && x == -minx + 1)
  633. fputc (')', D);
  634. else
  635. fputc (' ', D);
  636. fputc (buf[x], D);
  637. }
  638. fputs ("\n", D);
  639. }
  640. fputs ("\n", D);
  641. }
  642. fputs ("\nLegende:\n\n", D);
  643. switch (mode)
  644. {
  645. case M_TERRAIN:
  646. for (y = 0; y != MAXTERRAINS; y++)
  647. fprintf (D, "%c - %s\n", terrainsymbols[y], strings[terrainnames[y]][DEFAULT_LANGUAGE]);
  648. break;
  649. case M_FACTIONS:
  650. for (y = 0; y != MAXTERRAINS; y++)
  651. fprintf (D, "%c - %s\n", terrainsymbols[y], strings[terrainnames[y]][DEFAULT_LANGUAGE]);
  652. fputs ("x - mehr als 9 Parteien\n", D);
  653. fputs ("1-9 - Anzahl Parteien\n", D);
  654. break;
  655. case M_UNARMED:
  656. for (y = 0; y != MAXTERRAINS; y++)
  657. fprintf (D, "%c - %s\n", terrainsymbols[y], strings[terrainnames[y]][DEFAULT_LANGUAGE]);
  658. fputs ("X - mindestens eine bewaffnete Person\n", D);
  659. fputs ("x - mehr als 9 Personen\n", D);
  660. fputs ("1-9 - Anzahl unbewaffneter Personen\n", D);
  661. break;
  662. }
  663. }
  664. void
  665. showmap (int mode)
  666. {
  667. output_map (stdout, mode);
  668. }
  669. void
  670. writemap (int mode)
  671. {
  672. FILE *D;
  673. D = cfopen ("karte", "w");
  674. if (D == NULL)
  675. return;
  676. puts ("Schreibe Karte (karte)...");
  677. output_map (D, mode);
  678. fclose (D);
  679. }
  680. /* ------------------------------------------------------------- */
  681. void
  682. createcontinent (void)
  683. {
  684. int x, y, z;
  685. /* Kontinente werden automatisch generiert! Dies ist nur so zum Testen
  686. gedacht. Da man die X und Y Koordinaten braucht, kann man leider nicht
  687. inputregion () verwenden. */
  688. printf ("X? ");
  689. (void)gets (buf);
  690. if (buf[0] == 0)
  691. return;
  692. x = atoi (buf);
  693. printf ("Y? ");
  694. (void)gets (buf);
  695. if (buf[0] == 0)
  696. return;
  697. y = atoi (buf);
  698. printf ("Z? ");
  699. (void)gets (buf);
  700. if (buf[0] == 0)
  701. return;
  702. z = atoi (buf);
  703. if (!findregion (x, y, z))
  704. makeblock (x, y, z);
  705. else
  706. puts ("Dort gibt es schon Regionen.");
  707. }
  708. /* ------------------------------------------------------------- */
  709. static void
  710. longgets (char *s)
  711. {
  712. int l;
  713. char q = 0;
  714. /* so lange gets, bis nichts mehr eingegeben wird, oder die moegliche
  715. laenge ueberschritten wurde. */
  716. printf ("$ ");
  717. (void)gets (s);
  718. while (!q && (l = (int)strlen (s)) < DISPLAYSIZE)
  719. {
  720. s[l] = ' ';
  721. printf ("$ ");
  722. (void)gets (s + l + 1);
  723. q = !((s + l + 1)[0]);
  724. }
  725. /* wurde verlaengert und mit einer leerzeile abgeschlossen, so wurde
  726. unguterweise ein ' ' angehaengt */
  727. if (q)
  728. s[strlen (s) - 1] = 0;
  729. }
  730. /* ------------------------------------------------------------- */
  731. void
  732. changeterrain (void)
  733. {
  734. region *r;
  735. int i;
  736. r = inputregion ();
  737. if (!r)
  738. return;
  739. puts ("Terrain?");
  740. for (i = 0; i != MAXTERRAINS; i++)
  741. printf ("%d - %s\n", i, strings[terrainnames[i]][DEFAULT_LANGUAGE]);
  742. (void)gets (buf);
  743. if (buf[0])
  744. {
  745. i = atoi (buf);
  746. if (i >= 0 && i < MAXTERRAINS)
  747. terraform (r, i);
  748. }
  749. describe (stdout, r, findfaction(0));
  750. }
  751. /* ------------------------------------------------------------- */
  752. void
  753. addbuilding (void)
  754. {
  755. region *r;
  756. building *b;
  757. r = inputregion ();
  758. if (!r)
  759. return;
  760. b = cmalloc (sizeof (building));
  761. memset (b, 0, sizeof (building));
  762. do
  763. b->no++;
  764. while (findbuilding (b->no));
  765. printf ("Groesse: ");
  766. (void)gets (buf);
  767. b->size = max (atoi (buf), 1);
  768. printf ("Name: ");
  769. (void)gets (buf);
  770. if (buf[0] == 0)
  771. sprintf (buf, "Burg %d", b->no);
  772. mnstrcpy (&b->name, buf, NAMESIZE);
  773. printf ("Beschreibung: ");
  774. longgets (buf);
  775. if (buf[0])
  776. mnstrcpy (&b->display, buf, DISPLAYSIZE);
  777. addlist (&r->buildings, b);
  778. printf ("\n%s, Groesse %d, %s", buildingid (b), b->size,
  779. buildingtype (b));
  780. if (b->display)
  781. printf ("; %s", b->display);
  782. putc ('\n', stdout);
  783. }
  784. /* ------------------------------------------------------------- */
  785. /* Der type kann -1 sein, dann wird neu nach dem type gefragt. */
  786. void
  787. addunit (int type)
  788. {
  789. region *r;
  790. unit *u;
  791. faction *f;
  792. int i, n;
  793. r = inputregion ();
  794. if (!r)
  795. return;
  796. /* typ */
  797. if (type == -1)
  798. {
  799. puts ("Typ?");
  800. for (i = 0; i != MAXTYPES; i++)
  801. printf ("%d - %s\n", i, strings[types[i].names[0]][0]);
  802. (void)gets (buf);
  803. if (buf[0])
  804. {
  805. i = atoi (buf);
  806. if (i >= 0 && i < MAXTYPES)
  807. type = i;
  808. }
  809. }
  810. if (type == -1)
  811. {
  812. puts ("Diesen Typ gibt es nicht.");
  813. return;
  814. }
  815. /* anzahl - vor make_illsionary_unit, damit die Anzahl erschaffener
  816. Gegenstaende pro Unit auch stimmt */
  817. printf ("Anzahl: ");
  818. (void)gets (buf);
  819. n = atoi (buf);
  820. if (!n)
  821. return;
  822. /* partei - auch fuer die funktionen (fakultativ vorher schon) vorher schon
  823. pruefen, ob es die Monster (0) scho gibt, wenn nicht, erschaffen */
  824. if (!(f = findfaction (0)))
  825. {
  826. createmonsters ();
  827. if (!(f = findfaction (0)))
  828. puts ("* Fehler! Die Monsterpartei konnte nicht erzeugt "
  829. "werden");
  830. }
  831. printf ("Partei: ");
  832. (void)gets (buf);
  833. f = findfaction (atoi (buf));
  834. if (!f)
  835. {
  836. puts ("Diese Partei gibt es nicht.");
  837. return;
  838. }
  839. /* erschaffe unit und setze ein paar defaults */
  840. switch (type)
  841. {
  842. case U_FIREDRAGON:
  843. u = make_firedragon_unit (r, f, n);
  844. break;
  845. case U_DRAGON:
  846. u = make_dragon_unit (r, f, n);
  847. break;
  848. case U_WYRM:
  849. u = make_wyrm_unit (r, f, n);
  850. break;
  851. case U_UNDEAD:
  852. u = make_undead_unit (r, f, n);
  853. break;
  854. case U_ILLUSION:
  855. u = make_illsionary_unit (r, f, n);
  856. break;
  857. case U_GUARDS:
  858. u = make_guards_unit (r, f, n);
  859. break;
  860. default:
  861. u = createunit (r);
  862. u->type = type;
  863. u->number = n;
  864. u->money = types[u->type].income * u->number;
  865. u->faction = f;
  866. break;
  867. }
  868. puts ("Bis jetzt:");
  869. rpunit (stdout, f, r, u, 4);
  870. printf ("Neuer Name:\n"
  871. "$ ");
  872. (void)gets (buf);
  873. if (buf[0])
  874. mnstrcpy (&u->name, buf, NAMESIZE);
  875. puts ("Neue Beschreibung: ");
  876. longgets (buf);
  877. if (buf[0])
  878. mnstrcpy (&u->display, buf, DISPLAYSIZE);
  879. rpunit (stdout, f, r, u, 4);
  880. printf ("Akzeptieren? ");
  881. (void)gets (buf);
  882. if (!(buf[0] == 'j' ||
  883. buf[0] == 'J' ||
  884. buf[0] == 'y' ||
  885. buf[0] == 'Y'))
  886. u->number = 0; /* automatisch geloescht */
  887. return;
  888. }
  889. /* ------------------------------------------------------------- */
  890. static void
  891. writeinfo (FILE *D, region * r)
  892. {
  893. unit *u;
  894. building *b;
  895. ship *sh;
  896. faction *f;
  897. int d;
  898. fprintf (D, "%s\n", regionid (r));
  899. fprintf (D, "%s, %d Baeume, %d Bauern, $%d, %d Pferde\n",
  900. strings[terrainnames[mainterrain (r)]][DEFAULT_LANGUAGE], r->trees, r->peasants, r->money,
  901. r->horses);
  902. fprintf (D, "Burgen:\n");
  903. if (!r->buildings)
  904. fprintf (D, " keine\n");
  905. else
  906. {
  907. for (b = r->buildings; b; b = b->next)
  908. {
  909. fprintf (D, "%s, Groesse %d, %s\n",
  910. buildingid (b), b->size, buildingtype (b));
  911. fprintf (D, " (Besitzer: ");
  912. for (u = r->units; u; u = u->next)
  913. if (u->building == b && u->owner)
  914. {
  915. fprintf (D, "%s, Partei %d",
  916. unitid (u), u->faction->no);
  917. break;
  918. }
  919. if (!u)
  920. fprintf (D, "niemand");
  921. fprintf (D, ")\n");
  922. }
  923. b = largestbuilding (r);
  924. fprintf (D, "Groesste Burg: %s\n", buildingid (b));
  925. }
  926. fprintf (D, "Schiffe:\n");
  927. if (!r->ships)
  928. fprintf (D, " keine\n");
  929. else
  930. for (sh = r->ships; sh; sh = sh->next)
  931. {
  932. fprintf (D, "%s, %s", shipid (sh), shiptypes[0][sh->type]);
  933. if (sh->left)
  934. fprintf (D, ", im Bau");
  935. fprintf (D, "\n (Besitzer: ");
  936. for (u = r->units; u; u = u->next)
  937. if (u->ship == sh && u->owner)
  938. {
  939. fprintf (D, "%s, Partei %d",
  940. unitid (u), u->faction->no);
  941. break;
  942. }
  943. if (!u)
  944. fprintf (D, "niemand");
  945. fprintf (D, ")\n");
  946. }
  947. fprintf (D, "Parteien:\n");
  948. if (!r->units || !factions)
  949. fprintf (D, " keine\n");
  950. else
  951. for (f = factions; f; f = f->next)
  952. for (u = r->units; u; u = u->next)
  953. if (u->faction == f)
  954. {
  955. fprintf (D, " %s\n", factionid (u->faction));
  956. break;
  957. }
  958. for (d = 0; d != MAXDIRECTIONS; d++)
  959. {
  960. fprintf (D, "Im %s: %s, %s\n", directions[d],
  961. regionid (r->connect[d]),
  962. strings[terrainnames[mainterrain (r->connect[d])]][DEFAULT_LANGUAGE]);
  963. if (!r->connect[d] || !r->connect[d]->units || !factions)
  964. fprintf (D, " keine\n");
  965. else
  966. for (f = factions; f; f = f->next)
  967. for (u = r->connect[d]->units; u; u = u->next)
  968. if (u->faction == f)
  969. {
  970. fprintf (D, " %s\n", factionid (u->faction));
  971. break;
  972. }
  973. }
  974. }
  975. void
  976. regioninfo (void)
  977. {
  978. region *r;
  979. FILE *D;
  980. r = inputregion ();
  981. if (!r)
  982. return;
  983. writeinfo (stdout, r);
  984. D = cfopen ("info", "w");
  985. if (D == NULL)
  986. return;
  987. puts ("Schreibe Info...");
  988. writeinfo (D, r);
  989. fclose (D);
  990. }