PageRenderTime 55ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/src/reports.c

https://gitlab.com/german-atlantis/mainline
C | 1765 lines | 1338 code | 290 blank | 137 comment | 368 complexity | 4a120f05ef71fd46a6006f4494349c97 MD5 | raw file
  1. /*
  2. * German Atlantis PB(E)M host Copyright (C) 1995-1998 Alexander Schroeder
  3. * (c) 2003 Peter Kraus
  4. * (c) 2003 Thomas Gerigk
  5. * Erlaubte Lizenzen: GPL oder BSD(new)
  6. *
  7. * based on:
  8. *
  9. * Atlantis v1.0 13 September 1993 Copyright 1993 by Russell Wallace
  10. *
  11. * This program may be freely used, modified and distributed. It may
  12. * not be sold or used commercially without prior written permission
  13. * from the author.
  14. */
  15. #include "atlantis.h"
  16. #define C_REPORT_VERSION 6
  17. #define REPORTWIDTH 72
  18. #define MAILDELAY 2
  19. #define MAILCHECK_INTERVAL 10
  20. /* set to "" if unwanted */
  21. /* #define MAILCHECK "\nif waithost; then echo Mailing more...; else exit 1; fi\n\n" */
  22. #define MAILCHECK "\n"
  23. /* ------------------------------------------------------------- */
  24. char *
  25. buildingtype (building * b)
  26. {
  27. return buildingnames[buildingeffsize (b)];
  28. }
  29. /* ------------------------------------------------------------- */
  30. char *
  31. gamedate (faction *f)
  32. {
  33. static char buf[40];
  34. static int monthnames[] =
  35. {
  36. ST_JANUARY,
  37. ST_FEBRUARY,
  38. ST_MARCH,
  39. ST_APRIL,
  40. ST_MAY,
  41. ST_JUNE,
  42. ST_JULY,
  43. ST_AUGUST,
  44. ST_SEPTEMBER,
  45. ST_OCTOBER,
  46. ST_NOVEMBER,
  47. ST_DECEMBER,
  48. };
  49. if (turn)
  50. strcpy (buf, translate (ST_DATE, f->language,
  51. strings[monthnames[(turn - 1) % 12]][f->language],
  52. ((turn - 1) / 12) + 1));
  53. else
  54. strcpy (buf, strings[ST_NO_TIME][f->language]);
  55. return buf;
  56. }
  57. /* ------------------------------------------------------------- */
  58. static void
  59. sparagraph (strlist ** SP, char *s, int indent, int mark)
  60. {
  61. /* Die Liste SP wird mit dem String s aufgefuellt, mit indent und
  62. einer mark, falls angegeben. SP wurde also auf 0 gesetzt vor dem
  63. Aufruf. */
  64. int i, j, width;
  65. int firstline;
  66. static char buf[128];
  67. width = REPORTWIDTH - indent;
  68. firstline = 1;
  69. for (;;)
  70. {
  71. i = 0;
  72. /* i zeigt auf das Ende der aktuellen Zeile. j wird auf i gesetzt und um ein Wort verlaengert. Falls das
  73. gelingt, wird i auf j gesetzt. Ist j breiter als der Report, wird abgebrochen. Wird abgebrochen, obwohl
  74. i immer noch 0 ist (dh. das erste Wort der Zeile ist laenger als die Zeile selber), wird i einfach auf die
  75. maximale Breite gesetzt (und dieses erste Wort wird zwangs-getrennt). */
  76. do
  77. {
  78. j = i;
  79. while (s[j] && s[j] != ' ')
  80. j++;
  81. if (j > width)
  82. {
  83. if (i == 0)
  84. i = width - 1;
  85. break;
  86. }
  87. i = j + 1;
  88. }
  89. while (s[j]);
  90. /* Einrueckung, markierung innerhalb der Einrueckung. */
  91. for (j = 0; j != indent; j++)
  92. buf[j] = ' ';
  93. if (firstline && mark)
  94. buf[indent - 2] = mark;
  95. for (j = 0; j != i - 1; j++)
  96. buf[indent + j] = s[j];
  97. buf[indent + j] = 0;
  98. addstrlist (SP, buf);
  99. if (s[i - 1] == 0)
  100. break;
  101. s += i;
  102. firstline = 0;
  103. }
  104. }
  105. static void
  106. spskill (unit * u, int i, int *dh, int days)
  107. {
  108. if (!u->skills[i])
  109. return;
  110. scat (", ");
  111. if (!*dh)
  112. {
  113. scat ("Talente: ");
  114. *dh = 1;
  115. }
  116. scat (skillnames[i]);
  117. scat (" ");
  118. icat (effskill (u, i));
  119. if (days)
  120. {
  121. assert (u->number);
  122. scat (" [");
  123. icat (u->skills[i] / u->number);
  124. scat ("]");
  125. }
  126. }
  127. char *
  128. spunit (faction * f, region * r, unit * u, int battle)
  129. {
  130. int i;
  131. int dh;
  132. strcpy (buf, u->faction == f ? "*" : "-"); /* Wird nachher gesondert verwendet als buf[0]! */
  133. scat (unitid (u)); /* Die wirkliche Beschreibung beginnt bei buf[1]. */
  134. /* Parteizugehoerigkeit nur bei cansee () */
  135. if (cansee (f, r, u) == 2)
  136. {
  137. scat (", ");
  138. scat (factionid (u->faction));
  139. }
  140. /* Fuer fremde Parteien erscheinen Illusionen als Menschen. In Kaempfen werden die Illusionen allerdings
  141. aufgedeckt. Aenderungen hier im Computer Report nicht vergessen! */
  142. scat (translate (ST_QUANTITY_IN_LIST, f->language,
  143. u->number,
  144. strings[types[u->type != U_ILLUSION ? u->type :
  145. ((!battle && u->faction != f) ?
  146. U_MAN : U_ILLUSION)].names[u->number != 1]][f->language]));
  147. /* status */
  148. if (u->faction == f || battle)
  149. switch (u->status)
  150. {
  151. case ST_FIGHT:
  152. scat (", kampfbereit");
  153. break;
  154. case ST_BEHIND:
  155. scat (", kaempft hinten");
  156. break;
  157. case ST_AVOID:
  158. scat (", kaempft nicht");
  159. break;
  160. }
  161. if (u->guard)
  162. scat (", bewacht die Region");
  163. if (u->besieging)
  164. {
  165. scat (", belagert ");
  166. scat (buildingid (u->besieging));
  167. }
  168. if (u->faction == f && !battle && u->money)
  169. {
  170. scat (", $");
  171. icat (u->money);
  172. }
  173. dh = 0;
  174. if (u->faction == f)
  175. {
  176. for (i = 0; i != MAXSKILLS; i++)
  177. spskill (u, i, &dh, 1);
  178. switch (u->enchanted)
  179. {
  180. case SP_NIGHT_EYES:
  181. scat (", ");
  182. if (!dh)
  183. scat ("hat ");
  184. scat ("leuchtende Augen");
  185. break;
  186. case SP_WATER_WALKING:
  187. scat (", ");
  188. if (!dh)
  189. scat ("hat ");
  190. scat ("einen besonders leichtfuessigen Gang");
  191. break;
  192. }
  193. }
  194. dh = 0;
  195. for (i = 0; i != MAXITEMS; i++)
  196. if (u->items[i])
  197. {
  198. if (!dh)
  199. {
  200. scat (strings[ST_HAS][f->language]);
  201. scat (translate (ST_FIRST_QUANTITY_IN_LIST, f->language, u->items[i],
  202. strings[itemnames[u->items[i] != 1][i]][f->language]));
  203. dh = 1;
  204. }
  205. else
  206. scat (translate (ST_QUANTITY_IN_LIST, f->language, u->items[i],
  207. strings[itemnames[u->items[i] != 1][i]][f->language]));
  208. }
  209. if (u->faction == f)
  210. {
  211. dh = 0;
  212. for (i = 0; i != MAXSPELLS; i++)
  213. if (!spell[i].iscombat && u->spells[i])
  214. {
  215. scat (", ");
  216. if (!dh)
  217. {
  218. scat (strings[ST_SPELLS][f->language]);
  219. dh = 1;
  220. }
  221. scat (strings[spell[i].name][f->language]);
  222. }
  223. dh = 0;
  224. for (i = 0; i != MAXSPELLS; i++)
  225. if (spell[i].iscombat && u->spells[i])
  226. {
  227. scat (", ");
  228. if (!dh)
  229. {
  230. scat (strings[ST_COMBAT_SPELLS][f->language]);
  231. dh = 1;
  232. }
  233. scat (strings[spell[i].name][f->language]);
  234. }
  235. if (u->combatspell >= 0)
  236. {
  237. assert (dh);
  238. scat (", ");
  239. scat (strings[ST_SET][f->language]);
  240. scat (strings[spell[u->combatspell].name][f->language]);
  241. }
  242. if (!battle)
  243. {
  244. if (u->lastorder || u->thisorder2)
  245. scat (", Default: ");
  246. if (u->lastorder)
  247. {
  248. scat ("\"");
  249. scat (u->lastorder);
  250. scat ("\"");
  251. }
  252. if (u->lastorder && u->thisorder2)
  253. scat (" und ");
  254. if (u->thisorder2)
  255. {
  256. scat ("\"");
  257. scat (u->thisorder2);
  258. scat ("\"");
  259. }
  260. }
  261. }
  262. i = 0;
  263. if (u->display)
  264. {
  265. scat ("; ");
  266. scat (u->display);
  267. i = u->display[strlen (u->display) - 1];
  268. }
  269. if (i != '!' && i != '?' && i != '.')
  270. scat (".");
  271. return buf;
  272. }
  273. /* ------------------------------------------------------------- */
  274. static int outi;
  275. static char outbuf[1500];
  276. static void
  277. rpc (int c)
  278. {
  279. outbuf[outi++] = c;
  280. assert (outi < (int) sizeof outbuf);
  281. }
  282. static void
  283. rnl (FILE *D)
  284. {
  285. int i;
  286. int rc, vc;
  287. i = outi;
  288. while (i && isspace (outbuf[i - 1]))
  289. i--;
  290. outbuf[i] = 0;
  291. i = 0;
  292. rc = 0;
  293. vc = 0;
  294. while (outbuf[i])
  295. {
  296. switch (outbuf[i])
  297. {
  298. case ' ':
  299. vc++;
  300. break;
  301. case '\t':
  302. vc = (vc & ~7) + 8;
  303. break;
  304. default:
  305. while (rc / 8 != vc / 8)
  306. {
  307. if ((rc & 7) == 7)
  308. fputc (' ', D);
  309. else
  310. fputc ('\t', D);
  311. rc = (rc & ~7) + 8;
  312. }
  313. while (rc != vc)
  314. {
  315. fputc (' ', D);
  316. rc++;
  317. }
  318. fputc (outbuf[i], D);
  319. rc++;
  320. vc++;
  321. }
  322. i++;
  323. }
  324. fputc ('\n', D);
  325. outi = 0;
  326. }
  327. static void
  328. rps (char *s)
  329. {
  330. rpc (' '); /* neuer rand */
  331. while (*s)
  332. rpc (*s++);
  333. }
  334. static void
  335. rpstrlist (FILE *D, strlist * S)
  336. {
  337. while (S)
  338. {
  339. rps (S->s);
  340. rnl (D);
  341. S = S->next;
  342. }
  343. }
  344. static void
  345. crpstrlist (FILE *D, char *title, strlist * S)
  346. {
  347. fprintf (D, "%s\n", title);
  348. while (S)
  349. {
  350. fprintf (D, "\"%s\"\n", S->s);
  351. S = S->next;
  352. }
  353. }
  354. void
  355. rparagraph (FILE *D, char *s, int indent, int mark)
  356. {
  357. strlist *S;
  358. S = 0;
  359. sparagraph (&S, s, indent, mark);
  360. rpstrlist (D, S);
  361. freelist (S);
  362. }
  363. void
  364. rpunit (FILE *D, faction * f, region * r, unit * u, int indent)
  365. {
  366. strlist *S;
  367. rnl (D); /* neue leerzeile */
  368. S = 0;
  369. (void)spunit (f, r, u, 0);
  370. sparagraph (&S, buf + 1, indent, buf[0]);
  371. rpstrlist (D, S);
  372. freelist (S);
  373. }
  374. static void
  375. center (FILE *D, char *s)
  376. {
  377. int i;
  378. /* Bei Namen die genau 80 Zeichen lang sind, kann es hier Probleme geben.
  379. Seltsamerweise wird i dann auf MAXINT oder aehnlich initialisiert.
  380. Deswegen keine Strings die laenger als REPORTWIDTH sind! */
  381. assert (REPORTWIDTH >= strlen (s));
  382. for (i = (REPORTWIDTH - (int)strlen (s)) / 2; i; i--)
  383. rpc (' ');
  384. rps (s);
  385. rnl (D);
  386. }
  387. static void
  388. untitled_strlist (FILE *D, strlist * S)
  389. {
  390. strlist *T;
  391. while (S)
  392. {
  393. T = 0;
  394. sparagraph (&T, S->s, 0, 0);
  395. rpstrlist (D, T);
  396. freelist (T);
  397. S = S->next;
  398. }
  399. }
  400. static void
  401. titled_strlist (FILE *D, char *s, strlist * S)
  402. {
  403. if (S)
  404. {
  405. rnl (D);
  406. rps (s);
  407. rnl (D);
  408. rnl (D);
  409. untitled_strlist (D, S);
  410. }
  411. }
  412. static void
  413. centred_title_strlist (FILE *D, char *s, strlist * S)
  414. {
  415. strlist *T;
  416. if (S)
  417. {
  418. rnl (D);
  419. center (D, s);
  420. rnl (D);
  421. while (S)
  422. {
  423. T = 0;
  424. if (S->s[0] == '*' || S->s[0] == '-')
  425. /* Eine Einheit in f->battles, muss noch formatiert werden. */
  426. sparagraph (&T, S->s + 1, 4, S->s[0]);
  427. else
  428. sparagraph (&T, S->s, 0, 0);
  429. rpstrlist (D, T);
  430. freelist (T);
  431. S = S->next;
  432. }
  433. }
  434. }
  435. static void
  436. centred_paragraph (FILE *D, char *s)
  437. {
  438. strlist *S;
  439. S = 0;
  440. sparagraph (&S, s, 0, 0);
  441. while (S)
  442. {
  443. center (D, S->s);
  444. S = S->next;
  445. }
  446. freelist (S);
  447. }
  448. /* ------------------------------------------------------------- */
  449. static void
  450. prices (FILE *D, region *r, faction *f)
  451. {
  452. int i;
  453. /* Beginne Paragraphen */
  454. if (r->buildings)
  455. strcpy (buf, strings[ST_CURRENT_PRICES][f->language]);
  456. else
  457. strcpy (buf, strings[ST_PRICES_WITHOUT_BUILDINGS][f->language]);
  458. for (i = 0; i != MAXLUXURIES; i++)
  459. {
  460. if (i==0)
  461. scat (translate (ST_FIRST_PRICE, f->language, strings[itemnames[1][FIRSTLUXURY + i]][f->language],
  462. itemprice[i] * r->demand[i] / 100));
  463. else if (i == MAXLUXURIES - 1)
  464. scat (translate (ST_LAST_PRICE, f->language, strings[itemnames[1][FIRSTLUXURY + i]][f->language],
  465. itemprice[i] * r->demand[i] / 100));
  466. else
  467. scat (translate (ST_PRICE, f->language, strings[itemnames[1][FIRSTLUXURY + i]][f->language],
  468. itemprice[i] * r->demand[i] / 100));
  469. }
  470. scat (translate (ST_PEASANTS_MAKE, f->language,
  471. strings[itemnames[1][FIRSTLUXURY + r->produced_good]][f->language]));
  472. /* Schreibe Paragraphen */
  473. rparagraph (D, buf, 0, 0);
  474. }
  475. /* ------------------------------------------------------------- */
  476. static int
  477. roads (region * r)
  478. {
  479. return (r->road && r->road >= roadreq[r->terrain]);
  480. }
  481. int
  482. roadto (region * r, region * r2)
  483. {
  484. /* wenn es hier genug strassen gibt, und verbunden ist, und es dort genug
  485. strassen gibt, dann existiert eine strasse in diese richtung */
  486. int i;
  487. if (!r || !r2 || !roads (r) || !roads (r2))
  488. return 0;
  489. for (i = 0; i != MAXDIRECTIONS; i++)
  490. if (r->connect[i] == r2)
  491. return 1;
  492. return 0;
  493. }
  494. /* ------------------------------------------------------------- */
  495. void
  496. describe (FILE *D, region *r, faction *f)
  497. {
  498. int dh, n, d, i;
  499. /* Name */
  500. strcpy (buf, regionid (r));
  501. /* Terrain */
  502. scat (", ");
  503. scat (strings[terrainnames[mainterrain (r)]][f->language]);
  504. /* Baeume */
  505. if (r->trees)
  506. {
  507. scat (", ");
  508. scat (translate (r->trees != 1 ? ST_TREES : ST_TREE, f->language, r->trees));
  509. }
  510. /* Bauern & Geld */
  511. if (r->peasants)
  512. {
  513. scat (", ");
  514. scat (translate (r->peasants != 1 ? ST_PEASANTS : ST_PEASANT, f->language, r->peasants));
  515. if (r->money)
  516. {
  517. scat (", $");
  518. icat (r->money);
  519. }
  520. }
  521. /* Pferde */
  522. if (r->horses)
  523. scat (translate (ST_QUANTITY_IN_LIST, f->language, r->horses,
  524. strings[itemnames[r->horses > 1][I_HORSE]][f->language]));
  525. scat (".");
  526. /* Strassen */
  527. n = 0;
  528. if (!roads (r))
  529. {
  530. /* Strassen nicht vollstaendig */
  531. if (r->road)
  532. {
  533. scat (" Das Strassennetz ist zu ");
  534. icat (100 * r->road / roadreq[r->terrain]);
  535. scat ("% vollendet.");
  536. }
  537. /* ohne Strassen, keine besondere Meldung */
  538. }
  539. else
  540. {
  541. /* Strassenverbindungen zaehlen */
  542. for (d = 0; d != MAXDIRECTIONS; d++)
  543. if (roadto (r, r->connect[d]))
  544. n++;
  545. /* Der Satz beginnt */
  546. if (!n)
  547. {
  548. /* Strassen ohne weitere Verbindungen */
  549. scat (" Ein Strassennetz ueberzieht die Region.");
  550. }
  551. else
  552. {
  553. /* Strassen mit weiteren Verbindungen */
  554. if (n == 1)
  555. scat (" Eine Strasse fuehrt");
  556. else
  557. scat (" Strassen fuehren");
  558. dh = 0;
  559. i = 0;
  560. for (d = 0; d != MAXDIRECTIONS; d++)
  561. if (roadto (r, r->connect[d]))
  562. {
  563. /* "und" vor dem letzten, aber nicht beim ersten */
  564. i++;
  565. if (dh)
  566. {
  567. if (i == n)
  568. scat (" und");
  569. else
  570. scat (",");
  571. }
  572. dh = 1;
  573. scat (" nach ");
  574. scat (directions[d]);
  575. scat (" ");
  576. scat (roadinto[mainterrain (r->connect[d])]);
  577. scat (" ");
  578. scat (regionid (r->connect[d]));
  579. }
  580. scat (".");
  581. }
  582. }
  583. /* Richtungen ohne Strassen zaehlen */
  584. n = 0;
  585. for (d = 0; d != MAXDIRECTIONS; d++)
  586. if (!roadto (r, r->connect[d]))
  587. n++;
  588. if (n)
  589. {
  590. scat (" Im");
  591. dh = 0;
  592. i = 0;
  593. for (d = 0; d != MAXDIRECTIONS; d++)
  594. if (!roadto (r, r->connect[d]))
  595. {
  596. /* "und" vor dem letzten, aber nicht beim ersten */
  597. i++;
  598. if (dh)
  599. {
  600. if (i == n)
  601. scat (" und im");
  602. else
  603. scat (", im");
  604. }
  605. scat (" ");
  606. scat (directions[d]);
  607. scat (" ");
  608. if (!dh)
  609. {
  610. /* Fallunterscheidung bei "Berge", falls die erste Region "Berge" heisst. */
  611. if (mainterrain (r->connect[d]) == T_MOUNTAIN)
  612. scat ("liegen ");
  613. else
  614. scat ("liegt ");
  615. }
  616. scat (trailinto[mainterrain (r->connect[d])]);
  617. scat (" ");
  618. scat (regionid (r->connect[d]));
  619. dh = 1;
  620. }
  621. scat (".");
  622. }
  623. /* Beschreibung */
  624. if (r->display)
  625. {
  626. scat (" ");
  627. scat (r->display);
  628. n = r->display[strlen (r->display) - 1];
  629. if (n != '!' && n != '?' && n != '.')
  630. scat (".");
  631. }
  632. /* Schreibe Paragraphen */
  633. rparagraph (D, buf, 0, 0);
  634. /* Kommentare, zB. Effekte von Zauberspruechen wie "Nebelnetze" */
  635. if (r->comments)
  636. untitled_strlist (D, r->comments);
  637. }
  638. static void
  639. guards (FILE *D, region *r)
  640. {
  641. faction *f;
  642. unit *u;
  643. int i, n;
  644. /* Bewachung */
  645. for (u = r->units; u; u = u->next)
  646. if (u->guard)
  647. break;
  648. if (!u)
  649. return;
  650. for (f = factions; f; f = f->next)
  651. f->dh = 0;
  652. n = 0;
  653. for (u = r->units; u; u = u->next)
  654. if (u->guard)
  655. {
  656. u->faction->dh = 1;
  657. n++;
  658. }
  659. strcpy (buf, "Die Region wird von ");
  660. i = 0;
  661. n = 0;
  662. for (f = factions; f; f = f->next)
  663. if (f->dh)
  664. {
  665. i++;
  666. if (n)
  667. {
  668. if (i == n)
  669. scat (" und ");
  670. else
  671. scat (", ");
  672. }
  673. n = 1;
  674. scat (factionid (f));
  675. }
  676. scat (" bewacht.");
  677. rnl (D);
  678. rparagraph (D, buf, 0, 0);
  679. }
  680. static void
  681. statistics (FILE *D, region * r, faction * f)
  682. {
  683. unit *u;
  684. building *b;
  685. strlist *S;
  686. int i, number, money, maxwork, rmoney, items[MAXITEMS], wage;
  687. S = 0;
  688. /* Arbeiten. */
  689. if (production[r->terrain])
  690. {
  691. wage = WAGE;
  692. b = largestbuilding (r);
  693. if (b)
  694. wage += buildingeffsize (b) * BONUS;
  695. sprintf (buf, "Lohn fuer einen Monat Arbeiten: $%d", wage);
  696. addstrlist (&S, buf);
  697. maxwork = (production[r->terrain] - r->trees) * MAXPEASANTS_PER_AREA;
  698. sprintf (buf, "Arbeitsplaetze in der Region diesen Monat: max. %d", maxwork);
  699. addstrlist (&S, buf);
  700. rmoney = min (r->peasants, (production[r->terrain] - r->trees) * MAXPEASANTS_PER_AREA) * wage;
  701. sprintf (buf, "Erwarteter Lohn der arbeitenden Bauern: ca. $%d", rmoney);
  702. addstrlist (&S, buf);
  703. rmoney += r->money;
  704. sprintf (buf, "Davon Geld fuer Unterhaltung: max. $%d", rmoney / ENTERTAINFRACTION);
  705. addstrlist (&S, buf);
  706. rmoney -= rmoney / ENTERTAINFRACTION + r->peasants * MAINTENANCE;
  707. rmoney = max (rmoney, 0);
  708. sprintf (buf, "Steuern fuer eine stabile Population bei max. Unterhaltung: $%d", rmoney);
  709. addstrlist (&S, buf);
  710. sprintf (buf, "Kaufkraft der Bauern bei max. Unterhaltung: $%d", rmoney);
  711. addstrlist (&S, buf);
  712. sprintf (buf, "Anzahl Luxusgueter zu kaufen bei stabilen Preisen: %d",
  713. DEMANDFALL * r->peasants / DEMANDFACTOR);
  714. /* 6x mehr als beim Verkauf */
  715. addstrlist (&S, buf);
  716. sprintf (buf, "Anzahl Luxusgueter zu verkaufen bei stabilen Preisen: %d",
  717. DEMANDRISE * r->peasants / DEMANDFACTOR);
  718. /* Bei 10000 Bauern ist das 25 * 10000 / 2500 = 100. */
  719. addstrlist (&S, buf);
  720. sprintf (buf, "Anzahl rekrutierbarer Bauern: max. %d",
  721. r->peasants / RECRUITFRACTION);
  722. addstrlist (&S, buf);
  723. }
  724. number = 0;
  725. money = 0;
  726. memset (items, 0, sizeof items);
  727. for (u = r->units; u; u = u->next)
  728. if (u->faction == f)
  729. {
  730. number += u->number;
  731. money += u->money;
  732. for (i = 0; i != MAXITEMS; i++)
  733. items[i] += u->items[i];
  734. }
  735. sprintf (buf, "Personen: %d", number);
  736. addstrlist (&S, buf);
  737. sprintf (buf, "Silber: %d", money);
  738. addstrlist (&S, buf);
  739. for (i = 0; i != MAXITEMS; i++)
  740. if (items[i])
  741. {
  742. sprintf (buf, "%s: %d", strings[itemnames[1][i]][f->language], items[i]);
  743. addstrlist (&S, buf);
  744. }
  745. /* Ausgabe */
  746. titled_strlist (D, "Statistik", S);
  747. freelist (S);
  748. }
  749. static void
  750. template_unit (strlist *S, unit *u)
  751. {
  752. /* In order_template () verwendet man *S, und damit das dortige *S
  753. manipuliert werden kann, verwenden wir hier also **S. */
  754. /* Einheit mit Name. */
  755. sprintf (buf, "%s %d;\t\t%s [%d, $%d]", parameters[P_UNIT],
  756. u->no, u->name, u->number, u->money);
  757. addstrlist (&S, buf);
  758. /* Default Befehl. */
  759. if (u->lastorder)
  760. {
  761. sprintf (buf, " %s", u->lastorder);
  762. addstrlist (&S, buf);
  763. }
  764. if (u->thisorder2)
  765. {
  766. sprintf (buf, " %s", u->thisorder2);
  767. addstrlist (&S, buf);
  768. }
  769. }
  770. static void
  771. order_template (FILE *D, faction *f)
  772. {
  773. strlist *S;
  774. region *r;
  775. building *b;
  776. ship *sh;
  777. unit *u;
  778. S = 0;
  779. addstrlist (&S, "");
  780. addstrlist (&S, "");
  781. addstrlist (&S, "Vorlage fuer den naechsten Zug:");
  782. addstrlist (&S, "");
  783. sprintf (buf, "%s %d \"%s\"", parameters[P_FACTION], f->no,
  784. f->passw ? f->passw : "");
  785. addstrlist (&S, buf);
  786. for (r = regions; r; r = r->next)
  787. {
  788. /* Nur falls es units gibt. */
  789. for (u = r->units; u; u = u->next)
  790. if (u->faction == f)
  791. break;
  792. if (!u)
  793. continue;
  794. /* Region */
  795. addstrlist (&S, "");
  796. addstrlist (&S, "");
  797. sprintf (buf, "; %s", regionid (r));
  798. addstrlist (&S, buf);
  799. /* Einheiten in Burgen */
  800. for (b = r->buildings; b; b = b->next)
  801. {
  802. addstrlist (&S, "");
  803. sprintf (buf, "; BURG %d\t\t%s", b->no, b->name);
  804. addstrlist (&S, buf);
  805. for (u = r->units; u; u = u->next)
  806. if (u->faction == f && u->building == b && u->owner)
  807. template_unit (S, u);
  808. for (u = r->units; u; u = u->next)
  809. if (u->faction == f && u->building == b && !u->owner)
  810. template_unit (S, u);
  811. }
  812. /* Einheiten in Schiffen */
  813. for (sh = r->ships; sh; sh = sh->next)
  814. {
  815. addstrlist (&S, "");
  816. sprintf (buf, "; SCHIFF %d\t\t%s", sh->no, sh->name);
  817. addstrlist (&S, buf);
  818. for (u = r->units; u; u = u->next)
  819. if (u->faction == f && u->ship == sh && u->owner)
  820. template_unit (S, u);
  821. for (u = r->units; u; u = u->next)
  822. if (u->faction == f && u->ship == sh && !u->owner)
  823. template_unit (S, u);
  824. }
  825. /* Restliche Einheiten */
  826. addstrlist (&S, "");
  827. for (u = r->units; u; u = u->next)
  828. if (u->faction == f && !u->building && !u->ship && cansee (f, r, u))
  829. template_unit (S, u);
  830. }
  831. /* Zum Schluss: NAECHSTER. */
  832. addstrlist (&S, "");
  833. sprintf (buf, parameters[P_NEXT]);
  834. addstrlist (&S, buf);
  835. rpstrlist (D, S);
  836. freelist (S);
  837. }
  838. static void
  839. allies (FILE *D, faction * f)
  840. {
  841. int dh, m, i;
  842. rfaction *rf;
  843. if (f->allies)
  844. {
  845. m = 0;
  846. for (rf = f->allies; rf; rf = rf->next)
  847. m++;
  848. dh = 0;
  849. strcpy (buf, "Wir helfen folgenden Parteien: ");
  850. i = 0;
  851. for (rf = f->allies; rf; rf = rf->next)
  852. {
  853. i++;
  854. if (dh)
  855. {
  856. if (i == m)
  857. scat (" und ");
  858. else
  859. scat (", ");
  860. }
  861. dh = 1;
  862. scat (factionid (rf->faction));
  863. }
  864. scat (".");
  865. rnl (D);
  866. rparagraph (D, buf, 0, 0);
  867. }
  868. }
  869. void
  870. report_computer (FILE *D, faction * f)
  871. {
  872. int i, visible, d, wage, rmoney;
  873. region *r;
  874. rfaction *rf;
  875. building *b;
  876. ship *sh;
  877. unit *u;
  878. /* Wurde fuer diese Variable ein Kommentar gezeigt? */
  879. int cr=0, cu=0, cuu=0, cb=0, cs=0, csp=0;
  880. /* Computer Report Kommentare sind nicht sprachunabhaengig! */
  881. printf ("- Computer Report fuer %s...\n", factionid (f));
  882. fprintf (D, "VERSION %d; Version des Computer Reports\n", C_REPORT_VERSION);
  883. fprintf (D, "PARTEI %d\n", f->no);
  884. fprintf (D, "%d; Runde\n", turn);
  885. fprintf (D, "\"%s\"; ZAT\n", zat);
  886. fprintf (D, "\"%s\"; Passwort\n", f->passw ? f->passw : "");
  887. crpstrlist (D, "FEHLER", f->mistakes);
  888. crpstrlist (D, "WARNUNGEN", f->warnings);
  889. crpstrlist (D, "MELDUNGEN", f->messages);
  890. crpstrlist (D, "KAEMPFE", f->battles);
  891. crpstrlist (D, "EREIGNISSE", f->events);
  892. crpstrlist (D, "EINKOMMEN", f->income);
  893. crpstrlist (D, "HANDEL", f->commerce);
  894. crpstrlist (D, "PRODUKTION", f->production);
  895. crpstrlist (D, "BEWEGUNGEN", f->movement);
  896. fputs ("ZAUBER\n", D);
  897. for (i = 0; i != MAXSPELLS; i++)
  898. if (f->showdata[i])
  899. {
  900. fprintf (D, "\"%s\"%s\n", strings[spell[i].name][f->language], !csp ? "; Spruch" : "");
  901. fprintf (D, "%d%s\n", spell[i].level, !csp ? "; Stufe" : "");
  902. fprintf (D, "\"%s\"%s\n", strings[spell[i].description][f->language], !csp ? "; Beschreibung" : "");
  903. csp = 1;
  904. }
  905. fputs ("ALLIIERTE\n", D);
  906. for (i = 0, rf = f->allies; rf; rf = rf->next, i = 1)
  907. {
  908. fprintf (D, "%d%s\n", rf->faction->no, !i ? "; Partei" : "");
  909. fprintf (D, "\"%s\"%s\n", rf->faction->name ? rf->faction->name : "", !i ? "; Parteiname" : "");
  910. }
  911. for (r = regions; r; r = r->next)
  912. {
  913. for (u = r->units; u; u = u->next)
  914. if (u->faction == f)
  915. break;
  916. if (!u)
  917. continue;
  918. fprintf (D, "REGION %d %d\n", r->x, r->y);
  919. fprintf (D, "\"%s\"%s\n", r->name ? r->name : "", !cr ? "; Name" : "");
  920. fprintf (D, "\"%s\"%s\n", r->display ? r->display : "", !cr ? "; Beschreibung" : "");
  921. fprintf (D, "\"%s\"%s\n", strings[terrainnames[mainterrain (r)]][f->language], !cr ? "; Terrain" : "");
  922. fprintf (D, "%d%s\n", r->trees, !cr ? "; Baeume" : "");
  923. fprintf (D, "%d%s\n", r->peasants, !cr ? "; Bauern" : "");
  924. fprintf (D, "%d%s\n", r->money, !cr ? "; Silber" : "");
  925. fprintf (D, "%d%s\n", r->horses, !cr ? "; Pferde" : "");
  926. fprintf (D, "%d%s\n",
  927. roadreq[r->terrain]
  928. ? 100 * r->road / roadreq[r->terrain] : 0,
  929. !cr ? "; Prozent der Strasse" : "");
  930. /* Statistik */
  931. wage = 0;
  932. if (production[r->terrain])
  933. {
  934. wage = WAGE;
  935. b = largestbuilding (r);
  936. if (b)
  937. wage += buildingeffsize (b) * BONUS;
  938. }
  939. fprintf (D, "%d%s\n", wage,
  940. !cr ? "; Lohn fuer einen Monat Arbeiten" : "");
  941. rmoney = min (r->peasants, (production[r->terrain] - r->trees) * MAXPEASANTS_PER_AREA) * wage;
  942. fprintf (D, "%d%s\n", rmoney,
  943. !cr ? "; erwarteter Lohn der arbeitenden Bauern" : "");
  944. rmoney += r->money;
  945. fprintf (D, "%d%s\n", rmoney / ENTERTAINFRACTION,
  946. !cr ? "; davon max. fuer Unterhaltung" : "");
  947. rmoney -= rmoney / ENTERTAINFRACTION + r->peasants * MAINTENANCE;
  948. rmoney = max (rmoney, 0);
  949. fprintf (D, "%d%s\n", rmoney,
  950. !cr ? "; Steuern fuer eine stabile Population bei max. Unterhaltung" : "");
  951. fprintf (D, "%d%s\n", rmoney,
  952. !cr ? "; Kaufkraft der Bauern bei max. Unterhaltung" : "");
  953. /* DEMANDFALL / DEMANDRISE = 6! */
  954. if (!cr)
  955. fprintf (D, "%d; Anzahl Luxusgueter zu verkaufen bei stabilen Preisen (kaufen: %dx mehr)\n",
  956. DEMANDRISE * r->peasants / DEMANDFACTOR,
  957. DEMANDFALL / DEMANDRISE);
  958. else
  959. fprintf (D, "%d\n", DEMANDRISE * r->peasants / DEMANDFACTOR);
  960. fprintf (D, "%d%s\n", r->peasants / RECRUITFRACTION, !cr ? "; Rekrutieren" : "");
  961. for (d = 0; d != MAXDIRECTIONS; d++)
  962. {
  963. fprintf (D, "\"%s\"%s%s\n",
  964. strings[terrainnames[mainterrain (r->connect[d])]][f->language],
  965. !cr ? "; " : "",
  966. !cr ? directions[d] : "");
  967. fprintf (D, "\"%s\"%s\n",
  968. regionid (r->connect[d]),
  969. !cr ? "; Name der Region" : "");
  970. }
  971. fputs ("PREISE\n", D);
  972. for (i = 0; i != MAXLUXURIES; i++)
  973. fprintf (D, "%d%s%s\n",
  974. r->terrain != T_OCEAN
  975. ? (itemprice[i] * r->demand[i] / 100
  976. * (i == r->produced_good ? -1 : 1))
  977. : 0,
  978. (!cr
  979. ? (i == r->produced_good
  980. ? "; Preis (wird produziert, daher negativ) "
  981. : "; Preis")
  982. : ""),
  983. !cr ? strings[itemnames[1][FIRSTLUXURY + i]][0] : "");
  984. for (b = r->buildings; b; b = b->next)
  985. {
  986. fprintf (D, "BURG %d\n", b->no);
  987. fprintf (D, "\"%s\"%s\n", b->name ? b->name : "",
  988. !cb ? "; Name" : "");
  989. fprintf (D, "\"%s\"%s\n", b->display ? b->display : "",
  990. !cb ? "; Beschreibung" : "");
  991. fprintf (D, "%d%s\n", b->size,
  992. !cb ? "; Groesse" : "");
  993. u = buildingowner (r, b);
  994. fprintf (D, "%d%s\n", u ? u->no : -1,
  995. !cb ? "; Burgherr (-1 = niemand)" : "");
  996. fprintf (D, "%d%s\n", u && cansee (f, r, u) == 2
  997. ? u->faction->no
  998. : -1,
  999. !cb ? "; Partei des Burgherren (-1 = unbekannt)" : "");
  1000. cb = 1;
  1001. }
  1002. for (sh = r->ships; sh; sh = sh->next)
  1003. {
  1004. fprintf (D, "SCHIFF %d\n", sh->no);
  1005. fprintf (D, "\"%s\"%s\n", sh->name ? sh->name : "",
  1006. !cs ? "; Name" : "");
  1007. fprintf (D, "\"%s\"%s\n", sh->display ? sh->display : "",
  1008. !cs ? "; Beschreibung" : "");
  1009. fprintf (D, "\"%s\"%s\n", shiptypes[0][sh->type],
  1010. !cs ? "; Typ" : "");
  1011. fprintf (D, "%d%s\n",
  1012. 100 * (shipcost[sh->type] - sh->left) / shipcost[sh->type],
  1013. !cs ? "; Prozent Vollendet" : "");
  1014. u = shipowner (r, sh);
  1015. fprintf (D, "%d%s\n", u ? u->no : -1,
  1016. !cs ? "; Kapitaen (-1 = niemand)" : "");
  1017. fprintf (D, "%d%s\n", u && cansee (f, r, u) == 2
  1018. ? u->faction->no
  1019. : -1,
  1020. !cs ? "; Partei des Kapitaens (-1 = unbekannt)" : "");
  1021. cs = 1;
  1022. }
  1023. for (u = r->units; u; u = u->next)
  1024. if ((visible = cansee (f, r, u)))
  1025. {
  1026. fprintf (D, "EINHEIT %d\n", u->no);
  1027. fprintf (D, "\"%s\"%s\n", u->name ? u->name : "",
  1028. !cu ? "; Name" : "");
  1029. fprintf (D, "\"%s\"%s\n", u->display ? u->display : "",
  1030. !cu ? "; Beschreibung" : "");
  1031. fprintf (D, "%d%s\n", visible == 2 ? u->faction->no : -1,
  1032. !cu ? "; Partei (-1 = unbekannt)" : "");
  1033. fprintf (D, "\"%s\"%s\n",
  1034. visible == 2
  1035. ? (u->faction->name ? u->faction->name : "")
  1036. : "",
  1037. !cu ? "; Parteiname" : "");
  1038. fprintf (D, "%d%s\n", u->number,
  1039. !cu ? "; Anzahl" : "");
  1040. fprintf (D, "\"%s\"%s\n", u->type == U_ILLUSION && u->faction != f
  1041. ? strings[types[U_MAN].names[1]][f->language]
  1042. : strings[types[u->type].names[1]][f->language],
  1043. !cu ? "; Typ" : "");
  1044. fprintf (D, "%d%s\n",
  1045. u->building ? u->building->no : 0,
  1046. !cu ? "; Burg Nr." : "");
  1047. fprintf (D, "%d%s\n",
  1048. u->ship ? u->ship->no : 0,
  1049. !cu ? "; Schiff Nr." : "");
  1050. fprintf (D, "%d%s\n", u->guard,
  1051. !cu ? "; bewacht Region" : "");
  1052. if (u->faction == f)
  1053. {
  1054. fprintf (D, "%d%s\n", u->money,
  1055. !cuu ? "; Silber" : "");
  1056. fprintf (D, "%d%s\n", u->status,
  1057. !cuu ? "; kaempft (0-ja, 1-hinten, 2-nein)" : "");
  1058. fprintf (D, "\"%s\"%s\n", u->lastorder ? u->lastorder : "",
  1059. !cuu ? "; Default" : "");
  1060. fputs ("TALENTE\n", D);
  1061. for (d = 0; d != MAXSKILLS; d++)
  1062. fprintf (D, "%d %d%s%s\n", u->skills[d], effskill (u, d),
  1063. !cuu ? "; " : "",
  1064. !cuu ? skillnames[d] : "");
  1065. fputs ("SPRUECHE\n", D);
  1066. csp = 0;
  1067. for (d = 0; d != MAXSPELLS; d++)
  1068. if (u->spells[d])
  1069. {
  1070. fprintf (D, "\"%s\"%s\n", strings[spell[d].name][f->language],
  1071. !csp ? "; Spruch" : "");
  1072. csp = 1;
  1073. }
  1074. cuu = 1;
  1075. }
  1076. fputs ("GEGENSTAENDE\n", D);
  1077. for (d = 0; d != LASTLUXURY; d++)
  1078. fprintf (D, "%d%s%s\n", u->items[d],
  1079. !cu ? "; " : "",
  1080. !cu ? strings[itemnames[0][d]][0] : "");
  1081. /* Magische Gegenstaende werden nur angezeigt, falls man diese auch wirklich besitzt. */
  1082. fputs ("MAGISCHES\n", D);
  1083. for (d = FIRST_MAGIC_ITEM; d != LAST_MAGIC_ITEM; d++)
  1084. if (u->items[d])
  1085. fprintf (D, "%d \"%s\"%s\n", u->items[d], strings[itemnames[0][d]][f->language],
  1086. !cu ? "; magischer Gegenstand" : "");
  1087. cu = 1;
  1088. }
  1089. cr = 1;
  1090. }
  1091. }
  1092. void
  1093. report (FILE *D, faction * f)
  1094. {
  1095. int i;
  1096. int anyunits;
  1097. region *r;
  1098. building *b;
  1099. ship *sh;
  1100. unit *u;
  1101. char wants_stats;
  1102. char wants_debug;
  1103. i = 1 << O_STATISTICS;
  1104. wants_stats = (f->options & i);
  1105. i = 1 << O_DEBUG;
  1106. wants_debug = (f->options & i);
  1107. printf ("- Report fuer %s...\n", factionid (f));
  1108. center (D, strings[ST_ATLANTIS_REPORT][f->language]);
  1109. centred_paragraph (D, factionid (f));
  1110. center (D, gamedate (f));
  1111. strcpy (buf, translate (ST_ZAT, f->language, zat));
  1112. center (D, buf);
  1113. centred_title_strlist (D, strings[ST_MISTAKES][f->language], f->mistakes);
  1114. centred_title_strlist (D, strings[ST_WARNINGS][f->language], f->warnings);
  1115. centred_title_strlist (D, strings[ST_MESSAGES][f->language], f->messages);
  1116. centred_title_strlist (D, strings[ST_BATTLES][f->language], f->battles);
  1117. if (wants_debug) /* Debug ist nicht sprachunabhaengig! */
  1118. {
  1119. centred_title_strlist (D, "Debug", f->debug);
  1120. printf (" %s hat DEBUG gesetzt!\n", factionid (f));
  1121. }
  1122. centred_title_strlist (D, strings[ST_MISCELLANEOUS][f->language], f->events);
  1123. centred_title_strlist (D, strings[ST_INCOME][f->language], f->income);
  1124. centred_title_strlist (D, strings[ST_COMMERCE][f->language], f->commerce);
  1125. centred_title_strlist (D, strings[ST_PRODUCTION][f->language], f->production);
  1126. centred_title_strlist (D, strings[ST_MOVEMENTS][f->language], f->movement);
  1127. for (i = 0; i != MAXSPELLS; i++)
  1128. if (f->showdata[i])
  1129. break;
  1130. if (i != MAXSPELLS)
  1131. {
  1132. rnl (D);
  1133. center (D, strings[ST_NEW_SPELLS][f->language]);
  1134. for (i = 0; i != MAXSPELLS; i++)
  1135. if (f->showdata[i])
  1136. {
  1137. rnl (D);
  1138. center (D, strings[spell[i].name][f->language]);
  1139. strcpy (buf, translate (ST_LEVEL, f->language, spell[i].level));
  1140. center (D, buf);
  1141. rnl (D);
  1142. rparagraph (D, strings[spell[i].description][f->language], 0, 0);
  1143. }
  1144. }
  1145. rnl (D);
  1146. center (D, strings[ST_STATE_OF_AFFAIRS][f->language]);
  1147. allies (D, f);
  1148. anyunits = 0;
  1149. for (r = regions; r; r = r->next)
  1150. {
  1151. /* nur report, falls es units gibt */
  1152. for (u = r->units; u; u = u->next)
  1153. if (u->faction == f)
  1154. break;
  1155. if (!u)
  1156. continue;
  1157. anyunits = 1;
  1158. /* Debug */
  1159. if (wants_debug && r->debug)
  1160. {
  1161. rnl (D); /* leerzeile */
  1162. center (D, "------------------------------------------------------------------------");
  1163. titled_strlist (D, "Debug", r->debug);
  1164. }
  1165. /* Beschreibung */
  1166. rnl (D); /* leerzeile */
  1167. center (D, "------------------------------------------------------------------------");
  1168. rnl (D); /* leerzeile */
  1169. describe (D, r, f);
  1170. /* Preise nur auf dem Festland */
  1171. if (r->terrain != T_OCEAN)
  1172. {
  1173. rnl (D); /* leerzeile */
  1174. prices (D, r, f);
  1175. }
  1176. /* Bewachen */
  1177. guards (D, r);
  1178. /* Statistik */
  1179. if (wants_stats)
  1180. statistics (D, r, f);
  1181. /* Burgen und ihre Einheiten */
  1182. for (b = r->buildings; b; b = b->next)
  1183. {
  1184. rnl (D); /* neue leerzeile */
  1185. sprintf (buf, "%s, %s, %s",
  1186. buildingid (b),
  1187. translate (ST_SIZE, f->language, b->size),
  1188. buildingtype (b));
  1189. if (b->besieged)
  1190. scat (strings[ST_BESIEGED][f->language]);
  1191. i = 0;
  1192. if (b->display)
  1193. {
  1194. scat ("; ");
  1195. scat (b->display);
  1196. i = b->display[strlen (b->display) - 1];
  1197. }
  1198. if (i != '!' && i != '?' && i != '.')
  1199. scat (".");
  1200. rparagraph (D, buf, 4, 0);
  1201. /* Ich vertraue nicht darauf, dass die jeweiligen Kommando
  1202. Inhaber wirklich weiter vorne in der Liste stehen.
  1203. Deswegen werden sie hier explizit wieder gesucht und an
  1204. die erste Stelle gesetzt. Es waere interessant, woher
  1205. diese Fehler herruehren. */
  1206. for (u = r->units; u; u = u->next)
  1207. if (u->building == b && u->owner)
  1208. {
  1209. rpunit (D, f, r, u, 8);
  1210. break;
  1211. }
  1212. for (u = r->units; u; u = u->next)
  1213. if (u->building == b && !u->owner)
  1214. rpunit (D, f, r, u, 8);
  1215. }
  1216. /* Schiffe und ihre Einheiten */
  1217. for (sh = r->ships; sh; sh = sh->next)
  1218. {
  1219. rnl (D); /* neue leerzeile */
  1220. sprintf (buf, "%s, %s", shipid (sh), shiptypes[0][sh->type]);
  1221. if (sh->left)
  1222. {
  1223. if (r->terrain == T_OCEAN)
  1224. {
  1225. scat (", ");
  1226. scat (translate (ST_DAMAGED, f->language,
  1227. 100 * sh->left / shipcost[sh->type]));
  1228. }
  1229. else
  1230. {
  1231. scat (", ");
  1232. scat (translate (ST_INCOMPLETE, f->language,
  1233. 100 * (shipcost[sh->type] - sh->left) / shipcost[sh->type]));
  1234. }
  1235. }
  1236. else
  1237. {
  1238. scat (", ");
  1239. scat (translate (ST_CAPACITY, f->language, capacity (r, sh), shipcapacity[sh->type]));
  1240. }
  1241. i = 0;
  1242. if (sh->display)
  1243. {
  1244. scat ("; ");
  1245. scat (sh->display);
  1246. i = sh->display[strlen (sh->display) - 1];
  1247. }
  1248. if (i != '!' && i != '?' && i != '.')
  1249. scat (".");
  1250. rparagraph (D, buf, 4, 0);
  1251. /* Hier gilt der gleiche Kommentar wie oben bei den Burgen. */
  1252. for (u = r->units; u; u = u->next)
  1253. if (u->ship == sh && u->owner)
  1254. {
  1255. rpunit (D, f, r, u, 8);
  1256. break;
  1257. }
  1258. for (u = r->units; u; u = u->next)
  1259. if (u->ship == sh && !u->owner)
  1260. rpunit (D, f, r, u, 8);
  1261. }
  1262. /* Restliche Einheiten */
  1263. for (u = r->units; u; u = u->next)
  1264. if (!u->building && !u->ship && cansee (f, r, u))
  1265. rpunit (D, f, r, u, 4);
  1266. }
  1267. rnl (D); /* leerzeile */
  1268. center (D, "------------------------------------------------------------------------");
  1269. if (f->no)
  1270. {
  1271. if (!anyunits)
  1272. {
  1273. rnl (D);
  1274. rparagraph (D, strings[ST_NO_MORE_UNITS][f->language], 0, 0);
  1275. }
  1276. else
  1277. order_template (D, f);
  1278. }
  1279. }
  1280. /* ------------------------------------------------------------- */
  1281. static FILE *BAT;
  1282. /* ------------------------------------------------------------- */
  1283. static int
  1284. netaddress (char *s)
  1285. {
  1286. /* Die erste email Adresse wird verwendet. Simulierte regexp:
  1287. [-+._@0-9a-zA-Z]*@[-._@0-9a-zA-Z]* -- es ist moeglich nach der
  1288. adresse noch info - zB. den vollen Namen oder die Tel Nr
  1289. anzufuegen: "alex@zool.unizh.ch - Alexander Schroeder, Tel 01 /
  1290. 313 13 72" ist OK. */
  1291. int i, j;
  1292. char *c;
  1293. if (!s)
  1294. return 0;
  1295. c = strchr (s, '@');
  1296. if (!c)
  1297. return 0;
  1298. /* Setzte buf auf die Netadresse! */
  1299. i = c - s;
  1300. j = 0;
  1301. /* Finde Start der Adresse. Am Ende zeigt i auf den ersten Char,
  1302. der *nicht* mehr zur Adresse gehoert. */
  1303. while (i >= 0 && s[i] &&
  1304. (isalnum (s[i]) ||
  1305. s[i] == '@' ||
  1306. s[i] == '+' ||
  1307. s[i] == '-' ||
  1308. s[i] == '.' ||
  1309. s[i] == '_'))
  1310. i--;
  1311. /* Kopiere Adresse -- zuerst i auf Start der Adresse zeigen lassen.
  1312. Falls s mit der email Adresse began, war i -1, nun wird i++
  1313. gemacht, so dass ab s[0] kopiert wird -- was richtig ist. */
  1314. i++;
  1315. while (s[i] &&
  1316. (isalnum (s[i]) ||
  1317. s[i] == '@' ||
  1318. s[i] == '-' ||
  1319. s[i] == '.' ||
  1320. s[i] == '_'))
  1321. buf[j++] = s[i++];
  1322. /* beende adresse */
  1323. buf[j] = 0;
  1324. /* test der adresse, weitere koennen folgen: */
  1325. if (!strchr (buf, '@'))
  1326. return 0;
  1327. return 1;
  1328. }
  1329. /* ------------------------------------------------------------- */
  1330. static int net_report_count;
  1331. /* ------------------------------------------------------------- */
  1332. static void
  1333. openbatch (char *dir)
  1334. {
  1335. faction *f;
  1336. /* Falls mind. ein Spieler mit email Adresse gefunden wird, schreibe
  1337. den header des batch files. "if (BAT)" kann verwendet werden, um
  1338. zu pruefen ob netspieler vorhanden sind und ins mailit batch
  1339. geschrieben werden darf. Mit dem batch werden auch alle Zeitungen
  1340. und Kommentare verschickt. */
  1341. for (f = factions; f; f = f->next)
  1342. if (netaddress (f->addr))
  1343. break;
  1344. if (f)
  1345. {
  1346. sprintf (buf, "%s/mailit", dir);
  1347. if (!(BAT = fopen (buf, "w")))
  1348. puts ("Die Datei mailit konnte nicht erzeugt werden!");
  1349. else
  1350. fputs (
  1351. "#\n"
  1352. "# MAILIT shell file, vom Atlantis Host generiert\n"
  1353. "#\n"
  1354. "# MAILIT versendet Atlantis Reports fuer alle Spieler, deren Adresse\n"
  1355. "# die Form \"name@machine\" hat.\n"
  1356. "#\n"
  1357. "# Verwendung: nohup sh mailit &\n"
  1358. "#\n"
  1359. "# mailit laeuft im directory \'reports/\'\n"
  1360. "# Es ruft send.sh auf, das die \'zeitung\' und den \'kommentar\'\n"
  1361. "# in das report-Verzeichnis verlinkt, von wo aus sie zusammen\n"
  1362. "# mit den reports *.nr und *.cr versandt werden.\n"
  1363. "#\n"
  1364. "\n"
  1365. ,BAT);
  1366. /* Nachdem die Existenz der Partei 0 bereits an anderer Stelle vorausgesetzt wird */
  1367. fprintf (BAT, "subject=\"%s\"\n",
  1368. gamedate (findfaction(0)) );
  1369. fprintf (BAT, "\n. ../send.sh\n\n");
  1370. net_report_count = 0;
  1371. }
  1372. }
  1373. static void
  1374. closebatch (void)
  1375. {
  1376. if (BAT)
  1377. {
  1378. fputs ( "\n"
  1379. "echo Done!\n", BAT);
  1380. fclose (BAT);
  1381. }
  1382. }
  1383. /* ------------------------------------------------------------- */
  1384. static void
  1385. repdir (char *dir)
  1386. {
  1387. /* macht REPORT subdirectory (falls nicht vorhanden) und loescht alle
  1388. files darin (falls vorhanden) */
  1389. DIR *dp;
  1390. struct dirent *ep;
  1391. dp = opendir (dir);
  1392. if (dp != NULL)
  1393. {
  1394. while ((ep = readdir (dp)))
  1395. unlink (ep->d_name);
  1396. /* XXX unlink macht hier deswegen keinen Aerger,
  1397. * weil Linux Verzeichnisse _nicht_ per unlink loescht.
  1398. */
  1399. closedir (dp);
  1400. }
  1401. else
  1402. mkdir (dir, S_IRWXU);
  1403. }
  1404. /* ------------------------------------------------------------- */
  1405. void
  1406. reports (void)
  1407. {
  1408. faction *f;
  1409. int gotit, wants_report, wants_computer_report, wants_zine,
  1410. wants_comment, wants_compressed;
  1411. FILE *D;
  1412. /* macht REPORT subdirectory (falls nicht vorhanden) und loescht alle
  1413. files darin (falls vorhanden) */
  1414. repdir ("reports");
  1415. /* oeffnet file BAT (mailit batch file) */
  1416. openbatch ("reports");
  1417. wants_report = 1 << O_REPORT;
  1418. wants_computer_report = 1 << O_COMPUTER;
  1419. wants_zine = 1 << O_ZINE;
  1420. wants_comment = 1 << O_COMMENTS;
  1421. wants_compressed = 1 << O_COMPRESS;
  1422. for (f = factions; f; f = f->next)
  1423. {
  1424. gotit = 0;
  1425. /* Schreiben der Reports ind /REPORTS: *.nr sind normale Reports, *.cr sind Computer Reports.
  1426. Netreports werden im mailit file verschickt. Der mailit file
  1427. wird mit BAT gebraucht. */
  1428. if ((f->options & wants_report))
  1429. {
  1430. sprintf (buf, "reports/%d.nr", f->no);
  1431. D = cfopen (buf, "wt");
  1432. if (D != NULL)
  1433. {
  1434. report (D, f);
  1435. fclose (D);
  1436. gotit = 1;
  1437. }
  1438. }
  1439. if ((f->options & wants_computer_report))
  1440. {
  1441. sprintf (buf, "reports/%d.cr", f->no);
  1442. D = cfopen (buf, "wt");
  1443. if (D != NULL)
  1444. {
  1445. report_computer (D, f);
  1446. fclose (D);
  1447. gotit = 1;
  1448. }
  1449. }
  1450. /* Auch Kommentar und Zeitung muss per mail verschickt werden. buf enthaelt die adresse
  1451. nach Aufruf von netaddress.
  1452. BAT sollte gesetzt sein, sonst gab es schon eine Fehlermeldung. */
  1453. if (netaddress (f->addr) && (BAT != NULL) )
  1454. {
  1455. fprintf (BAT, "sleep %d;date;echo %s\n", MAILDELAY, buf);
  1456. fprintf (BAT, "send %d \"%s\" ", f->no, buf);
  1457. if (f->options & wants_compressed)
  1458. fprintf (BAT, "ZIP ");
  1459. if (f->options & wants_report)
  1460. fprintf (BAT, "AUS ");
  1461. if (f->options & wants_computer_report)
  1462. fprintf (BAT, "CR ");
  1463. if (f->options & wants_zine)
  1464. fprintf (BAT, "ZINE ");
  1465. if (f->options & wants_comment)
  1466. fprintf (BAT, "KOM ");
  1467. fprintf (BAT, "\n");
  1468. }
  1469. if (!gotit)
  1470. printf ("Kein Report fuer Partei Nr. %d!\n",
  1471. f->no);
  1472. }
  1473. /* schliesst BAT und verschickt Zeitungen und Kommentare */
  1474. closebatch ();
  1475. }