home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume13 / dominion / part22 < prev    next >
Encoding:
Internet Message Format  |  1992-02-10  |  61.0 KB

  1. Path: uunet!zephyr.ens.tek.com!master!saab!billr
  2. From: billr@saab.CNA.TEK.COM (Bill Randle)
  3. Newsgroups: comp.sources.games
  4. Subject: v13i058:  dominion - a multi-player world simulation game, Part22/28
  5. Message-ID: <2461@masterCNA.TEK.COM>
  6. Date: 11 Feb 92 18:27:08 GMT
  7. Sender: news@masterCNA.TEK.COM
  8. Lines: 2238
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: rosalia@dirac.physics.sunysb.edu (Mark Galassi)
  12. Posting-number: Volume 13, Issue 58
  13. Archive-name: dominion/Part22
  14. Environment: Unix, curses
  15.  
  16.  
  17.  
  18. #! /bin/sh
  19. # This is a shell archive.  Remove anything before this line, then unpack
  20. # it by saving it into a file and typing "sh file".  To overwrite existing
  21. # files, type "sh file -c".  You can also feed this as standard input via
  22. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  23. # will see the following message at the end:
  24. #        "End of archive 22 (of 28)."
  25. # Contents:  cur_stuff.c mag_Monsters mag_Unity menus.c npclib.c
  26. # Wrapped by billr@saab on Tue Feb 11 10:14:57 1992
  27. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  28. if test -f 'cur_stuff.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'cur_stuff.c'\"
  30. else
  31. echo shar: Extracting \"'cur_stuff.c'\" \(18715 characters\)
  32. sed "s/^X//" >'cur_stuff.c' <<'END_OF_FILE'
  33. X  /* cur_stuff.c -- stuff that uses curses a lot */
  34. X
  35. X/*
  36. X * Copyright (C) 1990 Free Software Foundation, Inc.
  37. X * Written by the dominion project.
  38. X *
  39. X * This file is part of dominion.
  40. X *
  41. X * dominion is free software; you can redistribute it and/or
  42. X * modify it under the terms of the GNU General Public License as published
  43. X * by the Free Software Foundation; either version 1, or (at your option)
  44. X * any later version.
  45. X *
  46. X * This software is distributed in the hope that it will be useful,
  47. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  48. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  49. X * GNU General Public License for more details.
  50. X *
  51. X * You should have received a copy of the GNU General Public License
  52. X * along with this software; see the file COPYING.  If not, write to
  53. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  54. X */
  55. X
  56. X/* pager(fname) - pages through a file                             */
  57. X/* mygetch() - runs getch(), and gives help if user types '?'      */
  58. X/* wget_name(w, name) - gets a name in a curses window             */
  59. X/* wget_string(w, str, len) - gets a string in a curses window     */
  60. X/* wget_number(w, p) - gets a number in a curses window            */
  61. X
  62. X#include "dominion.h"
  63. X#include "misc.h"
  64. X#include "cur_stuff.h"
  65. X#include <stdio.h>
  66. X
  67. Xextern Suser user;
  68. Xextern Sworld world;
  69. Xextern int (*keymap[128])(), (*wrapx)(), (*wrapy)();
  70. Xextern struct s_desig_map desig_map[];
  71. Xextern struct s_altitude_map altitude_map[];
  72. Xextern struct item_map terrains[];
  73. X
  74. XWINDOW *sectw;
  75. X/* WINDOW *sectw, *armyw; */
  76. X
  77. X/* statline and statline2 moved to misc.c */
  78. X
  79. X  /* simple standalone pager, used for news and other stuff */
  80. Xpager(fname)
  81. X     char fname[];
  82. X{
  83. X  FILE *fp, *fopen();
  84. X  WINDOW *pagew;
  85. X  long page_lines = LINES-2, lines = 0;
  86. X  char line[200];
  87. X  char c;
  88. X  int i;
  89. X
  90. X  if ((fp = fopen(fname, "r")) == NULL) {
  91. X    statline2_err("cannot open file", fname);
  92. X    return '\0';
  93. X  }
  94. X  pagew = newwin(LINES-2, COLS, 0, 0);
  95. X  touchwin(pagew);
  96. X  lines = 0;
  97. X  while (fgets(line, 180, fp) != NULL) {
  98. X    line[COLS-2] = '\0';    /* make sure it fits on screen */
  99. X    mvwaddstr(pagew, lines, 0, line);
  100. X    wclrtoeol(pagew);
  101. X    wrefresh(pagew);
  102. X    ++lines;
  103. X    if (lines % page_lines == 0) { /* next page? */
  104. X      wclrtobot(pagew);
  105. X      wrefresh(pagew);
  106. X      lines = 0;
  107. X      statline("SPACE to continue, [q] or [n] to leave this file", fname);
  108. X      switch(c = getch()) {
  109. X      case 'q':
  110. X      case 'n':
  111. X    fclose(fp);
  112. X    return c;
  113. X    break;
  114. X      case 'f':            /* skip 23 lines */
  115. X    for (i = 0; i < 23 && fgets(line, 180, fp); ++i) {
  116. X    }
  117. X    break;
  118. X      case ' ':
  119. X    break;
  120. X      default:
  121. X    break;
  122. X      }
  123. X      wmove(pagew, 0, 0);
  124. X    }
  125. X  }
  126. X  fclose(fp);
  127. X  wclrtobot(pagew);
  128. X  wrefresh(pagew);
  129. X  delwin(pagew);
  130. X  return ' ';
  131. X}
  132. X
  133. X  /* draw the world map */
  134. Xdraw_map()
  135. X{
  136. X  if (user.map_style == NORMAL_MAP) {
  137. X    draw_map_regular();
  138. X  } else {
  139. X    draw_map_compact();
  140. X  }
  141. X}
  142. X
  143. X  /* draw the map with a space between adjacent sectors */
  144. Xdraw_map_regular()
  145. X{
  146. X  char s[80];
  147. X  int x = user.cursor.x, y = user.cursor.y /*,
  148. X         xoff = user.center.x-(COLS-2)/4, yoff = user.center.y - (LINES-2)/2*/;
  149. X  int i, j, iw, jw, n;
  150. X  int mark;    /* what to draw in that sector, negative if highlight */
  151. X  Ssector *sp = &world.map[x][y];
  152. X  int visibility;
  153. X
  154. X    /* clean up the space from the previous armies */
  155. X  for (i = 0; i <= 2*user.last_n_armies; ++i) {
  156. X    move(i, ARMYW_X);
  157. X    clrtoeol();
  158. X  }
  159. X  user.last_n_armies = sect_n_armies(sp);
  160. X
  161. X  for (i = xoff(); (i < xoff()+(COLS-2)/2) && (i < xoff()+world.xmax); ++i) {
  162. X    for (j = yoff(); (j < yoff()+LINES-2) && (j < yoff()+world.ymax); ++j) {
  163. X      if (!is_under_sectw(2*(i-xoff()), j-yoff())) {
  164. X          /* now wrap the coordinates, so we handle the topology */
  165. X    move(j-yoff(), 2*(i-xoff()));    /* move does not want wrapping */
  166. X    iw = (*wrapx)(i,j);
  167. X    jw = (*wrapy)(i,j);
  168. X    visibility = user.visible_sectors[iw][jw];
  169. X    if (visibility > SEE_NOTHING && visibility != SEE_ARMIES) {
  170. X      if ((mark = which_mark(iw, jw, &user)) < 0) {
  171. X        standout();
  172. X        addch(-mark);
  173. X        standend();
  174. X      } else {
  175. X        addch(mark);
  176. X      }
  177. X    } else {        /* if not visible, put a space */
  178. X      addch(' ');
  179. X    }
  180. X      }
  181. X    }
  182. X  }
  183. X  show_armies(&world.map[x][y]);
  184. X  sprintf(s, "Nation %s; money %d; Thon %d;   type %c for help",
  185. X      user.np->name, user.np->money, world.turn, user.help_char);
  186. X  statline(s, "draw_map_regular");
  187. X  show_sector(x, y);
  188. X  move((*wrapy)(x-xoff(),y-yoff()), 2*(*wrapx)(x-xoff(),y-yoff()));
  189. X  refresh();
  190. X}
  191. X
  192. Xdraw_map_compact()        /* compact drawing of map */
  193. X{
  194. X  char s[80];
  195. X  int x = user.cursor.x, y = user.cursor.y;
  196. X  int i, j, n;
  197. X  int mark;    /* what to draw in that sector, negative if highlight */
  198. X  Ssector *sp = &world.map[x][y];
  199. X  int visibility;
  200. X
  201. X    /* clean up the space from the previous armie */
  202. X  for (i = 0; i <= 2*user.last_n_armies; ++i) {
  203. X    move(i, ARMYW_X);
  204. X    clrtoeol();
  205. X  }
  206. X  user.last_n_armies = sect_n_armies(sp);
  207. X
  208. X  for (i = xoff_compact();
  209. X       (i < xoff_compact() + COLS-2) && (i < xoff_compact() + world.xmax); ++i) {
  210. X    for (j = yoff(); (j < yoff() + LINES-2) && (j < yoff() + world.ymax); ++j) {
  211. X      move(j-yoff(), i-xoff_compact());
  212. X      visibility = user.visible_sectors[(*wrapx)(i,j)][(*wrapy)(i,j)];
  213. X      if (visibility > SEE_NOTHING && visibility != SEE_ARMIES) {
  214. X    if ((mark = which_mark((*wrapx)(i,j), (*wrapy)(i,j), &user)) < 0) {
  215. X      standout();
  216. X      addch(-mark);
  217. X      standend();
  218. X    } else {
  219. X      addch(mark);
  220. X    }
  221. X      } else {            /* if not visible, put a space */
  222. X    addch(' ');
  223. X      }
  224. X    }
  225. X  }
  226. X  show_armies(&world.map[x][y]);
  227. X  sprintf(s, "Nation %s; money %d; Thon %d;   type %c for help",
  228. X      user.np->name, user.np->money, world.turn, user.help_char);
  229. X  statline(s, "draw_map_compact");
  230. X  show_sector(user.cursor.x, user.cursor.y);
  231. X  move((*wrapy)(x-xoff_compact(),y-yoff()), (*wrapx)(x-xoff_compact(),y-yoff()));
  232. X  refresh();
  233. X}
  234. X
  235. Xshow_sector(x, y)        /* give info on the sector */
  236. X     int x, y;
  237. X{
  238. X  Ssector *sp = &world.map[x][y];
  239. X  char s[2*NAMELEN];
  240. X  int visibility = user.visible_sectors[x][y];
  241. X
  242. X  if (user.show_sect_win && user.just_moved) {
  243. X    /* put the stuff in the special sector window */
  244. X  mvwprintw(sectw, 1, 1, "(%d,%d)", xrel(x,y,user.np->capital),
  245. X        yrel(x,y,user.np->capital));
  246. X
  247. X  wclrtobot(sectw);
  248. X
  249. X    /* Show sector name if they can see the population of the sector! */
  250. X  if (visibility & SEE_POPULATION) {
  251. X    wprintw(sectw," %s", sp->name);
  252. X  }
  253. X  
  254. X    /* Shows owner if can see owner */
  255. X  wmove(sectw, 2, 1);
  256. X  if ((visibility & SEE_OWNER) && (sp->owner!=0)) {
  257. X    wprintw(sectw,"%s-", world.nations[sp->owner].name);
  258. X  }
  259. X  
  260. X    /* Shows designation if can see designation */
  261. X  if (visibility & SEE_DESIG) {
  262. X    if (sp->owner != 0 || sp->designation != D_NODESIG) {
  263. X      wprintw(sectw, "%s", desig_map[sp->designation].name);
  264. X      if (has_bubble(sp)) {
  265. X    waddstr(sectw, "/B");
  266. X      }
  267. X      if (has_hidden(sp)) {
  268. X    waddstr(sectw, "/H");
  269. X      }
  270. X      if (has_traded(sp)) {
  271. X    waddstr(sectw, "/T");
  272. X      }
  273. X      if (has_impenetrable(sp)) {
  274. X    waddstr(sectw, "/I");
  275. X      }
  276. X      if (has_hostile(sp)) {
  277. X    waddstr(sectw, "/h");
  278. X      }
  279. X    }
  280. X  }
  281. X  
  282. X  if (visibility & SEE_LAND_WATER) {
  283. X    mvwprintw(sectw, 3, 1, "%s ", terrains[sp->terrain - MIN_TERRAIN].name);
  284. X    wprintw(sectw, "%s", altitude_map[map_alt(sp->altitude)].name);
  285. X  }
  286. X
  287. X    wmove(sectw, 4, 1);    
  288. X    if (visibility & SEE_POPULATION) {
  289. X      wprintw(sectw, "%d people", sp->n_people);
  290. X      if (sp->owner != 0) {    /* print race of owner, if owner is not 0 */
  291. X    wprintw(sectw, " (%c)",    world.nations[sp->owner].race.mark);
  292. X      }
  293. X    }
  294. X  
  295. X  if (visibility & SEE_RESOURCES) {
  296. X    mvwprintw(sectw, 5, 1, "metal %d", sp->metal);
  297. X    mvwprintw(sectw, 5, 13, "jewels %d", sp->jewels);
  298. X  }
  299. X  
  300. X  if (visibility & SEE_RESOURCES) {
  301. X    mvwprintw(sectw, 6, 2, "soil %d", sp->soil);
  302. X  }
  303. X  if (visibility & SEE_LAND_WATER) {
  304. X    mvwprintw(sectw, 6, 11, "movecost %d",
  305. X          get_generic_move_cost(&world.nations[user.id],sp));
  306. X/*          get_move_cost(&world.nations[user.id],sp)); */
  307. X  }
  308. X
  309. X  box(sectw, '|', '-');
  310. X  } /* (for future optimization) */
  311. X  wrefresh(sectw);
  312. X}
  313. X
  314. Xbad_key()            /* user typed an undefined key */
  315. X{
  316. X  statline("type space to go on", "bad_key");
  317. X  while (getch() != ' ') {
  318. X  }
  319. X}
  320. X
  321. Xredraw()
  322. X{
  323. X/*  user.center = user.cursor; */
  324. X  clear();
  325. X  refresh();
  326. X  user.just_moved = 1;
  327. X}
  328. X
  329. Xwindows()            /* user gets to manage windows */
  330. X{
  331. X  WINDOW *winw;            /* for this screen only */
  332. X  Pt new_loc;            /* new location of the window */
  333. X
  334. X  statline("", "windows");
  335. X  winw = newwin(6, 26, 2, 2);
  336. X  wstandout(winw);
  337. X  mvwprintw(winw, 1, 4, "you can choose: ");
  338. X  wstandend(winw);
  339. X  mvwprintw(winw, 2, 0, "m - [m]ove sector window");
  340. X  mvwprintw(winw, 3, 0, "h - [h]ide sector window");
  341. X  mvwprintw(winw, 4, 0, "s - [s]how sector window");
  342. X  move(4,0);
  343. X  box(winw, '|', '-');
  344. X  wrefresh(winw);
  345. X  move(4,0);
  346. X  switch(getch()) {
  347. X  case 'm':
  348. X    new_loc.x = sectw->_begx;
  349. X    new_loc.y = sectw->_begy;
  350. X    mvprintw(LINES-2, 0, "starting at (%d,%d)", new_loc.x, new_loc.y);
  351. X    refresh();
  352. X      /* absolute dragging */
  353. X    new_loc = drag_cursor(new_loc, DRAG_ABS, NULL, NULL);
  354. X    mvwin(sectw, new_loc.y, new_loc.x);
  355. X    break;
  356. X  case 'h':
  357. X    user.show_sect_win = 0;
  358. X    werase(sectw);
  359. X    wrefresh(sectw);
  360. X    touchwin(stdscr);
  361. X    break;
  362. X  case 's':
  363. X    if (!user.show_sect_win) {
  364. X      show_sector(user.cursor.x, user.cursor.y);
  365. X    }
  366. X    user.show_sect_win = 1;
  367. X    break;
  368. X  default:
  369. X    break;
  370. X  }
  371. X  delwin(winw);            /* done with it */
  372. X  touch_all_wins();
  373. X/*  fflush(stdin); */
  374. X}
  375. X
  376. Xtouch_all_wins()    /* make sure all permanent windows get touched */
  377. X{
  378. X  touchwin(stdscr);
  379. X/*  if (user.show_sect_win) {
  380. X    touchwin(sectw);
  381. X  }
  382. X*/
  383. X  user.just_moved = 1;
  384. X}
  385. X
  386. X  /* this is used in general to track the user's movements */
  387. XPt drag_cursor(pt, flags, comment, legal)
  388. X     Pt pt;
  389. X     int flags;
  390. X     char (*comment)();
  391. X     int (*legal)();
  392. X{
  393. X  char c;
  394. X  char s[100], comment_str[100];
  395. X  Pt old_pt;
  396. X  int done = 0;
  397. X
  398. X  old_pt = pt;
  399. X
  400. X  statline("move the cursor; type space when done", "drag_cursor");
  401. X
  402. X  if ((flags == DRAG_REL) && (user.map_style == NORMAL_MAP)) {
  403. X    wrap(&pt);            /* regural map, relative drag */
  404. X    move(pt.y-yoff(), 2*(pt.x-xoff()));
  405. X  } else if (flags == DRAG_REL) { /* compact map, but still relative */
  406. X    wrap(&pt);
  407. X    move((*wrapy)(pt.x-xoff_compact(), pt.y-yoff()),
  408. X     (*wrapx)(pt.x-xoff_compact(),pt.y-yoff()));
  409. X  } else {            /* absolute positions */
  410. X    move(pt.y, pt.x);
  411. X  }
  412. X  refresh();
  413. X  while (((c = getch()) != ' ') && !done) {
  414. X    old_pt = pt;
  415. X    switch (c) {
  416. X    case '?':
  417. X      online_info();
  418. X      break;
  419. X    case 'h':
  420. X    case '4':
  421. X      --pt.x;
  422. X      break;
  423. X    case 'j':
  424. X    case '2':
  425. X      ++pt.y;
  426. X      break;
  427. X    case 'k':
  428. X    case '8':  
  429. X      --pt.y;
  430. X      break;
  431. X    case 'l':
  432. X    case '6':  
  433. X      ++pt.x;
  434. X      break;
  435. X    case 'y':
  436. X    case '7':
  437. X      --pt.x;
  438. X      --pt.y;
  439. X      break;
  440. X    case 'u':
  441. X    case '9':
  442. X      ++pt.x;
  443. X      --pt.y;
  444. X      break;
  445. X    case 'b':
  446. X    case '1':
  447. X      --pt.x;
  448. X      ++pt.y;
  449. X      break;
  450. X    case 'n':
  451. X    case '3':
  452. X      ++pt.x;
  453. X      ++pt.y;
  454. X      break;
  455. X    default:
  456. X      continue;
  457. X    }
  458. X    if (legal != NULL) {    /* if there *is* a legal() func... */
  459. X      wrap(&pt);
  460. X      if (!((*legal)(pt, user.np, user.current_army))) {
  461. X    beep();            /* illegal */
  462. X    pt = old_pt;
  463. X    statline2("hit space", "invalid point");
  464. X    get_space();
  465. X      }
  466. X    }
  467. X    if (flags == DRAG_REL) {    /* cludge, and ugly, since we wrap later */
  468. X      wrap(&pt);
  469. X      sprintf(s, "(%d,%d)", xrel(pt.x,pt.y,user.np->capital),
  470. X          yrel(pt.x,pt.y,user.np->capital));
  471. X    } else {
  472. X      sprintf(s, "(%d,%d)", pt.x, pt.y);
  473. X    }
  474. X    if (comment != NULL) {
  475. X      done = comment(comment_str);
  476. X      statline2(comment_str, s);
  477. X    } else {
  478. X      statline2("", s);
  479. X    }
  480. X    switch (flags) {
  481. X    case DRAG_REL:
  482. X      wrap(&pt);
  483. X      re_center(pt.x, pt.y);
  484. X      user.just_moved = 1;
  485. X      draw_map();
  486. X/*      show_sector(pt.x, pt.y); */
  487. X      if (user.map_style == NORMAL_MAP) {
  488. X    move((*wrapy)(pt.x-xoff(),pt.y-yoff()), 2*(*wrapx)(pt.x-xoff(),pt.y-yoff()));
  489. X      } else {
  490. X    move((*wrapy)(pt.x-xoff_compact(),pt.y-yoff()), (*wrapx)(pt.x-xoff_compact(),pt.y-yoff())); /* compact map */
  491. X      }
  492. X      break;
  493. X    case DRAG_ABS:
  494. X      move(pt.y, pt.x);
  495. X      break;
  496. X    default:
  497. X      break;
  498. X    }
  499. X    refresh();
  500. X  }
  501. X  if (flags == DRAG_REL) {
  502. X    sprintf(s, "the new point is (%d, %d)", xrel(pt.x,pt.y,user.np->capital),
  503. X        yrel(pt.x,pt.y,user.np->capital));
  504. X  } else {
  505. X    sprintf(s, "the new point is (%d, %d)", pt.x, pt.y);
  506. X  }
  507. X  statline2(s, "");
  508. X  move(LINES-2, 0);
  509. X  clrtoeol();
  510. X  refresh();
  511. X  return pt;
  512. X}
  513. X
  514. X  /* this routine sees if the screen needs re-centering, and
  515. X     re-centers it if necessary.  return 1 if re-centering was done.
  516. X     return 0 if there was no need to re-center.
  517. X   */
  518. Xre_center(x, y)
  519. X     int x, y;
  520. X{
  521. X  int change = 0;
  522. X  int width, height;
  523. X
  524. X  height = LINES-3;
  525. X  width = (COLS-2)-2;
  526. X
  527. X  if (user.map_style == NORMAL_MAP) {
  528. X    if ((*wrapx)(x - xoff(),0) >= width/2) { /* No Y coord to add! -KM */
  529. X      user.center.x = x;    /* too much to the right */
  530. X      change = 1;
  531. X    }
  532. X    if ((*wrapx)(x - xoff(),0) <= 0) { /* No Y coord to add! -KM */
  533. X      user.center.x = x;    /* too much to the left */
  534. X      change = 1;
  535. X    }
  536. X  } else {
  537. X    if ((*wrapx)(x - xoff_compact(),0) >= width) {
  538. X      user.center.x = x;    /* too much to the right */
  539. X      change = 1;
  540. X    }
  541. X    if ((*wrapx)(x - xoff_compact(),0) <= 0) {
  542. X      user.center.x = x;    /* too much to the left */
  543. X      change = 1;
  544. X    }
  545. X  }
  546. X  if ((*wrapy)(0,y - yoff()) >= height) {
  547. X    user.center.y = y;        /* too far down */
  548. X    change = 1;
  549. X  }
  550. X  if ((*wrapy)(0,y - yoff()) <= 0) {
  551. X    user.center.y = y;        /* too far up */
  552. X    change = 1;
  553. X  }
  554. X#ifdef hpux
  555. X  if (change) {
  556. X    redraw();
  557. X  }
  558. X#endif /* hpux */
  559. X  return change;
  560. X}
  561. X
  562. X  /* see if these coordinates would appear under the sector window */
  563. Xis_under_sectw(x, y)
  564. X     int x, y;
  565. X{
  566. X  int xfirst, yfirst, xlast, ylast;
  567. X
  568. X  if (!user.show_sect_win) {
  569. X    return 0;
  570. X  }
  571. X  xfirst = sectw->_begx;
  572. X  yfirst = sectw->_begy;
  573. X  xlast = xfirst + SECTW_SIZE_X;
  574. X  ylast = yfirst + SECTW_SIZE_Y;
  575. X  if (x < xfirst ||  x > xlast || y < yfirst || y > ylast) {
  576. X    return 0;
  577. X  }
  578. X  return 1;
  579. X}
  580. X
  581. X  /* this puts the cursor in the right place */
  582. Xset_cursor()
  583. X{
  584. X  int x = user.cursor.x, y = user.cursor.y;
  585. X
  586. X  if (user.map_style == NORMAL_MAP) {
  587. X    move((*wrapy)(x-xoff(),y-yoff()), 2*(*wrapx)(x-xoff(),y-yoff()));
  588. X  } else {
  589. X    move((*wrapy)(x-xoff_compact(),y-yoff()), (*wrapx)(x-xoff_compact(),y-yoff()));
  590. X  }
  591. X  refresh();
  592. X}
  593. X
  594. X  /* replacement for getch():  first checks if it is a question
  595. X     mark, and if it is it calls online_info().
  596. X   */
  597. Xmygetch()
  598. X{
  599. X  int c;
  600. X  if ((c = getch()) == '?') {
  601. X    online_info();
  602. X  }
  603. X  return c;
  604. X}
  605. X
  606. X  /* gets a string str of max length len; returns 0 on failure; 1 otherwise */
  607. Xwget_string (w, rets, len)
  608. X     WINDOW * w;
  609. X     char * rets;
  610. X     int len;
  611. X{
  612. X  char s [80];
  613. X  int pos, done;
  614. X  int x, y, i;
  615. X  int oldpos;        /* Used for ^W */
  616. X  noecho ();
  617. X
  618. X  if (w == NULL) {
  619. X    w = stdscr;
  620. X  }
  621. X
  622. X  pos = 0;
  623. X  done = 0;
  624. X
  625. X  getyx (w, y, x);
  626. X  wrefresh (w);
  627. X
  628. X  while (!done) {
  629. X    s [pos] = wgetch (stdscr);
  630. X    switch (s[pos]) {
  631. X    case '\n':
  632. X    case '\r':
  633. X      s [pos] = '\0';
  634. X      done = 1;
  635. X      break;
  636. X    case '\b':
  637. X    case DEL:
  638. X      if (pos > 0) {
  639. X    pos--;
  640. X    s[pos] = '\0';
  641. X    wmove (w, y, x + pos);
  642. X    waddch (w, ' ');
  643. X    wmove (w, y, x + pos);
  644. X      }
  645. X      break;
  646. X    case CTL('U'):
  647. X      wmove (w, y, x);
  648. X      for (i=0; i < pos; i++) {
  649. X    waddch (w, ' ');
  650. X      }
  651. X      wmove (w, y, x);
  652. X      pos = 0;
  653. X      s [pos] = '\0';
  654. X      break;
  655. X    case CTL('W'):
  656. X      oldpos = pos;
  657. X      while (pos != 0 && s[pos] == ' ') {
  658. X    pos --;
  659. X      }
  660. X      if (pos) {
  661. X    pos --;
  662. X      }
  663. X      while (pos != 0 && s[pos] != ' ') {
  664. X    pos --;
  665. X      }
  666. X      wmove (w, y, x + pos);
  667. X      while (oldpos != pos) {
  668. X    oldpos--;
  669. X    waddch (w, ' ');
  670. X      }      
  671. X      wmove (w, y, x + pos);
  672. X      break;
  673. X    default:
  674. X      waddch (w, s [pos]);
  675. X      pos++;
  676. X      break;
  677. X    }
  678. X    wrefresh (w);
  679. X  }
  680. X
  681. X  if (pos == 0) {
  682. X    return 0;
  683. X  }
  684. X  s [len-1] = '\0';
  685. X  strcpy (rets, s); 
  686. X  return 1;
  687. X}
  688. X
  689. X/* gets a number from window w; returns 1 if all OK; -1 otherwise */
  690. Xwget_number (w, num)
  691. X     WINDOW * w;
  692. X     int * num;
  693. X{
  694. X  char s [80];
  695. X  int pos, done;
  696. X  int x, y, i;
  697. X  noecho ();
  698. X
  699. X  if (w == NULL) {
  700. X    w = stdscr;
  701. X  }
  702. X
  703. X  pos = 0;
  704. X  done = 0;
  705. X
  706. X  getyx (w, y, x);
  707. X  wrefresh (w);
  708. X
  709. X  while (!done) {
  710. X    s [pos] = wgetch (stdscr);
  711. X    switch (s[pos]) {
  712. X    case '\n':
  713. X    case '\r':
  714. X      done = 1;
  715. X      break;
  716. X    case '\b':
  717. X    case DEL:
  718. X      if (pos > 0) {
  719. X    pos--;
  720. X    s[pos] = '\0';
  721. X    wmove (w, y, x + pos);
  722. X    waddch (w, ' ');
  723. X    wmove (w, y, x + pos);
  724. X      }
  725. X      break;
  726. X    case CTL('U'):
  727. X      wmove (w, y, x);
  728. X      for (i=0; i < pos; i++) {
  729. X    waddch (w, ' ');
  730. X      }
  731. X      wmove (w, y, x);
  732. X      pos = 0;
  733. X      s [pos] = '\0';
  734. X      break;
  735. X    default:
  736. X      waddch (w, s [pos]);
  737. X      pos++;
  738. X      break;
  739. X    }
  740. X    wrefresh (w);
  741. X  }
  742. X  if (pos == 0) {
  743. X    return -1;
  744. X  }
  745. X  if ((sscanf(s, "%d", num)) < 1) {
  746. X    return -1;
  747. X  }
  748. X  return 1;
  749. X}
  750. X
  751. Xwget_name (w, name)
  752. X     WINDOW * w;
  753. X     char * name;
  754. X{
  755. X  char s[80];
  756. X  int pos, done;
  757. X  int x, y, i;
  758. X  int oldpos;        /* Used for ^W */
  759. X  noecho();
  760. X
  761. X  if (w == NULL) {
  762. X    w = stdscr;
  763. X  }
  764. X
  765. X  pos = 0;
  766. X  done = 0;
  767. X
  768. X  getyx (w, y, x);
  769. X  wrefresh (w);
  770. X
  771. X  while (!done) {
  772. X    s [pos] = wgetch (stdscr);
  773. X    switch (s[pos]) {
  774. X    case '\n':
  775. X    case '\r':
  776. X      s [pos] = '\0';
  777. X      done = 1;
  778. X      break;
  779. X    case '\b':
  780. X    case DEL:
  781. X      if (pos > 0) {
  782. X    pos--;
  783. X    s[pos] = '\0';
  784. X    wmove (w, y, x + pos);
  785. X    waddch (w, ' ');
  786. X    wmove (w, y, x + pos);
  787. X      }
  788. X      break;
  789. X    case CTL('U'):
  790. X      wmove (w, y, x);
  791. X      for (i=0; i < pos; i++) {
  792. X    waddch (w, ' ');
  793. X      }
  794. X      wmove (w, y, x);
  795. X      pos = 0;
  796. X      s [pos] = '\0';
  797. X      break;
  798. X    case CTL('W'):
  799. X      oldpos = pos;
  800. X      while (pos != 0 && s[pos] == ' ') {
  801. X    pos --;
  802. X      }
  803. X      if (pos) {
  804. X    pos --;
  805. X      }
  806. X      while (pos != 0 && s[pos] != ' ') {
  807. X    pos --;
  808. X      }
  809. X      wmove (w, y, x + pos);
  810. X      while (oldpos != pos) {
  811. X    oldpos--;
  812. X    waddch (w, ' ');
  813. X      }      
  814. X      wmove (w, y, x + pos);
  815. X      break;
  816. X    default:
  817. X      waddch (w, s [pos]);
  818. X      pos++;
  819. X      break;
  820. X    }
  821. X    wrefresh (w);
  822. X  }
  823. X
  824. X  if (pos == 0) {
  825. X    return -1;
  826. X  }
  827. X  strcpy (name, s); 
  828. X  return 1;
  829. X}
  830. X
  831. X#ifdef PMAX  /* Fix for the mvwprintw bug in pmax curses */
  832. X#undef mvwprintw
  833. X#include <varargs.h>
  834. X
  835. Xmymvwprintw(va_alist)
  836. X     va_dcl
  837. X{
  838. X    va_list ap;
  839. X    reg WINDOW    *win;
  840. X    reg int        y, x;
  841. X    char        *fmt;
  842. X    char    buf[512];
  843. X
  844. X    va_start(ap);
  845. X    win = va_arg(ap, WINDOW *);
  846. X    y = va_arg(ap, int);
  847. X    x = va_arg(ap, int);
  848. X    fmt = va_arg(ap, char *);
  849. X    
  850. X    if (wmove(win,y, x) != OK)
  851. X      return ERR;
  852. X    (void) vsprintf(buf, fmt, ap);
  853. X    va_end(ap);
  854. X    return waddstr(win, buf);
  855. X}
  856. X#endif /* PMAX */
  857. END_OF_FILE
  858. if test 18715 -ne `wc -c <'cur_stuff.c'`; then
  859.     echo shar: \"'cur_stuff.c'\" unpacked with wrong size!
  860. fi
  861. # end of 'cur_stuff.c'
  862. fi
  863. if test -f 'mag_Monsters' -a "${1}" != "-c" ; then 
  864.   echo shar: Will not clobber existing file \"'mag_Monsters'\"
  865. else
  866. echo shar: Extracting \"'mag_Monsters'\" \(689 characters\)
  867. sed "s/^X//" >'mag_Monsters' <<'END_OF_FILE'
  868. X# this file describes magic powers available to magical
  869. X# order of Monstrosity.
  870. X#
  871. X# the format is:
  872. X# name level cost
  873. X# begin
  874. X#   series of exec lines
  875. X# end
  876. X#
  877. X# where `level' is the magical skill level at which you get the power,
  878. X# and `cost' is the cost in spell points to use the power.
  879. X#
  880. Xsummon_spider 50 1
  881. Xsummon_yeti 90 2
  882. Xsummon_ettin 170 3
  883. Xsummon_cyclops 200 3
  884. Xsummon_hydra 500 4
  885. Xsummon_crimson_death 800 8
  886. Xsummon_sea_dragon 1300 9
  887. Xsummon_green_dragon 1700 11
  888. Xsummon_red_dragon 2300 17
  889. Xsummon_gold_dragon 3000 24
  890. X#
  891. Xhide_army 200 1 2
  892. Xhide_sector 250 2 8
  893. Xmag_bonus 300 1 2
  894. Xfly_army 400 2 2
  895. Xwater_walk 500 2 2
  896. Xhaste_army 600 3 2
  897. Xcaltitude 800 8 6
  898. Xvampire_army 900 3 8
  899. Xfireburst 1000 4 4
  900. END_OF_FILE
  901. if test 689 -ne `wc -c <'mag_Monsters'`; then
  902.     echo shar: \"'mag_Monsters'\" unpacked with wrong size!
  903. fi
  904. # end of 'mag_Monsters'
  905. fi
  906. if test -f 'mag_Unity' -a "${1}" != "-c" ; then 
  907.   echo shar: Will not clobber existing file \"'mag_Unity'\"
  908. else
  909. echo shar: Extracting \"'mag_Unity'\" \(608 characters\)
  910. sed "s/^X//" >'mag_Unity' <<'END_OF_FILE'
  911. X# this file describes magic powers available to magical order of Unity,
  912. X# which is concerned mostly with mixed animals.
  913. X#
  914. X# the format is:
  915. X# name level cost
  916. X# begin
  917. X#   series of exec lines
  918. X# end
  919. X#
  920. X# where `level' is the magical skill level at which you get the power,
  921. X# and `cost' is the cost in spell points to use the power.
  922. X#
  923. Xsummon_naga 50 1
  924. Xsummon_centaur 90 3
  925. Xsummon_werewolf 140 4
  926. Xsummon_minotaur 150 3
  927. Xsummon_owl_bear 400 4
  928. Xsummon_gryphon 500 7
  929. Xsummon_sea_lion 700 7
  930. Xsummon_chimera 1100 10
  931. Xsummon_sphynx 2200 17
  932. X#
  933. Xhide_army 400 1 2
  934. Xmerge 0 0 0
  935. Xhide_sector 500 2 8
  936. Xmag_bonus 600 1 2
  937. Xfly_army 800 2 2
  938. END_OF_FILE
  939. if test 608 -ne `wc -c <'mag_Unity'`; then
  940.     echo shar: \"'mag_Unity'\" unpacked with wrong size!
  941. fi
  942. # end of 'mag_Unity'
  943. fi
  944. if test -f 'menus.c' -a "${1}" != "-c" ; then 
  945.   echo shar: Will not clobber existing file \"'menus.c'\"
  946. else
  947. echo shar: Extracting \"'menus.c'\" \(19167 characters\)
  948. sed "s/^X//" >'menus.c' <<'END_OF_FILE'
  949. X  /* menus.c -- various menus for dominion */
  950. X
  951. X/*
  952. X * Copyright (C) 1990 Free Software Foundation, Inc.
  953. X * Written by the dominion project.
  954. X *
  955. X * This file is part of dominion.
  956. X *
  957. X * dominion is free software; you can redistribute it and/or
  958. X * modify it under the terms of the GNU General Public License as published
  959. X * by the Free Software Foundation; either version 1, or (at your option)
  960. X * any later version.
  961. X *
  962. X * This software is distributed in the hope that it will be useful,
  963. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  964. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  965. X * GNU General Public License for more details.
  966. X *
  967. X * You should have received a copy of the GNU General Public License
  968. X * along with this software; see the file COPYING.  If not, write to
  969. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  970. X */
  971. X
  972. X#include <stdio.h>
  973. X#include <ctype.h>
  974. X#ifdef SYSV
  975. X# include <string.h>
  976. X#else
  977. X# include <strings.h>
  978. X#endif /* SYSV */
  979. X
  980. X#include "dominion.h"
  981. X#include "misc.h"
  982. X#include "army.h"
  983. X
  984. Xextern Sworld world;
  985. Xextern Suser user;
  986. X  /* info about all spirits */
  987. Xextern struct spirit_type *spirit_types;
  988. Xextern char help_tag[];
  989. X
  990. X  /* asks the user what the display should look like */
  991. Xdisplay_menu()
  992. X{
  993. X  WINDOW *dispw;
  994. X  char c;
  995. X
  996. X  strcpy(help_tag, "Display options");
  997. X  if (user.xmode) {
  998. X    statline("[r,c,n,d,p,A,w,M,t,T,s,m,j,h,o,a,y,O,l,u,-,C,W]", "display_menu");
  999. X  } else {
  1000. X    statline("choose an option (space to exit)", "display menu");
  1001. X    dispw = newwin(9, COLS-4, LINES-11, 2);
  1002. X    wmove(dispw, 1, 1);
  1003. X    waddstr(dispw, "Map Style:         [r]egular, [c]ompact");
  1004. X    wmove(dispw, 2, 1);
  1005. X    waddstr(dispw, "Display Options:   ");
  1006. X    waddstr(dispw, "[n]ation mark, [d]esignation, [p]opulation,");
  1007. X    wmove(dispw, 3, 1);
  1008. X    waddstr(dispw, "                   ");
  1009. X    waddstr(dispw, "[A]ltitude, [w] Climate, army [M]ovecost, [t]errain,");
  1010. X    wmove(dispw, 4, 1);
  1011. X    waddstr(dispw, "                   ");
  1012. X    waddstr(dispw, "[s]oil, [m]etal, [j]ewels, [T]errain move cost");
  1013. X    wmove(dispw, 5, 1);
  1014. X    waddstr(dispw, "Highlight Options: ");
  1015. X    waddstr(dispw, "[o]wnership, [a]rmies, [y]our armies, [O]ther armies,");
  1016. X    wmove(dispw, 6, 1);
  1017. X    waddstr(dispw, "                   ");
  1018. X    waddstr(dispw, "[l] move left, [h]ostile, [u]nemployment, [-]none");
  1019. X    wmove(dispw, 7, 1);
  1020. X    waddstr(dispw, "Other Things:      ");
  1021. X    waddstr(dispw, "[C]enter screen at cursor, [W]ater/underwater toggle");
  1022. X    box(dispw, '|', '-');
  1023. X    wrefresh(dispw);
  1024. X  }
  1025. X  switch (c = mygetch()) {
  1026. X  case ' ':
  1027. X    break;
  1028. X  case 'h':
  1029. X    user.highlight = H_HOSTILE;
  1030. X    break;
  1031. X  case 'M':
  1032. X    user.display = ARMY_MOVECOST;
  1033. X    break;
  1034. X  case 'r':
  1035. X    user.map_style = NORMAL_MAP; /* map style */
  1036. X    wclear(stdscr);
  1037. X    break;
  1038. X  case 'c':
  1039. X    user.map_style = COMPACT_MAP;
  1040. X    wclear(stdscr);
  1041. X    break;
  1042. X  case 'd':
  1043. X    user.display = DESIGNATION; /* display */
  1044. X    break;
  1045. X  case 'n':
  1046. X    user.display = NATION_MARK;
  1047. X    break;
  1048. X  case 's':
  1049. X    user.display = SOIL;
  1050. X    break;
  1051. X  case 'm':
  1052. X    user.display = METAL;
  1053. X    break;
  1054. X  case 'j':
  1055. X    user.display = JEWELS;
  1056. X    break;
  1057. X  case 'A':
  1058. X    user.display = ALTITUDE;
  1059. X    break;
  1060. X  case 'w':
  1061. X    user.display = CLIMATE;
  1062. X    break;
  1063. X  case 'p':
  1064. X    user.display = POPULATION;
  1065. X    break;
  1066. X  case 'T':
  1067. X    user.display = MOVECOST;
  1068. X    break;
  1069. X  case 't':
  1070. X    user.display = TERRAIN;
  1071. X    break;
  1072. X  case 'o':
  1073. X    user.highlight = H_OWNED;    /* highlighting */
  1074. X    break;
  1075. X  case 'a':
  1076. X    user.highlight = H_ARMIES;
  1077. X    break;
  1078. X  case 'y':
  1079. X    user.highlight = H_YOUR_ARMIES;
  1080. X    break;
  1081. X  case 'O':
  1082. X    user.highlight = H_OTHER_ARMIES;
  1083. X    break;
  1084. X  case 'l':
  1085. X    user.highlight = H_MOVE_LEFT;
  1086. X    break;
  1087. X  case 'u':
  1088. X    user.highlight = H_UNEMP;
  1089. X    break;
  1090. X  case '-':            /* no highlighting */
  1091. X    user.highlight = H_NONE;
  1092. X    break;
  1093. X  case 'C':            /* center screen around current cursor */
  1094. X    user.center = user.cursor;
  1095. X#ifdef hpux            /* HP curses is baaad */
  1096. X    redraw();
  1097. X#endif /* hpux */
  1098. X    break;
  1099. X  case 'W':            /* above/below water toggle */
  1100. X    user.underwater = !user.underwater;
  1101. X    break;
  1102. X  default:
  1103. X    bad_key();
  1104. X    break;
  1105. X  }
  1106. X  if (!user.xmode) {
  1107. X    delwin(dispw);
  1108. X  }
  1109. X  touchwin(stdscr);
  1110. X  user.just_moved = 1;
  1111. X}
  1112. X
  1113. X  /* wizardry commands */
  1114. Xwizardry_menu()
  1115. X{
  1116. X  WINDOW *wizw;
  1117. X  char c;
  1118. X  int done = 0;
  1119. X  char s[PATHLEN];
  1120. X  Snation *np = user.np;
  1121. X  Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  1122. X
  1123. X  if (user.xmode) {
  1124. X    wizw = (WINDOW *) NULL;
  1125. X  } else {
  1126. X    wizw = newwin(6, COLS-4, LINES-8, 2);
  1127. X  }
  1128. X    /* now see if we can automatically select the first mage
  1129. X       on this sector.
  1130. X     */
  1131. X  if (first_sect_mage_id(user.np, sp) != -1) {
  1132. X    user.current_army = first_sect_mage_id(user.np, sp);
  1133. X    show_armies(sp);
  1134. X  }
  1135. X  while (!done) {
  1136. X    strcpy(help_tag, "Wizardry");
  1137. X    if (user.xmode) {
  1138. X      sprintf(s, "%d spell pts. [l,c,s,h,i]", np->spell_pts);
  1139. X      statline(s, "wizardry_menu");
  1140. X    } else {
  1141. X      statline("Choose a wizardry command (space to leave)","wizardry_menu");
  1142. X      mvwaddstr(wizw, 1, 1,
  1143. X    "  [l]ist spells and spirits, [c]ast a spell, [s]ummon a spirit");
  1144. X      mvwaddstr(wizw, 2, 1, "  list [h]anging spells, [i]nitiate a mage");
  1145. X      mvwprintw(wizw, 3, 1, "    You have %d spell points", np->spell_pts);
  1146. X      box(wizw, '|', '-');
  1147. X      wrefresh(wizw);
  1148. X    }
  1149. X    switch (c = getch()) {
  1150. X    case ' ':
  1151. X      done = 1;
  1152. X      break;
  1153. X    case 'l':
  1154. X      if (!user.xmode) {
  1155. X    wmove(wizw, 2, 1);
  1156. X    wprintw(wizw,
  1157. X        "  listing spells and spirits for nation %s (order of %s)",
  1158. X        user.np->name, user.np->mag_order);
  1159. X      }
  1160. X      list_spells(&user);
  1161. X      list_spirits(&user);
  1162. X      statline2_err("Type space to get back", "spells and spirits list");
  1163. X      touchwin(stdscr);
  1164. X      refresh();
  1165. X      fflush(stdin);
  1166. X      user.just_moved = 1;
  1167. X      break;
  1168. X    case 's':
  1169. X      if (!user.xmode) {
  1170. X    list_spirits(&user);
  1171. X      }
  1172. X      summon(&user, wizw);
  1173. X      break;
  1174. X    case 'c':
  1175. X      if (!user.xmode) {
  1176. X    list_spells(&user);
  1177. X      }
  1178. X      cast_spell(&user, wizw);
  1179. X      break;
  1180. X    case 'i':
  1181. X      initiate_mage(&user, wizw);
  1182. X      break;
  1183. X    case 'h':
  1184. X      show_hanging_spells(&user);
  1185. X      break;
  1186. X    case '?':
  1187. X      online_info();
  1188. X      break;
  1189. X    default:
  1190. X      break;
  1191. X    }
  1192. X    statline2("", "");
  1193. X    if (!user.xmode) {
  1194. X      wmove(wizw, 2, 1);
  1195. X      wclrtobot(wizw);
  1196. X    }
  1197. X  }
  1198. X  if (!user.xmode) {
  1199. X    touchwin(stdscr);
  1200. X    delwin(wizw);
  1201. X    user.just_moved = 1;
  1202. X  }
  1203. X}
  1204. X
  1205. X  /* conjures a spirit */
  1206. Xsummon(up, w)
  1207. X     Suser *up;
  1208. X     WINDOW *w;
  1209. X{
  1210. X  char type[NAMELEN], name[NAMELEN];
  1211. X  int type_index;
  1212. X  Sspirit *spiritp = user.spirit_list;
  1213. X  Sarmy *ap, *get_army();
  1214. X  Ssector *sp = &world.map[up->cursor.x][up->cursor.y];
  1215. X
  1216. X  strcpy(help_tag, "Spirit types");
  1217. X
  1218. X  if ((ap = get_army(up->np, up->current_army)) == NULL  ||  !is_mage(ap) ) {
  1219. X    statline2_err("only mages can summon. hit space.", "summon");
  1220. X    return;
  1221. X  }
  1222. X  if (sp->owner != up->np->id) {
  1223. X    statline2_err("must summon in your own land", "summon");
  1224. X    return;
  1225. X  }
  1226. X  if (w) {
  1227. X    mvwprintw(w, 2, 1, "Which type of spirit do you wish to summon? ");
  1228. X  } else {
  1229. X    statline_prompt("Which type? ", "summon");
  1230. X  }
  1231. X  wget_name(w, type);
  1232. X  if ((type_index = spirit_type_index(type)) < 0) {
  1233. X    statline2_err("couldn't find a spirit of that type. hit space.", "summon");
  1234. X    return;
  1235. X  }
  1236. X    /* get the spirit pointer from the list of available spirits */
  1237. X  while (spiritp && (strcmp(type, spiritp->type) != 0)) {
  1238. X    spiritp = spiritp->next;
  1239. X  }
  1240. X  if (spiritp == NULL) {
  1241. X    statline2_err("That is not available to you. hit space.", "summon");
  1242. X    return;
  1243. X  }
  1244. X    /* now see if they can afford it */
  1245. X  if (spiritp->cost > up->np->spell_pts) {
  1246. X    statline2_err("you do not have enough spell points. hit space.", "summon");
  1247. X    return;
  1248. X  }
  1249. X  if (w) {
  1250. X    mvwprintw(w, 3, 1, "Give a name to your spirit (default %s: ", type);
  1251. X  } else {
  1252. X    statline("Give name: ", "summon");
  1253. X    move(LINES-1, strlen("Give name: "));
  1254. X  }
  1255. X  if (wget_name(w, name) <= 0) {
  1256. X    sprintf(name, "%s", type);
  1257. X  }
  1258. X  exec_summon(type_index, name);
  1259. X  statline2_err("spirit has been summoned, hit space to get back", "summon");
  1260. X}
  1261. X
  1262. X  /* initiates a mage */
  1263. Xinitiate_mage(up, w)
  1264. X     Suser *up;
  1265. X     WINDOW *w;
  1266. X{
  1267. X  char c;
  1268. X  char name[NAMELEN], s[NAMELEN];
  1269. X  Ssector *sp;
  1270. X  char def_name [NAMELEN];
  1271. X
  1272. X  strcpy(help_tag, "Mages");
  1273. X  sp = &world.map[user.cursor.x][user.cursor.y];
  1274. X  if ((sp->designation != D_CITY && sp->designation != D_UNIVERSITY
  1275. X      && sp->designation != D_TEMPLE && sp->designation != D_CAPITAL)
  1276. X      || (sp->owner != user.id)) {
  1277. X    statline2_err("must initiate in *your* city/univ/temple. hit space.",
  1278. X          "initiate_mage");
  1279. X    return;
  1280. X  }
  1281. X  name[0] = '\0';
  1282. X  if (w) {
  1283. X    mvwprintw(w, 3, 1,
  1284. X          "initiation costs %d jewels.  go ahead (y/n)? ",
  1285. X          INITIATION_JEWELS);
  1286. X    wrefresh(w);
  1287. X  } else {
  1288. X    sprintf(s, "costs %d jewels.  go ahead (y/n)? ", INITIATION_JEWELS);
  1289. X    statline(s, "initiate");
  1290. X    move(LINES-1, strlen(s));
  1291. X  }
  1292. X  c = getchar();
  1293. X  if (c == '?') {
  1294. X    online_info();
  1295. X  }
  1296. X  if (c != 'y' && c != 'y') {
  1297. X    return;
  1298. X  }
  1299. X  if (up->np->jewels < INITIATION_JEWELS) {
  1300. X    statline2_err("You do not have enough jewels. hit space.","initiate_mage");
  1301. X    return;
  1302. X  }
  1303. X  if (next_thon_jewels (up->np) - MAGE_JEWELS_MAINT < 0) {
  1304. X    statline2_err ("You would have negative jewels next thon.  hit space.",
  1305. X           "initiate_mage");
  1306. X    return;
  1307. X  }
  1308. X
  1309. X  sprintf (def_name, "Mage");
  1310. X  sprintf (s, "Name (default \"%s\"): ", def_name);
  1311. X
  1312. X  if (w) {
  1313. X    mvwprintw(w, 4, 1,"Give a name to your new mage (default \"%s\"): ",
  1314. X          def_name);
  1315. X  } else {
  1316. X    statline(s, "initiate");
  1317. X    move(LINES-1,strlen (s));
  1318. X  }
  1319. X  if ((wget_name(w, name)) == NULL) {
  1320. X    strcpy (name, def_name);
  1321. X  }
  1322. X    /* if we got this far, it means that the initiation is valid */
  1323. X  exec_initiate(name);
  1324. X  statline2_err("mage has been initiated, hit space to get back",
  1325. X        "initiate_mage");
  1326. X}
  1327. X
  1328. X  /* list a user's spells */
  1329. Xlist_spells(up)
  1330. X     Suser *up;
  1331. X{
  1332. X  Sspell *spells = up->spell_list;
  1333. X  WINDOW *listw;
  1334. X  int i, n_spells = 0;
  1335. X
  1336. X  while (spells != NULL) {
  1337. X    spells = spells->next;
  1338. X    ++n_spells;
  1339. X  }
  1340. X  listw = newwin(n_spells+3, NAMELEN, 2, 37);
  1341. X  box(listw, '|', '-');
  1342. X  wstandout(listw);
  1343. X  mvwaddstr(listw, 0, 2, "Spell");
  1344. X  wstandend(listw);
  1345. X  waddstr(listw, "(cost,time)");
  1346. X  spells = up->spell_list;
  1347. X  for (i = 0; i < n_spells; ++i) {
  1348. X    mvwprintw(listw, i+2, 1, "%s(%d,%d)",
  1349. X          spells->name, spells->cost, spells->duration);
  1350. X    spells = spells->next;
  1351. X  }
  1352. X  wrefresh(listw);
  1353. X  delwin(listw);
  1354. X}
  1355. X
  1356. X  /* list a user's spirits */
  1357. Xlist_spirits(up)
  1358. X     Suser *up;
  1359. X{
  1360. X  Sspirit *spirits = up->spirit_list;
  1361. X  int n_spirits = 0, i;
  1362. X  WINDOW *listw;
  1363. X
  1364. X  while (spirits != NULL) {
  1365. X    spirits = spirits->next;
  1366. X    ++n_spirits;
  1367. X  }
  1368. X  listw = newwin(n_spirits+3, NAMELEN, 2, 7);
  1369. X  box(listw, '|', '-');
  1370. X  wstandout(listw);
  1371. X  mvwaddstr(listw, 0, 4, "Spirit");
  1372. X  wstandend(listw);
  1373. X  waddstr(listw, "(cost)");
  1374. X  spirits = up->spirit_list;
  1375. X    /* run through the list and print them out */
  1376. X  for (i = 0; i < n_spirits; ++i) {
  1377. X    if (spirit_type_index(spirits->type) >= 0) {
  1378. X      mvwprintw(listw, i+2, 1, "%s(%d)", spirits->type, spirits->cost);
  1379. X    }
  1380. X    spirits = spirits->next;
  1381. X  }
  1382. X  wrefresh(listw);
  1383. X  delwin(listw);
  1384. X}
  1385. X
  1386. Xcast_spell(up, w)
  1387. X     Suser *up;
  1388. X     WINDOW *w;
  1389. X{
  1390. X  Sspell *slist = up->spell_list;
  1391. X  char name[NAMELEN], s[NAMELEN];
  1392. X  Sarmy *ap, *get_army();
  1393. X  int cost;
  1394. X
  1395. X  if ((ap = get_army(up->np, up->current_army)) == NULL  ||  !is_mage(ap) ) {
  1396. X    statline2_err("only mages can cast spells. hit space.", "cast_spell");
  1397. X    return;
  1398. X  }
  1399. X  if (w) {
  1400. X    mvwprintw(w, 4, 1, "which spell do you want to cast? ");
  1401. X  } else {
  1402. X    statline_prompt("Which spell? ", "cast_spell");
  1403. X  }
  1404. X  wget_name(w, name);
  1405. X  while (slist != NULL) {
  1406. X    if (strcmp(slist->name, name) == 0) {
  1407. X      break;            /* found it */
  1408. X    }
  1409. X    slist = slist->next;
  1410. X  }
  1411. X  if (slist == NULL) {
  1412. X    statline2_err("no spell by that name. hit space.", "cast_spell");
  1413. X    return;
  1414. X  }
  1415. X  if (slist->cost > 0 && slist->cost > up->np->spell_pts) {
  1416. X    statline2_err("you do not have enough spell points. hit space.",
  1417. X          "cast_spell");
  1418. X    return;
  1419. X  }
  1420. X    /* if we got this far, it means that the spell is valid */
  1421. X  cost = exec_spell(slist, w);
  1422. X  show_armies(&world.map[up->cursor.x][up->cursor.y]);
  1423. X  if (cost > 0) {
  1424. X    statline2_err("spell has been cast, hit space to get back", "cast_spell");
  1425. X  }
  1426. X}
  1427. X
  1428. X  /* this sets up the spirit as a new army */
  1429. Xexec_summon(type_index, name)
  1430. X     int type_index;
  1431. X     char name[];
  1432. X{
  1433. X  Sarmy army, make_army();
  1434. X  Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  1435. X  char s[EXECLEN];
  1436. X
  1437. X  army = make_army(spirit_types[type_index].type, name,
  1438. X           spirit_types[type_index].size, A_DEFEND,
  1439. X           user.np->id, sp->loc);
  1440. X  army.id = free_army_id(user.np);
  1441. X   /* spirits cost spell points to draft *and* maintain (set in make_army) */
  1442. X  army.next = NULL;
  1443. X  army.flags = spirit_types[type_index].flags;
  1444. X    /* now insert it into the list */
  1445. X  ++user.np->n_armies;
  1446. X  if (user.np->armies == NULL) { /* special case:  empty list */
  1447. X    user.np->armies = (Sarmy *) malloc(sizeof(Sarmy));
  1448. X    *(user.np->armies) = army;
  1449. X    user.np->armies->next = NULL;
  1450. X  } else {
  1451. X    insert_army_nation(user.np, &army, -1);
  1452. X  }
  1453. X  insert_army_sector(sp, &army);
  1454. X  user.np->spell_pts -= spirit_types[type_index].spell_pts_draft;
  1455. X  cspell_pts(user.np, -spirit_types[type_index].spell_pts_draft);
  1456. X    /* now prepare the exec string for making the army and costs */
  1457. X  sprintf(s, "AMAKE:%d:%d:%d:%d:%s:%s\n", army.id, army.n_soldiers,
  1458. X      army.pos.x, army.pos.y, army.type, army.name);
  1459. X  gen_exec(s);
  1460. X    /* now a last detail:  the "current_army" variable
  1461. X       must be set (like in draft_army())
  1462. X     */
  1463. X  if (user.current_army == -1) {
  1464. X    user.current_army = first_sect_army(sp);
  1465. X  }
  1466. X  show_armies(sp);
  1467. X}
  1468. X
  1469. X  /* this sets up the mage as a new army */
  1470. Xexec_initiate(name)
  1471. X     char name[];
  1472. X{
  1473. X  Sarmy army, make_army();
  1474. X  Ssector *sp = &world.map[user.cursor.x][user.cursor.y];
  1475. X  char s[EXECLEN];
  1476. X
  1477. X  army = make_army("Mage", name, 1, A_DEFEND,
  1478. X           user.np->id, sp->loc);
  1479. X    /* now give the mage maintainance costs */
  1480. X  army.jewel_maint = 1000;
  1481. X/*  army.spell_pts_maint = 1; */
  1482. X  army.id = free_army_id(user.np);
  1483. X  army.flags |= AF_WIZARD;
  1484. X  army.next = NULL;
  1485. X    /* now insert it into the list */
  1486. X  ++user.np->n_armies;
  1487. X  if (user.np->armies == NULL) { /* special case:  empty list */
  1488. X    user.np->armies = (Sarmy *) malloc(sizeof(Sarmy));
  1489. X    *(user.np->armies) = army;
  1490. X    user.np->armies->next = NULL;
  1491. X  } else {
  1492. X    insert_army_nation(user.np, &army, -1);
  1493. X  }
  1494. X  insert_army_sector(sp, &army);
  1495. X  user.np->jewels -= INITIATION_JEWELS;
  1496. X  cjewels(user.np, -INITIATION_JEWELS);
  1497. X    /* now prepare the exec string for making the army and costs */
  1498. X  sprintf(s, "AMAKE:%d:%d:%d:%d:%s:%s\n", army.id, army.n_soldiers,
  1499. X      army.pos.x, army.pos.y, army.type, army.name);
  1500. X  gen_exec(s);
  1501. X  aflag_set(&army, AF_WIZARD);
  1502. X/*  sprintf(s, "%d:%d", army.id, AF_WIZARD); */
  1503. X/*  aflag_set(&army, AF_NOFIGHT); */
  1504. X    /* now a last detail:  the "current_army" var must be set
  1505. X       (like in draft_army())
  1506. X     */
  1507. X  if (user.current_army == -1) {
  1508. X    user.current_army = first_sect_army(sp);
  1509. X  }
  1510. X  show_armies(sp);
  1511. X}
  1512. X
  1513. X  /* make a window to show user her/his hanging spells */
  1514. Xshow_hanging_spells(up)
  1515. X     Suser *up;
  1516. X{
  1517. X  WINDOW *sw;
  1518. X  int done = 0, i;
  1519. X  Sh_spell *h_list;        /* list of hanging spells for this user */
  1520. X
  1521. X  strcpy(help_tag, "Spells");
  1522. X  statline("Hit space to get back", "show_hanging_spells");
  1523. X  sw = newwin(20, 30, 2, 2);
  1524. X  while (!done) {
  1525. X    mvwprintw(sw, 1, 1, "     Spell       thons");
  1526. X    wclrtobot(sw);
  1527. X    if (up->id == 0) { waddstr(sw, " (nat)"); }
  1528. X    mvwprintw(sw, 2, 1, "   --------       --- ");
  1529. X    if (up->id == 0) { waddstr(sw, "  --- "); }
  1530. X    for (i = 0, h_list = up->h_spells; h_list != NULL;
  1531. X     ++i,h_list = h_list->next) {
  1532. X      mvwprintw(sw, 3+i, 1, " %2d %-12.12s  %2d", i, h_list->name,
  1533. X        h_list->thons_left);
  1534. X      if (up->id == 0) { wprintw(sw, "    %3d", h_list->nat_id); }
  1535. X      wclrtoeol(sw);
  1536. X    }
  1537. X    mvwaddstr(sw, 18, 1, " [z]oom, [d]elete ");
  1538. X    wclrtoeol(sw);
  1539. X    box(sw, '|', '-');
  1540. X    wrefresh(sw);
  1541. X    switch(getch()) {
  1542. X    case 'z':
  1543. X      zoom_on_h_spell(up->h_spells, sw);
  1544. X      break;
  1545. X    case 'd':
  1546. X      zoom_del_h_spell(up->h_spells, sw);
  1547. X      break;
  1548. X
  1549. X    case ' ':
  1550. X      done = 1;
  1551. X      break;
  1552. X    case '?':
  1553. X      online_info();
  1554. X      break;
  1555. X    default:
  1556. X      break;
  1557. X    }
  1558. X  }
  1559. X  delwin(sw);
  1560. X  touch_all_wins();
  1561. X}
  1562. X
  1563. X  /* allows the user to focus on a specific spell */
  1564. Xzoom_on_h_spell(h_list, sw)
  1565. X     Sh_spell *h_list;
  1566. X     WINDOW *sw;
  1567. X{
  1568. X  WINDOW *zoomw;
  1569. X  int n, i;
  1570. X  char s[EXECLEN];
  1571. X
  1572. X    /* first ask the user which spell s/he wants to see */
  1573. X  mvwaddstr(sw, 18, 1, " On which spell? ");
  1574. X  wclrtoeol(sw);
  1575. X  box(sw, '|', '-');
  1576. X  wrefresh(sw);
  1577. X  if (wget_number(sw, &n) < 0 || n < 0) {
  1578. X    return -1;
  1579. X  }
  1580. X  for (i = 0; h_list && i < n; ++i) {
  1581. X    h_list = h_list->next;
  1582. X  }
  1583. X  if (h_list == NULL) {
  1584. X    return -1;
  1585. X  }
  1586. X    /* then zoom in on it */
  1587. X  zoomw = newwin(h_list->n_lines/2+3, 30, 4, 25);
  1588. X  mvwprintw(zoomw, 1, 3, " Spell <%s>  ", h_list->name);
  1589. X  for (i = 0; i < h_list->n_lines; i += 2) {
  1590. X      /* now insert the hiding of coordinates */
  1591. X    strcpy(s, h_list->lines[i]);
  1592. X    fix_sector_line(h_list->lines[i], s);
  1593. X    mvwprintw(zoomw, i/2+2, 1, " %s", s);
  1594. X  }
  1595. X  box(zoomw, '|', '-');
  1596. X  wrefresh(zoomw);
  1597. X  statline2_err("Hit space to return", "zoom_on_h_spell");
  1598. X  delwin(zoomw);
  1599. X  return 1;
  1600. X}
  1601. X
  1602. X  /* fix the exec line if it has references to a sector by
  1603. X     absolute coordinates.  put the "censored" line into s.
  1604. X     this is quite a hack, what?
  1605. X   */
  1606. Xfix_sector_line(line, s)
  1607. X     char line[], s[];
  1608. X{
  1609. X  int xabs, yabs, x_rel, y_rel, arg;
  1610. X  char *s2, s3[EXECLEN];    /* for temporary work */
  1611. X
  1612. X    /* if there is no '_', then just return */
  1613. X  if ((s2 = strrchr(line, '_')) == NULL) {
  1614. X    strcpy(s, line);
  1615. X    return;
  1616. X  }
  1617. X    /* the convention is, if the exec line ends with "_SECTOR"
  1618. X       then the first 2 numbers are the x and y coordinates.
  1619. X     */
  1620. X  if (strncmp(s2+1, "SECTOR", strlen("SECTOR")) != 0) {
  1621. X    strcpy(s, line);
  1622. X    return;
  1623. X  }
  1624. X    /* for now make the gross assumption that
  1625. X       the only arguments are x, y and a third "arg"
  1626. X     */
  1627. X  s2 = line;
  1628. X  s2 = strchr(s2, ':')+1;
  1629. X  sscanf(s2, "%d", &xabs);
  1630. X  s2 = strchr(s2, ':')+1;
  1631. X  sscanf(s2, "%d", &yabs);
  1632. X  s2 = strchr(s2, ':')+1;
  1633. X  sscanf(s2, "%d", &arg);
  1634. X  if (user.id == 0) {
  1635. X    x_rel = xabs;
  1636. X    y_rel = yabs;
  1637. X  } else {
  1638. X    x_rel = xrel(xabs, yabs, user.np->capital);
  1639. X    y_rel = yrel(xabs, yabs, user.np->capital);
  1640. X  }
  1641. X  /*    sprintf(s3, "%d:%d:%d\n", xabs, yabs, arg); (debug) */
  1642. X  sprintf(s3, ":%d:%d:%d\n", x_rel, y_rel, arg);
  1643. X  strcpy(strchr(s, ':'), s3);
  1644. X  /*    statline(s, "final s, hit space"); */
  1645. X}
  1646. X
  1647. Xzoom_del_h_spell(h_list, sw)
  1648. X     Sh_spell *h_list;
  1649. X     WINDOW *sw;
  1650. X{
  1651. X  WINDOW *zoomw;
  1652. X  int n, i;
  1653. X  char s[EXECLEN];
  1654. X
  1655. X    /* first ask the user which spell s/he wants to see */
  1656. X  mvwaddstr(sw, 18, 1, " Remove which spell? ");
  1657. X  wclrtoeol(sw);
  1658. X  box(sw, '|', '-');
  1659. X  wrefresh(sw);
  1660. X  if (wget_number(sw, &n) < 0 || n < 0) {
  1661. X    return -1;
  1662. X  }
  1663. X  for (i = 0; h_list && i < n; ++i) {
  1664. X    h_list = h_list->next;
  1665. X  }
  1666. X  if (h_list == NULL) {
  1667. X    return -1;
  1668. X  }
  1669. X
  1670. X  delete_hanging_spell(h_list);
  1671. X  return 1;
  1672. X}
  1673. X
  1674. END_OF_FILE
  1675. if test 19167 -ne `wc -c <'menus.c'`; then
  1676.     echo shar: \"'menus.c'\" unpacked with wrong size!
  1677. fi
  1678. # end of 'menus.c'
  1679. fi
  1680. if test -f 'npclib.c' -a "${1}" != "-c" ; then 
  1681.   echo shar: Will not clobber existing file \"'npclib.c'\"
  1682. else
  1683. echo shar: Extracting \"'npclib.c'\" \(17716 characters\)
  1684. sed "s/^X//" >'npclib.c' <<'END_OF_FILE'
  1685. X   /* nplib.c -- modules involved in NPC movemaking */
  1686. X
  1687. X/*
  1688. X * Copyright (C) 1990 Free Software Foundation, Inc.
  1689. X * Written by the dominion project.
  1690. X *
  1691. X * This file is part of dominion.
  1692. X *
  1693. X * dominion is free software; you can redistribute it and/or
  1694. X * modify it under the terms of the GNU General Public License as published
  1695. X * by the Free Software Foundation; either version 1, or (at your option)
  1696. X * any later version.
  1697. X *
  1698. X * This software is distributed in the hope that it will be useful,
  1699. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  1700. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1701. X * GNU General Public License for more details.
  1702. X *
  1703. X * You should have received a copy of the GNU General Public License
  1704. X * along with this software; see the file COPYING.  If not, write to
  1705. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1706. X */
  1707. X#ifdef SYSV
  1708. X# include <string.h>
  1709. X#else
  1710. X# include <strings.h>
  1711. X#endif /* SYSV */
  1712. X
  1713. X#include "dominion.h"
  1714. X#include "misc.h"
  1715. X#include "army.h"
  1716. X#include <math.h>
  1717. X#include <curses.h>
  1718. X#include <stdio.h>
  1719. X#include <ctype.h>
  1720. X#include <signal.h>
  1721. X
  1722. X#define CUTOFF1 -30        /* army bonus for draft cutoff 1 (npc_draft) */
  1723. X#define CUTOFF2 0        /* army bonus for draft cutoff 2 (npc_draft) */
  1724. X
  1725. Xextern Sworld world;
  1726. Xextern Suser user;
  1727. Xextern struct s_desig_map desig_map[];
  1728. Xextern int (*wrapx)(), (*wrapy)();
  1729. Xextern int debug;
  1730. Xextern struct army_type *army_types;
  1731. Xextern struct spirit_type *spirit_types;
  1732. X
  1733. Xextern float npc_food_need,npc_metal_need,npc_jewel_need,npc_money_need;
  1734. Xextern int opt_army_size,atwar,npc_specific;
  1735. X
  1736. X/*--------------------find_visible_sectors()-------------------------------
  1737. X   NOTE: the following routine copied from user.c to avoid fiddling with
  1738. X   the Makefile and increasing the size of dom_update.  One difference,
  1739. X   viewall is not used. 
  1740. X
  1741. X   this routine goes through the entire map and figures out
  1742. X   which sectors are visible by the user.
  1743. X---------------------------------------------------------------------------*/
  1744. X/*
  1745. Xfind_visible_sectors(visible_sectors)
  1746. X     int **visible_sectors;
  1747. X{
  1748. X  int x, y, i, j;
  1749. X  struct pt_list *plist;
  1750. X  Sarmy *ap;
  1751. X  Ssector *sp;
  1752. X
  1753. X  for (i = 0; i < world.xmax; ++i) {
  1754. X    for (j = 0; j < world.ymax; ++j) {
  1755. X      visible_sectors[i][j] = SEE_NOTHING;
  1756. X    }
  1757. X  }
  1758. X  for (plist = user.np->ptlist; plist != NULL; plist = plist->next) {
  1759. X    x = plist->pt.x;
  1760. X    y = plist->pt.y;
  1761. X    visible_sectors[x][y] = SEE_ALL;
  1762. X    for (i = x-LAND_SIGHT; i <= x+LAND_SIGHT; ++i) {
  1763. X      for (j = y-LAND_SIGHT; j <= y+LAND_SIGHT; ++j) {
  1764. X    sp = &world.map[(*wrapx)(i,j)][(*wrapy)(i,j)];
  1765. X    if (has_hidden(sp) && sp->owner != user.id) {
  1766. X      visible_sectors[x][y] |= SEE_ARMIES;
  1767. X    } else {
  1768. X      visible_sectors[(*wrapx)(i,j)][(*wrapy)(i,j)] |=
  1769. X        (SEE_LAND_WATER | SEE_OWNER | SEE_DESIG | SEE_POPULATION);
  1770. X    }
  1771. X    if (world.map[(*wrapx)(i,j)][(*wrapy)(i,j)].owner == 0) {
  1772. X      visible_sectors[(*wrapx)(i,j)][(*wrapy)(i,j)] |= SEE_RESOURCES;
  1773. X    }
  1774. X      }
  1775. X    }
  1776. X  }
  1777. X  for (ap = user.np->armies; ap != NULL; ap = ap->next) {
  1778. X    x = ap->pos.x;
  1779. X    y = ap->pos.y;
  1780. X    sp = &world.map[x][y];
  1781. X    if (has_hidden(sp) && sp->owner != user.id) {
  1782. X      visible_sectors[x][y] = SEE_ARMIES;
  1783. X    } else {
  1784. X      visible_sectors[x][y] = SEE_ALL;
  1785. X    }
  1786. X    for (i = x-ARMY_SIGHT; i <= x+ARMY_SIGHT; ++i) {
  1787. X      for (j = y-ARMY_SIGHT; j <= y+ARMY_SIGHT; ++j) {
  1788. X    sp = &world.map[(*wrapx)(i,j)][(*wrapy)(i,j)];
  1789. X    if (!has_hidden(sp)) {
  1790. X      visible_sectors[(*wrapx)(i,j)][(*wrapy)(i,j)] |=
  1791. X        (SEE_LAND_WATER | SEE_OWNER | SEE_DESIG |
  1792. X         SEE_POPULATION | SEE_ARMIES);
  1793. X    }
  1794. X    if (world.map[(*wrapx)(i,j)][(*wrapy)(i,j)].owner == 0) {
  1795. X      visible_sectors[(*wrapx)(i,j)][(*wrapy)(i,j)] |= SEE_RESOURCES;
  1796. X    }
  1797. X      }
  1798. X    }
  1799. X  }
  1800. X}
  1801. X*/
  1802. X/*------------------------------get_good_types()-----------------------------
  1803. X    This function fills an array with the indexed to army_types that will
  1804. Xbe good for this npc.
  1805. X    Basically, the npc will only draft armies like spearmen and cavemen
  1806. Xwhen it is in desperate straits.  For now, npc's will not draft transports,
  1807. Xwater-walk armies, kamikaze armies, front-line armies, or machines, because
  1808. Xhandling these well is beyond me at this point.
  1809. X    The npc decides whether or not to draft armies with low bonuses based
  1810. Xon the proportion of current#of troops to desired #of troops.  The desired
  1811. Xis  civilians * npc_agg/200 when at war, and civil. * npc_agg/300 otherwise.
  1812. XThe cutoffs are 25+npc/2 % and npc/2 %, for armies with -1 to -30 bonuses and
  1813. Xarmies with <-30 bonuses, respectively.
  1814. X    For example, a nation with an aggressiveness of 50 and a civilian
  1815. Xpopulation of 10,000 will not draft cavemen when it has more than 625 soldiers,
  1816. Xand will not draft spearmen when it has more than 1250 soldiers, and will not
  1817. Xdraft at all when it has more than 2500 soldiers. (when at war)
  1818. X---------------------------------------------------------------------------*/
  1819. Xget_good_types(good_armies,current,cut1,cut2)
  1820. Xint good_armies[MAX_TYPES];
  1821. Xint current,cut1,cut2;    /* current # of troops and cutoffs */
  1822. X{
  1823. X  Savail_army *tmp_avail;
  1824. X  struct army_type this_atype;
  1825. X  int type_index,ngood = 0,badflags;
  1826. X
  1827. X  badflags = AF_WATER |  AF_LAND | AF_INVERSE_ALT | AF_KAMIKAZE | AF_FRONT_LINE
  1828. X       | AF_MACHINE | AF_CARGO | AF_WIZARD;
  1829. X
  1830. X  for(tmp_avail = user.avail_armies;tmp_avail ; tmp_avail = tmp_avail->next){
  1831. X    type_index = army_type_index(tmp_avail->type);
  1832. X    this_atype = army_types[type_index];
  1833. X    if (this_atype.flags & badflags)
  1834. X     continue;
  1835. X    if(this_atype.bonus < CUTOFF1 && current > cut1)
  1836. X      continue;
  1837. X    else if(this_atype.bonus < CUTOFF2 && current > cut2)
  1838. X      continue;
  1839. X        /* replace army type with race-specific type if appropriate */
  1840. X    if(npc_specific &&
  1841. X    army_types[npc_specific-1].bonus >= this_atype.bonus &&
  1842. X    this_atype.bonus >= 0)
  1843. X      good_armies[ngood++] = npc_specific - 1;
  1844. X    else
  1845. X      good_armies[ngood++] = type_index;
  1846. X    }
  1847. X  if (debug)
  1848. X    printf("ngood = %d\n",ngood);
  1849. X  return(ngood);
  1850. X}
  1851. X
  1852. X/*---------------------------tmp_army_better()-------------------------------
  1853. X    This function checks tmpap and oldap to see if tmpap would be better
  1854. Xfor ap to merge with.  Better is defined as big enough after the merge
  1855. Xto take sectors, but smaller after the merge than the other army.
  1856. XThis is a crude way of preventing one army from growing too large.
  1857. XEdit to your heart's content, if you think it will make the npc's better.
  1858. X    (This function is called by npc_merge)
  1859. X------------------------------------------------------------------------*/
  1860. Xtmp_army_better(ap,tmpap,oldap)
  1861. XSarmy *ap,*tmpap,*oldap;
  1862. X{
  1863. X  if(strcmp(tmpap->type,ap->type)){    /* different types */
  1864. X    return(0);
  1865. X  }
  1866. X  
  1867. X  if(!oldap)                /* anything is better than nothing */
  1868. X    return(1);
  1869. X
  1870. X  if(tmpap->n_soldiers + ap->n_soldiers < opt_army_size)
  1871. X    return(0);                /* already have oldap */
  1872. X
  1873. X  if(tmpap->n_soldiers < oldap->n_soldiers)
  1874. X    return(1);                /* enough soldiers but not too big */
  1875. X  else
  1876. X    return(0);                /* too big */
  1877. X}
  1878. X
  1879. X/*---------------------------find_desire()------------------------------------
  1880. X    Fill the desire array with the desireability for each sector on the
  1881. Xmap.  The base desire goes from zero to half the length of the shortest side.
  1882. XTo find the final desire, the base desire is squared.  The desire for the
  1883. Xsurrounding sectors is modified.  If the base desire is N, then all the
  1884. Xadjacent sectors have their desireability increased by N-1, the next sectors
  1885. Xout are increased by N-2, etc.  This will hopefully keep npc's moving in the
  1886. Xright general direction. (the base desire of owned sectors is 0, unless at war)
  1887. X---------------------------------------------------------------------------*/
  1888. Xfind_desire(np,des_array)
  1889. XSnation *np;
  1890. Xstruct desire{
  1891. X    int base,final;
  1892. X    } **des_array;
  1893. X{
  1894. X  int x,y,i,d;
  1895. X
  1896. X  for(x = 0; x < world.xmax;x++)
  1897. X    for(y = 0; y < world.ymax; y++){
  1898. X      des_array[x][y].base = npc_des(np,x,y);
  1899. X      des_array[x][y].final = 0;
  1900. X    }
  1901. X
  1902. X  for(x = 0; x < world.xmax;x++)
  1903. X    for(y = 0; y < world.ymax; y++){
  1904. X      d = des_array[x][y].base;
  1905. X      des_array[x][y].final += d*d;
  1906. X      if(atwar && d > 0){        /* sector owned by us or enemy */
  1907. X        des_array[x][y].final += world.map[x][y].n_people/25;
  1908. X        if (world.map[x][y].designation == D_CAPITAL) 
  1909. X          des_array[x][y].final *= 2;
  1910. X        }
  1911. X      if(user.visible_sectors[x][y])
  1912. X        for(i = 1;i < d && add_square(x,y,i,d-i,des_array,np);i++);
  1913. X      }
  1914. X/* This makes a big mess--------
  1915. X    if(debug){
  1916. X    for(y = 0; y < world.ymax; y++){
  1917. X      for(x = 0; x < world.xmax;x++)
  1918. X        printf("%2d,",des_array[x][y].base);
  1919. X      printf("\n");
  1920. X    }
  1921. X    for(y = 0; y < world.ymax; y++){
  1922. X      for(x = 0; x < world.xmax;x++)
  1923. X        printf("%3d,",des_array[x][y].final);
  1924. X      printf("\n");
  1925. X    }
  1926. X  } */
  1927. X}
  1928. X
  1929. X/*-------------------------------npc_des()-------------------------------------
  1930. X    This function calculates the desireability of a sector to an npc.
  1931. XThis desireability will be calculated differently when the npc is at war
  1932. Xthan when it is at peace.  For now, just try to expand.
  1933. X-----------------------------------------------------------------------------*/
  1934. Xnpc_des(np,x,y)
  1935. XSnation *np;
  1936. Xint x,y;
  1937. X{
  1938. X  int num,i,j,dstat;
  1939. X  Sdiplo **dm;
  1940. X
  1941. X  if(!good_altitude(&world.map[x][y],np))
  1942. X    return(0);
  1943. X
  1944. X  if(atwar && world.map[x][y].owner){
  1945. X    dm = user.diplo_matrix;
  1946. X    dstat = get_diplo_status(dm, np->id, world.map[x][y].owner);
  1947. X    if(world.map[x][y].owner != np->id && (dstat != WAR && dstat != JIHAD))
  1948. X      return(0);
  1949. X  } else if (world.map[x][y].owner == np->id)
  1950. X    return (0);
  1951. X
  1952. X  if(atwar && world.map[x][y].owner){
  1953. X    if(world.map[x][y].owner == np->id){
  1954. X      switch(world.map[x][y].designation){
  1955. X        case D_FARM:
  1956. X          num = 3 + world.map[x][y].soil * npc_food_need;
  1957. X      break;
  1958. X        case D_METAL_MINE:
  1959. X          num = 3 + world.map[x][y].metal * npc_metal_need;
  1960. X      break;
  1961. X        case D_JEWEL_MINE:
  1962. X          num = 3 + world.map[x][y].jewels * npc_jewel_need;
  1963. X      break;
  1964. X        case D_CITY: case D_UNIVERSITY:
  1965. X          num = 11;
  1966. X      break;
  1967. X    case D_CAPITAL:
  1968. X      num = 8 + np->npc_agg / 10;
  1969. X      break;
  1970. X        default:
  1971. X      break;
  1972. X        }
  1973. X      }
  1974. X    else{
  1975. X      num = 12;
  1976. X  /*    switch(world.map[x][y].designation){
  1977. X        case D_FARM:
  1978. X          num = 8 * npc_food_need;
  1979. X      break;
  1980. X        case D_METAL_MINE:
  1981. X          num = 8 * npc_metal_need;
  1982. X      break;
  1983. X        case D_JEWEL_MINE:
  1984. X          num = 8 * npc_jewel_need;
  1985. X      break;
  1986. X        case D_CITY: case D_UNIVERSITY: case D_CAPITAL:
  1987. X      num = 12;
  1988. X      break;
  1989. X        default:
  1990. X      num = 7;
  1991. X      break;
  1992. X        } */
  1993. X  
  1994. X      for(i = -1;i < 2;i++)
  1995. X        for(j = -1;j < 2;j++)
  1996. X          if(world.map[(*wrapx)(x+j,y+i)][(*wrapy)(x+j,y+i)].owner == np->id)
  1997. X            num++;
  1998. X      /* if(world.map[x][y].n_people >= 0)
  1999. X        num += sqrt((double)world.map[x][y].n_people)/5.0; */
  2000. X      }
  2001. X    }
  2002. X  
  2003. X  else{
  2004. X    num = world.map[x][y].soil * npc_food_need;
  2005. X    num += world.map[x][y].metal * npc_metal_need;
  2006. X    num += world.map[x][y].jewels * npc_jewel_need;
  2007. X    for(i = -1;i < 2;i++)
  2008. X      for(j = -1;j < 2;j++)
  2009. X        if(world.map[(*wrapx)(x+j,y+i)][(*wrapy)(x+j,y+i)].owner == np->id)
  2010. X          num++;
  2011. X  }
  2012. X
  2013. X/*  if(atwar && !world.map[x][y].owner)
  2014. X    return(num/4);
  2015. X  else */
  2016. X  num = min ( num, min (world.xmax, world.ymax) );
  2017. X    return(num/2);
  2018. X}
  2019. X
  2020. X/*----------------------------add_square()---------------------------------
  2021. X    This function adds a number, add to the desireability of the sectors
  2022. Xradius away from x,y.  Radius is defined rather loosely here, since the sectors
  2023. Xform a square.
  2024. X---------------------------------------------------------------------------*/
  2025. Xadd_square(x,y,radius,add,des_array,np)
  2026. Xint x,y,radius,add;
  2027. Xstruct desire{
  2028. X    int base,final;
  2029. X    } **des_array;
  2030. XSnation *np;
  2031. X{
  2032. Xint i,tx,ty,id,flag = 0;
  2033. XSsector *sp;
  2034. X
  2035. X  id = np->id;
  2036. X  tx = x-radius;            /* bottom side from lower left corner */
  2037. X  ty = y-radius;
  2038. X  for(i = 0; i < radius*2;i++){
  2039. X    sp = &world.map[(*wrapx)(tx+i,ty)][(*wrapy)(tx+i,y)];
  2040. X    if(!good_altitude(sp,np))
  2041. X      flag++;
  2042. X    des_array[(*wrapx)(tx+i,ty)][(*wrapy)(tx+i,ty)].final += add;
  2043. X  }
  2044. X
  2045. X  ty = y+radius;            /* left side from upper left corner */
  2046. X  for(i = 0; i < radius*2;i++){
  2047. X    sp = &world.map[(*wrapx)(tx,ty-i)][(*wrapy)(tx-i,y-i)];
  2048. X    if(!good_altitude(sp,np))
  2049. X      flag++;
  2050. X    des_array[(*wrapx)(tx,ty-i)][(*wrapy)(tx,ty-i)].final += add;
  2051. X  }
  2052. X
  2053. X  tx = x+radius;            /* top side from upper right corner */
  2054. X  for(i = 0; i < radius*2;i++){
  2055. X    sp = &world.map[(*wrapx)(tx-i,ty)][(*wrapy)(tx-i,y)];
  2056. X    if(!good_altitude(sp,np))
  2057. X      flag++;
  2058. X    des_array[(*wrapx)(tx-i,ty)][(*wrapy)(tx-i,ty)].final += add;
  2059. X  }
  2060. X
  2061. X  ty = y-radius;            /* right side from lower right corner */
  2062. X  for(i = 0; i < radius*2;i++){
  2063. X    sp = &world.map[(*wrapx)(tx,ty+i)][(*wrapy)(tx,y+i)];
  2064. X    if(!good_altitude(sp,np))
  2065. X      flag++;
  2066. X    des_array[(*wrapx)(tx,ty+i)][(*wrapy)(tx,ty+i)].final += add;
  2067. X  }
  2068. X
  2069. X  return((flag > 4*radius) ? 0:1);    /* equal to zero if lots of water */
  2070. X}
  2071. X
  2072. X/*----------------------------check_moves()-----------------------------------
  2073. X    Ary represents the area of the map centered at the army ap.  This
  2074. Xfunction fills ary with the maximum movepoints the army can have left when
  2075. Xit arrives at the sector.  Of course, routes that are outside of the section
  2076. Xof the map in ary are not considered, so a larger value for NPC_SIDE will
  2077. Xsometimes result in better movement.  However, since the algorithm includes
  2078. Xan insertion, it's best to keep the value small in the interest of time.
  2079. X--------------------------------------------------------------------------*/
  2080. Xcheck_moves(np,ap,ary)
  2081. XSnation *np;
  2082. XSarmy *ap;
  2083. Xstruct tmp_map{
  2084. X  int mvcost,mvleft;
  2085. X  } ary[NPC_SIDE][NPC_SIDE];
  2086. X{
  2087. X  int i,j,k;
  2088. X  int x,y,tx,ty,mapx,mapy;
  2089. X  int mv,mvleft;
  2090. X  int head=0,tail=0;
  2091. X  struct mvlist{
  2092. X    int mv;
  2093. X    Pt pos;
  2094. X  } list[NPC_SIDE * NPC_SIDE];    /* doesn't really need to be this big */
  2095. X  Ssector *sect;
  2096. X
  2097. X  for(x = 1; x < NPC_SIDE-1; x++)
  2098. X  for(y = 1; y < NPC_SIDE-1; y++){
  2099. X    tx = x - (NPC_VIEW+1) + ap->pos.x;    /* translate ary */
  2100. X    ty = y - (NPC_VIEW+1) + ap->pos.y;    /* coords to map */
  2101. X    sect = &world.map[(*wrapx)(tx,ty)][(*wrapy)(tx,ty)];
  2102. X    ary[x][y].mvleft = -1;
  2103. X    ary[x][y].mvcost = get_army_move_cost(np,sect,ap);
  2104. X  }
  2105. X  for(i = 0;i < NPC_SIDE * NPC_SIDE;i++)    /* initialize list of points */
  2106. X  list[i].mv = 0;
  2107. X  /* start army in center of ary with whatever movement it has */
  2108. X  ary[NPC_VIEW+1][NPC_VIEW+1].mvleft = ap->mvpts;
  2109. X  list[0].mv = ap->mvpts;
  2110. X  list[0].pos.x = NPC_VIEW+1;
  2111. X  list[0].pos.y = NPC_VIEW+1;
  2112. X
  2113. X  for(head = 0; list[head].mv; head++){        /* until list is empty */
  2114. X    mv = list[head].mv;
  2115. X    for(x = list[head].pos.x-1;x <= list[head].pos.x + 1;x++)
  2116. X      for(y = list[head].pos.y-1;y <= list[head].pos.y + 1;y++)
  2117. X        if(ary[x][y].mvleft == -1 && ary[x][y].mvcost <= mv){
  2118. X          mvleft = mv - ary[x][y].mvcost;
  2119. X          ary[x][y].mvleft = mvleft;
  2120. X          if(mvleft){
  2121. X            for(j = tail;list[j].mv < mvleft;j--);
  2122. X            for(k = tail;k > j;k--)
  2123. X              list[k+1] = list[k];
  2124. X            list[j+1].mv = mvleft;
  2125. X            list[j+1].pos.x = x;
  2126. X            list[j+1].pos.y = y;
  2127. X            tail++;
  2128. X          }
  2129. X        }
  2130. X    }
  2131. X
  2132. Xif(debug){
  2133. X  printf("ary for army %d= :\n",ap->id);
  2134. X  for(y = 0; y < NPC_SIDE; y++){
  2135. X    for(x = 0;x < NPC_SIDE;x++)
  2136. X      printf("[%d,%d],",ary[x][y].mvleft,ary[x][y].mvcost);
  2137. X    printf("\n");
  2138. X    }
  2139. X  }
  2140. X}
  2141. X
  2142. X/*--------------------------do_npc_diplo()------------------------------------
  2143. X    Update the diplomacy for npcs.  Change the diplomacy according to
  2144. Xa random number, and the npc aggressiveness.  If the number is less than
  2145. Xthe npc aggressiveness, then the diplomacy status goes down.  Otherwise
  2146. Xit goes up.
  2147. X---------------------------------------------------------------------------*/
  2148. Xdo_npc_diplo(np)
  2149. X     Snation *np;
  2150. X{
  2151. X  int i,dip_from,dip_to,num,up,down;
  2152. X  Snation *tmpnp;
  2153. X  
  2154. X  /* Take care of NPC diplomacy here */
  2155. X  
  2156. X  atwar = 0;
  2157. X  for(i = 1;i < world.n_nations;i++){
  2158. X    tmpnp = &world.nations[i];
  2159. X    if (is_active_ntn(tmpnp) && (!tmpnp->npc_flag || NPC_FIGHT)) { 
  2160. X      if (!have_met(user.diplo_matrix, np->id, i))
  2161. X        continue;
  2162. X      dip_to = get_diplo_status(user.diplo_matrix, np->id, i);
  2163. X      dip_from = get_diplo_status(user.diplo_matrix, i, np->id);
  2164. X      if (debug)
  2165. X    printf("from = %d, to = %d\n",dip_from,dip_to);
  2166. X      down = np->npc_agg * DIP_CHANGE / 100;
  2167. X      up = (100 - np->npc_agg) * DIP_CHANGE / 100;
  2168. X      num = RND()%100;
  2169. X      if (debug)
  2170. X    printf("num = %d ",num);
  2171. X      if(num < np->npc_agg){
  2172. X        if(num < down/2 || dip_from < dip_to)
  2173. X          dip_to--;
  2174. X        if(num < down)
  2175. X      dip_to--;
  2176. X    }
  2177. X      else{
  2178. X    num = 100 - num;
  2179. X        if(num < up/2)
  2180. X      dip_to++;
  2181. X        if(num < up)
  2182. X      dip_to++;
  2183. X    }
  2184. X      if(dip_to > dip_from)
  2185. X        dip_to = dip_from;
  2186. X      dip_to = max(dip_to,JIHAD);
  2187. X      if (debug)
  2188. X    printf("up = %d, down = %d, newto = %d\n",up,down,dip_to);
  2189. X      if(dip_to == WAR || dip_to == JIHAD)
  2190. X        atwar = 1;
  2191. X      set_diplo_status(user.diplo_matrix,np->id,i,dip_to);
  2192. X      }
  2193. X    }
  2194. X  dump_diplo(np,user.diplo_matrix, world.n_nations);
  2195. X}
  2196. X
  2197. X/*---------------------------init_npc_mage()-----------------------------------
  2198. X    Initiate a mage for the npc.  Copied from menus.c
  2199. X-----------------------------------------------------------------------------*/
  2200. Xinit_npc_mage(np,sp)
  2201. XSnation *np;
  2202. XSsector *sp;
  2203. X{
  2204. X  Sarmy army, make_army();
  2205. X
  2206. X  army = make_army("Mage", "Mage", 1, A_DEFEND, np->id, sp->loc);
  2207. X  army.jewel_maint = 1000;
  2208. X  army.id = free_army_id(np);
  2209. X  army.flags |= AF_WIZARD;
  2210. X  army.next = NULL;
  2211. X    /* now insert it into the list */
  2212. X  np->n_armies++;
  2213. X  if (np->armies == NULL) { /* special case:  empty list */
  2214. X    np->armies = (Sarmy *) malloc(sizeof(Sarmy));
  2215. X    *(np->armies) = army;
  2216. X    np->armies->next = NULL;
  2217. X  } else {
  2218. X    insert_army_nation(np, &army, -1);
  2219. X  }
  2220. X  insert_army_sector(sp, &army);
  2221. X  np->jewels -= INITIATION_JEWELS;
  2222. X}
  2223. END_OF_FILE
  2224. if test 17716 -ne `wc -c <'npclib.c'`; then
  2225.     echo shar: \"'npclib.c'\" unpacked with wrong size!
  2226. fi
  2227. # end of 'npclib.c'
  2228. fi
  2229. echo shar: End of archive 22 \(of 28\).
  2230. cp /dev/null ark22isdone
  2231. MISSING=""
  2232. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 ; do
  2233.     if test ! -f ark${I}isdone ; then
  2234.     MISSING="${MISSING} ${I}"
  2235.     fi
  2236. done
  2237. if test "${MISSING}" = "" ; then
  2238.     echo You have unpacked all 28 archives.
  2239.     echo "Now execute ./do_cat.sh to build doc files"
  2240.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2241. else
  2242.     echo You still need to unpack the following archives:
  2243.     echo "        " ${MISSING}
  2244. fi
  2245. ##  End of shell archive.
  2246. exit 0
  2247.