home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / games / volume13 / dominion / part21 < prev    next >
Encoding:
Text File  |  1992-02-10  |  60.6 KB  |  2,225 lines

  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: v13i057:  dominion - a multi-player world simulation game, Part21/28
  5. Message-ID: <2460@masterCNA.TEK.COM>
  6. Date: 11 Feb 92 18:26:57 GMT
  7. Sender: news@masterCNA.TEK.COM
  8. Lines: 2214
  9. Approved: billr@saab.CNA.TEK.COM
  10.  
  11. Submitted-by: rosalia@dirac.physics.sunysb.edu (Mark Galassi)
  12. Posting-number: Volume 13, Issue 57
  13. Archive-name: dominion/Part21
  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 21 (of 28)."
  25. # Contents:  c_news.c economy.c npc.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 'c_news.c' -a "${1}" != "-c" ; then 
  29.   echo shar: Will not clobber existing file \"'c_news.c'\"
  30. else
  31. echo shar: Extracting \"'c_news.c'\" \(19406 characters\)
  32. sed "s/^X//" >'c_news.c' <<'END_OF_FILE'
  33. X/* c_news.c : Curses routines for the news subsystem of Dominion */
  34. X/*
  35. X * Copyright (C) 1990 Free Software Foundation, Inc.
  36. X * Written by the dominion project.
  37. X *
  38. X * This file is part of dominion.
  39. X *
  40. X * dominion is free software; you can redistribute it and/or
  41. X * modify it under the terms of the GNU General Public License as published
  42. X * by the Free Software Foundation; either version 1, or (at your option)
  43. X * any later version.
  44. X *
  45. X * This software is distributed in the hope that it will be useful,
  46. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  47. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  48. X * GNU General Public License for more details.
  49. X *
  50. X * You should have received a copy of the GNU General Public License
  51. X * along with this software; see the file COPYING.  If not, write to
  52. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  53. X */
  54. X
  55. X#include "dominion.h"
  56. X#include "news.h"
  57. X#include <stdio.h>
  58. X#ifdef SYSV
  59. X#include <string.h>
  60. X#else
  61. X#include <strings.h>
  62. X#endif
  63. X#include <ctype.h>
  64. X
  65. Xextern Suser user;        /* The current user. Used for names. */
  66. Xextern Sworld world;        /* The current world. Used for the thon. num.*/
  67. X
  68. Xextern s_group *group_find();    /* In news.c. Searches a database for a 
  69. X                 specified group. */
  70. X
  71. Xint first_unread(art_arr,g_choice)
  72. Xs_article **art_arr;
  73. Xs_group *g_choice;
  74. X{
  75. X  int loop,ret;
  76. X
  77. X  ret=g_choice->last;
  78. X  if (g_choice->first <= g_choice->last)
  79. X    for(loop=g_choice->first;((loop<=g_choice->last)&&(ret==g_choice->last))
  80. X    ;loop++)
  81. X      if (!(art_arr[loop-g_choice->first]->read))
  82. X    ret=loop;
  83. X  return(ret);
  84. X} /* first_unread */
  85. X
  86. X
  87. Xwrite_newsrc(art_arr, g_choice)
  88. Xs_article **art_arr;
  89. Xs_group *g_choice;
  90. X{
  91. X  FILE *nr_fp,*tmp_fp;
  92. X  char nr_fn[100],tmp_fn[100];
  93. X  char input[300],output[300],cmd[100],group_name[100];
  94. X  int art_pnt;
  95. X
  96. X  if ((g_choice->first)>(g_choice->last))
  97. X    return;
  98. X  sprintf(nr_fn,"%s/.newsrc.%d",NEWS_DIR,user.id);
  99. X  sprintf(tmp_fn,"%s/.tmprc.%d",NEWS_DIR,user.id);
  100. X  nr_fp=fopen(nr_fn,"r");
  101. X  tmp_fp=fopen(tmp_fn,"w");
  102. X  if (tmp_fp==NULL)
  103. X    {
  104. X      fprintf(stderr,"Could not open temp. file to save read article list\n");
  105. X      fflush(stderr);
  106. X      fclose(nr_fp);
  107. X      fclose(tmp_fp);
  108. X    }
  109. X  else
  110. X    {
  111. X      if (nr_fp!=NULL)
  112. X/*    while((fscanf(nr_fp,"%[^\n]",input))!=EOF)*/
  113. X    while ((fgets(input,300,nr_fp))!=NULL)
  114. X      {
  115. X        sscanf(input,"%s",group_name);
  116. X        if (strcmp(group_name,g_choice->name))
  117. X          fprintf(tmp_fp,"%s",input);
  118. X      }
  119. X      fprintf(tmp_fp,"%s ",g_choice->name);
  120. X      art_pnt=g_choice->first;
  121. X      while(art_pnt<=g_choice->last)
  122. X    {
  123. X      if (!(art_arr[art_pnt-g_choice->first]->read))
  124. X        art_pnt++;
  125. X      else
  126. X        if ((art_pnt<g_choice->last)&&
  127. X        (art_arr[art_pnt+1-g_choice->first]->read))
  128. X          {
  129. X        fprintf(tmp_fp,"%d-",art_pnt);
  130. X        while((art_pnt<g_choice->last)&&
  131. X              (art_arr[art_pnt+1-g_choice->first]->read))
  132. X          art_pnt++;
  133. X        fprintf(tmp_fp,"%d ",art_pnt);
  134. X        art_pnt++;
  135. X          }
  136. X        else
  137. X          {
  138. X        fprintf(tmp_fp,"%d ",art_pnt);
  139. X        art_pnt++;
  140. X          }
  141. X    } /* while art_pnt <= gchoice->last */
  142. X      fprintf(tmp_fp,"\n");
  143. X      fclose(tmp_fp);
  144. X      fclose(nr_fp);
  145. X      sprintf(cmd,"rm -f %s",nr_fn);
  146. X      system(cmd);
  147. X      sprintf(cmd,"cp %s %s",tmp_fn,nr_fn);
  148. X      system(cmd);
  149. X      sprintf(cmd,"rm -f %s",tmp_fn);
  150. X      system(cmd);
  151. X    } /* else */
  152. X} /* write_newsrc */
  153. X
  154. Xread_newsrc(art_arr,g_choice)
  155. Xs_article **art_arr;
  156. Xs_group *g_choice;
  157. X{
  158. X  FILE *nr_fp;
  159. X  char nr_fn[100],input[300],group_name[100],*in_ptr;
  160. X  int art_num,art_pnt,first_art,last_art;
  161. X
  162. X  sprintf(nr_fn,"%s/.newsrc.%d",NEWS_DIR,user.id);
  163. X  nr_fp=fopen(nr_fn,"r");
  164. X  if (nr_fp!=NULL)
  165. X    {
  166. X      while ((fgets(input,300,nr_fp))!=NULL)
  167. X    {
  168. X      sscanf(input,"%s",group_name);
  169. X      if (!strcmp(group_name,g_choice->name))
  170. X        {
  171. X          in_ptr=strchr(input,(int)' ');
  172. X          if (in_ptr!=NULL)
  173. X        in_ptr++;
  174. X          while (*in_ptr!='\0')
  175. X        {
  176. X          sscanf(in_ptr,"%d",&first_art);
  177. X          while (isdigit(*in_ptr))
  178. X            in_ptr++;
  179. X          if (*in_ptr=='-')
  180. X            {
  181. X              sscanf(in_ptr+1,"%d",&last_art);
  182. X              in_ptr=strchr(in_ptr,(int)(' '));
  183. X            }
  184. X          else
  185. X            {
  186. X              last_art=first_art;
  187. X              in_ptr++;
  188. X            }
  189. X          for (art_num=first_art;art_num<=last_art;art_num++)
  190. X            if ((art_num<=g_choice->last)&&(art_num>=g_choice->first))
  191. X              (art_arr[art_num-g_choice->first]->read)=1;
  192. X        } /* while *in_ptr */
  193. X        } /* if !strcmp */
  194. X    } /* while */
  195. X    } /* if nr_fp */
  196. X  fclose(nr_fp);
  197. X} /* read_newsrc */
  198. X
  199. Xart_menu_bottom(menu_lines)
  200. Xint menu_lines;
  201. X{
  202. X  mvaddstr(menu_lines+2,5,"Position arrow with [j]/[2] (down) and [k]/[8] (up)");
  203. X  mvaddstr((menu_lines+3),5,"RETURN to Read, Q to Quit    (Use SHIFT to jump by page)");
  204. X  mvaddstr(menu_lines+4,1,"(*'s indicate previously read - [r]/[u] to mark as read/unread)");
  205. X}
  206. X
  207. X
  208. X/* This function displays a portion (or the whole) of the menu of articles
  209. X   that can be read. The menu is displayed according to where the cursor is
  210. X   and where it's pointing to. (and of course the size of the screen) */
  211. X
  212. Xshow_art_menu(art_arr,menu_lines,cur_point,cur_pos,first_art,last_art)
  213. X     s_article **art_arr;
  214. X     /* This is an array of pointers to "article structures". See news.h */
  215. X     int menu_lines,cur_point,cur_pos,first_art,last_art;
  216. X     /* menu_lines: how many lines can be displayed on the screen
  217. X    cur_point: which article the cursor is pointing to
  218. X    cur_pos: where on the screen the cursor is
  219. X    first_art: the first article of all the articles that can be read
  220. X    last_art: the last article....
  221. X    */
  222. X{
  223. X  int line,art_no; /* line: what line on the display we're showing.
  224. X              art_no: What article this is we're showing. */
  225. X  char fmt[50],out[200]; /* fmt: How to format the output strings (sprintf).
  226. X                out: The output string for the menu. */
  227. X
  228. X  sprintf(fmt,"%%4d> %%-9.9s  %%-%d.%ds %%-%d.%ds",NAMELEN,
  229. X      NAMELEN,(COLS-23-NAMELEN),(COLS-23-NAMELEN)); 
  230. X  /* fmt is how the menu lines look. It's used to handle variable width screens
  231. X     4 characters for the article number, a >, 16 characters for the thon,
  232. X     NAMELEN characters for the sender, and the rest for the subject. */
  233. X  for(line=1;line <= menu_lines;line++)
  234. X    {
  235. X      art_no=(cur_point-cur_pos)+line; /* Took a while to figure out. I 
  236. X                    think it's right though. */
  237. X      if (art_no <= last_art)    /* Don't display articles past the end.  */
  238. X    {
  239. X      sprintf(out,fmt,art_no,art_arr[art_no-first_art]->date,
  240. X          art_arr[art_no-first_art]->sender,
  241. X          art_arr[art_no-first_art]->subject); /* Print to the string*/
  242. X      mvaddstr(line,4,out);    /* Show the string. */
  243. X      if ((art_arr[art_no-first_art]->read)==1)
  244. X        mvaddstr(line,5,"*");
  245. X    } /* if (art_no <= last_art */
  246. X    } /* for line=1... */
  247. X} /* show_art_menu */
  248. X
  249. X
  250. X/* This function is used for reading news articles. The user has selected a
  251. X   group to read (pointed to by g_choice). This displays a menu of the articles
  252. X   and allows the user to display articles from the menu. */
  253. X
  254. Xnews_arts_menu(g_choice,turn)
  255. Xs_group *g_choice;        /* This is the group to read from */
  256. Xint turn;            /* What thon is this? For positioning the
  257. X                 cursor. */
  258. X{
  259. X  char news_dir[100], g_dir[100], a_fn[100], cmd[100];
  260. X    /* news_dir: the main news directory. g_dir: this group's directory.
  261. X       a_fn: The file name of an article. cmd: the 'system' command
  262. X       to view arts. */
  263. X  char text[100],type[10];
  264. X    /* , date, from: The header of the articles. 
  265. X     type what type line of the header? */
  266. X  char this_thon[20]; /* What thon it is in string format. */
  267. X  FILE *a_fp; /* The file pointer to an article file. */
  268. X  int loop;   /* To loop through the articles. */
  269. X  char c;     /* The key the user presses. */
  270. X  s_article **art_arr,*a_temp;    /* art_arr: An array of pointers to
  271. X                            'article' structures.
  272. X                   a_temp: A work pointer. */
  273. X  int menu_lines,menu_center,cur_pos,cur_point,done;
  274. X  int show_next = 0;    /* should we see the next article immediately? */
  275. X    /* menu_lines: How many lines can be shown.
  276. X       menu_center: What line is the center line.
  277. X       cur_pos: Where on the screen is the cursor.
  278. X       cur_point: What article is it pointing to.
  279. X       done: Can we leave news? */
  280. X  if((g_choice->first)<=(g_choice->last))
  281. X    art_arr=(s_article **)malloc(sizeof(s_article *)*(g_choice->last-
  282. X                              g_choice->first+1));
  283. X       /* Allocate space for the array. */
  284. X  else
  285. X    art_arr=NULL;
  286. X  sprintf(this_thon,"Thon %d",turn);  
  287. X  sprintf(news_dir,"%s",NEWS_DIR);
  288. X  sprintf(g_dir,"%s/%s",news_dir,g_choice->name);
  289. X  clear();
  290. X  for(loop=g_choice->first;loop<=g_choice->last;loop++)
  291. X    {
  292. X      a_temp=(s_article *)malloc(sizeof(s_article));
  293. X      a_temp->read=0;
  294. X      sprintf(a_fn,"%s/%d",g_dir,loop);
  295. X      a_fp=fopen(a_fn,"r");
  296. X      if (a_fp!=NULL)
  297. X    {
  298. X      strcpy(a_temp->subject,"");
  299. X      while (!strcmp(a_temp->subject,""))
  300. X        {
  301. X          fscanf(a_fp,"%s",type);
  302. X          if (!strcmp(type,"Date:"))
  303. X        {
  304. X          fscanf(a_fp,"%[^\n]",text);
  305. X          strcpy(a_temp->date,text);
  306. X        }
  307. X          if (!strcmp(type,"From:"))
  308. X        {
  309. X          fscanf(a_fp,"%[^\n]",text);
  310. X          strcpy(a_temp->sender,text);
  311. X        }
  312. X          if (!strcmp(type,"Author:"))
  313. X        {
  314. X          fscanf(a_fp,"%[^\n]",text);
  315. X        }
  316. X          if (!strcmp(type,"Subj:"))
  317. X        {
  318. X          fscanf(a_fp,"%[^\n]",text);
  319. X          strcpy(a_temp->subject,text);
  320. X        }
  321. X        }
  322. X      a_temp->art_num=loop;
  323. X    }
  324. X      else
  325. X    {
  326. X      sprintf(a_temp->date,"");
  327. X      sprintf(a_temp->sender,"  --Article Missing--");
  328. X      sprintf(a_temp->subject,"");
  329. X      a_temp->art_num=loop;
  330. X    } /* else */
  331. X      art_arr[loop-(g_choice->first)]=a_temp;
  332. X      if (a_fp != NULL) { fclose(a_fp); } 
  333. X    }
  334. X
  335. X  read_newsrc(art_arr,g_choice);
  336. X  
  337. X  menu_lines=(LINES-6);
  338. X  menu_lines=(int)((menu_lines-1)/2);
  339. X  menu_lines*=2;
  340. X  menu_lines+=1;
  341. X  menu_center=(int)((menu_lines+1)/2);
  342. X  cur_point=first_unread(art_arr,g_choice);
  343. X  cur_pos=cur_point-(g_choice->first-1);
  344. X  while (cur_pos>menu_lines)
  345. X    cur_pos-=(menu_center);
  346. X    
  347. X  
  348. X  show_art_menu(art_arr,menu_lines,cur_point,cur_pos,g_choice->first,
  349. X        g_choice->last);
  350. X  art_menu_bottom(menu_lines);
  351. X  mvaddstr(cur_pos,1,"===>");
  352. X  refresh();
  353. X  done=0;
  354. X  while (!done)
  355. X    {
  356. X      switch(c=getch()) {
  357. X      case 'k':
  358. X      case '8':
  359. X    if (cur_point > g_choice->first)
  360. X      {
  361. X        mvaddstr(cur_pos,1,"    ");
  362. X        cur_point--;
  363. X        if (cur_pos==1)
  364. X          {
  365. X        cur_pos=menu_center;
  366. X        clear();
  367. X        show_art_menu(art_arr,menu_lines,cur_point,cur_pos,
  368. X                  g_choice->first,g_choice->last);
  369. X        art_menu_bottom(menu_lines);
  370. X          }
  371. X        else
  372. X          cur_pos--;
  373. X        mvaddstr(cur_pos,1,"===>");
  374. X        refresh();
  375. X      } /* if cur_point > ... */
  376. X    break; 
  377. X      case 'K':
  378. X      case '*':
  379. X    if (cur_point > g_choice->first)
  380. X      {
  381. X        mvaddstr(cur_pos,1,"    ");
  382. X        if (cur_pos > menu_center)
  383. X          {
  384. X        cur_point-=(cur_pos-menu_center);
  385. X        cur_pos=menu_center;
  386. X          }
  387. X        else
  388. X          {
  389. X        cur_point-=cur_pos;
  390. X        if (cur_point<g_choice->first)
  391. X          {
  392. X            cur_pos=1;
  393. X            cur_point=g_choice->first;
  394. X          }
  395. X        else
  396. X          {
  397. X            cur_pos=menu_center;
  398. X            clear();
  399. X            show_art_menu(art_arr,menu_lines,cur_point,cur_pos,
  400. X                  g_choice->first, g_choice->last);
  401. X            art_menu_bottom(menu_lines);
  402. X          } /* else */
  403. X          } /* else */
  404. X        mvaddstr(cur_pos,1,"===>");
  405. X        refresh();
  406. X      } /* if cur_point ... */
  407. X    break;
  408. X      case 'j':
  409. X      case '2':
  410. X      if (cur_point < g_choice->last)
  411. X    {
  412. X      mvaddstr(cur_pos,1,"    ");
  413. X      cur_point++;
  414. X      if (cur_pos==menu_lines)
  415. X        {
  416. X          cur_pos=menu_center;
  417. X          clear();
  418. X          show_art_menu(art_arr,menu_lines,cur_point,cur_pos,
  419. X                g_choice->first, g_choice->last);
  420. X          art_menu_bottom(menu_lines);
  421. X        }
  422. X      else
  423. X        cur_pos++;
  424. X      mvaddstr(cur_pos,1,"===>");
  425. X      refresh();
  426. X    } /*  if cur_point... */
  427. X      break;
  428. X      case 'J':
  429. X      case '@':
  430. X    if (cur_point < g_choice->last)
  431. X      {
  432. X        mvaddstr(cur_pos,1,"    ");
  433. X        if (cur_pos<menu_center)
  434. X          {
  435. X        cur_point+=(menu_center-cur_pos);
  436. X        cur_pos=menu_center;
  437. X          }
  438. X        else
  439. X          {
  440. X        cur_point+=((menu_lines-cur_pos)+1);
  441. X        if(cur_point>g_choice->last)
  442. X          {
  443. X            cur_point=g_choice->last;
  444. X            cur_pos=cur_point-(g_choice->first-1);
  445. X            while(cur_pos>menu_lines)
  446. X              cur_pos-=menu_center;
  447. X          }
  448. X        else
  449. X          {
  450. X            cur_pos=menu_center;
  451. X            clear();
  452. X            show_art_menu(art_arr,menu_lines,cur_point,cur_pos,
  453. X                  g_choice->first, g_choice->last);
  454. X            art_menu_bottom(menu_lines);
  455. X          } /* else*/
  456. X          } /* else */
  457. X        mvaddstr(cur_pos,1,"===>");
  458. X        refresh();
  459. X      } /* if cur_point... */
  460. X    break;
  461. X      case 'r':
  462. X    if (art_arr!=NULL)
  463. X      {
  464. X        art_arr[cur_point-g_choice->first]->read=1;
  465. X        mvaddstr(cur_pos,5,"*");
  466. X        mvaddstr(cur_pos,5,"");
  467. X      }
  468. X    break;
  469. X      case 'u':
  470. X    if (art_arr!=NULL)
  471. X      {
  472. X        art_arr[cur_point-g_choice->first]->read=0;
  473. X        mvaddstr(cur_pos,5," ");
  474. X        mvaddstr(cur_pos,5,"");
  475. X      }
  476. X          break;
  477. X      case '\n':
  478. X      case '\r':
  479. X      case ' ':
  480. X    show_next = 0;
  481. X    start_help_win();
  482. X    do {
  483. X        /* show the article with more */
  484. X/*      sprintf(cmd,"more %s/%d",g_dir,cur_point);
  485. X      sprintf(cmd,"%s/%d",g_dir,cur_point);
  486. X*/
  487. X      sprintf(a_fn, "%s/%d", g_dir, cur_point);
  488. X/*      cleanup(); */
  489. X/*      system(cmd); */
  490. X/*      show_file(a_fn); */
  491. X/*      init_screen(); */
  492. X/*      printf("\nPress RETURN to continue or [n] for the next article\n");
  493. X      fflush(stdout);
  494. X*/
  495. X        /* run the pager on the file.  pager() returns 'n'
  496. X           if the user types n at the end of an article
  497. X         */
  498. X      if ((c = pager(a_fn)) != 'n'){ /* run the pager on this file */
  499. X        statline("RETURN or [q] for article menu; [n] for next article"
  500. X             , "");
  501. X        c = getch();
  502. X      }
  503. X
  504. X      if (art_arr!=NULL)
  505. X        art_arr[cur_point-g_choice->first]->read=1;
  506. X
  507. X      if (c == 'n') {
  508. X        show_next = 1;
  509. X      } else {
  510. X        show_next = 0;
  511. X      }
  512. X      if(cur_point<g_choice->last) {
  513. X        cur_point++;
  514. X        cur_pos++;
  515. X        if (cur_pos>=menu_lines)
  516. X           cur_pos-=menu_center;
  517. X      } /* if cur_point < */
  518. X    } while (show_next);
  519. X    end_help_win();
  520. X    clear();
  521. X    show_art_menu(art_arr,menu_lines,cur_point,cur_pos,
  522. X              g_choice->first,g_choice->last);
  523. X    art_menu_bottom(menu_lines);
  524. X    mvaddstr(cur_pos,1,"===>");
  525. X    refresh();
  526. X    break;
  527. X      case 'Q':
  528. X      case 'q':
  529. X    done=1;
  530. X    break;
  531. X      } /* switch */
  532. X    }   /* while */
  533. X  /* Write out "newsrc" data for this group */
  534. X  write_newsrc(art_arr,g_choice);
  535. X  /* Clean up memory */
  536. X  for (loop=g_choice->first;loop<=g_choice->last;loop++)
  537. X    free(art_arr[loop-(g_choice->first)]);
  538. X  free(art_arr);
  539. X
  540. X  clear();
  541. X} /* news_arts_menu */
  542. X
  543. X
  544. Xs_group *news_groups_menu(human,reading)
  545. X     int human;            /* a flag to say if a human is posting. */
  546. X     int reading;               /* a flag to say if we're only reading. */
  547. X{
  548. X  int ret;
  549. X  char news_dir[100],g_fn[100],a_fn[100];
  550. X  FILE *g_fp,*a_fp;
  551. X  char g_name_in[100],post_in;
  552. X  int first_in,last_in,g_index,total_groups,cur_pos,done,loop;
  553. X  char s_in[100],c;
  554. X  s_group *g_first,*g_temp,*g_ret;
  555. X
  556. X  g_first=NULL;
  557. X  g_temp=NULL;
  558. X  total_groups=0;
  559. X
  560. X  sprintf(news_dir,"%s",NEWS_DIR);
  561. X  sprintf(g_fn,"%s/%s",news_dir,NGDB_FILE);
  562. X  g_fp=fopen(g_fn,"r");
  563. X  if (g_fp!=NULL)
  564. X/*    while ((fscanf(g_fp,"%[^:]: %d %d %c",g_name_in,&first_in,&last_in,
  565. X           &post_in))>0) */
  566. X    while ((fgets(s_in,100,g_fp))!=NULL)
  567. X      {
  568. X    s_in[strlen(s_in)-1] = '\0';
  569. X    sscanf(s_in,"%s %d %d %c",g_name_in,&first_in,&last_in,&post_in);
  570. X    g_temp=(s_group *)malloc(sizeof(s_group));
  571. X    sprintf((g_temp)->name,"%s",g_name_in);
  572. X    (g_temp)->first=first_in;
  573. X    (g_temp)->last=last_in;
  574. X    (g_temp)->postable=post_in;
  575. X    (g_temp)->next=NULL;
  576. X    if ((human==0)||(g_temp->postable=='1'))
  577. X      if (!reading||((g_temp->first)<=(g_temp->last)))
  578. X      {
  579. X        group_insert(&g_first,g_temp);
  580. X        total_groups++;
  581. X      }
  582. X    else
  583. X      free(g_temp);
  584. X      }
  585. X  if (g_fp != NULL) { fclose(g_fp); } 
  586. X  clear();
  587. X  if (g_first==NULL)
  588. X    {
  589. X      fprintf(stderr,"Problem getting group database\n");
  590. X      return(NULL);
  591. X    }
  592. X  statline("choose the group you want (RETURN to exit)","news_group_choices");
  593. X  statline2("*'s indicate articles exist","");
  594. X  g_index=0;
  595. X  for ((g_temp)=(g_first);(g_temp)!=NULL;(g_temp)=(g_temp)->next)
  596. X    {
  597. X      if ((g_temp)->last >= (g_temp)->first)
  598. X    mvaddstr((g_index)+2,6,"*");
  599. X      mvaddstr((g_index++)+2,7,(g_temp)->name);
  600. X    }
  601. X  mvaddstr(LINES-4,5,"Position arrow with [j]/[2] (down) and [k]/[8] (up)");
  602. X  mvaddstr(LINES-3,5,"RETURN to Read, Q to Quit");
  603. X  cur_pos=1;
  604. X  mvaddstr(cur_pos+1,1,"===>");
  605. X  refresh();
  606. X  done=0;
  607. X  g_temp=NULL;
  608. X/*  if (total_groups==1)
  609. X    {
  610. X      done=1;
  611. X      g_temp=g_first;
  612. X    } */
  613. X  while (!done)
  614. X    {
  615. X      switch(c=getch()) {
  616. X      case 'k':
  617. X      case '8':
  618. X    if (cur_pos>1)
  619. X      {
  620. X        mvaddstr(cur_pos+1,1,"    ");
  621. X        cur_pos--;
  622. X        mvaddstr(cur_pos+1,1,"===>");
  623. X        refresh();
  624. X      }
  625. X    break;
  626. X      case 'j':
  627. X      case '2':
  628. X    if (cur_pos<total_groups)
  629. X      {
  630. X        mvaddstr(cur_pos+1,1,"    ");
  631. X        cur_pos++;
  632. X        mvaddstr(cur_pos+1,1,"===>");
  633. X        refresh();
  634. X      }
  635. X    break;
  636. X      case '\n':
  637. X      case '\r':
  638. X      case ' ':
  639. X    g_temp=g_first;
  640. X    if (cur_pos>1)
  641. X      for(loop=2;loop<=cur_pos;loop++)
  642. X        g_temp=g_temp->next;
  643. X    done=1;
  644. X    break;
  645. X      case 'q':
  646. X      case 'Q':
  647. X    done = 1;
  648. X    break;
  649. X      } /* switch */
  650. X    } /* while */
  651. X  
  652. X/*  ret = wget_name(stdscr, g_name_in);
  653. X  if (ret > 0)
  654. X    {
  655. X      g_temp=group_find(g_first,g_name_in);
  656. X      if (g_temp==NULL)
  657. X    {
  658. X      statline("Bad Group Name - Space to Return","Bad Group Name");
  659. X      get_space();
  660. X    }
  661. X    }
  662. X  clear();*/
  663. X/* Clean up allocated space */
  664. X  g_ret=g_temp;
  665. X  for(g_temp=g_first;g_temp!=NULL;g_temp=g_first)
  666. X    {
  667. X      if (g_temp!=g_ret)
  668. X    {
  669. X      g_first=g_temp->next;
  670. X      free(g_temp);
  671. X    }
  672. X      else
  673. X    {
  674. X      g_first=g_temp->next;
  675. X      g_ret->next=NULL;
  676. X    }
  677. X    }
  678. X  return(g_ret);
  679. X} /* news_groups_menu */
  680. X
  681. Xnews()
  682. X{
  683. X  int not_done;
  684. X  char tmp_fname[PATHLEN];
  685. X  char date[80];
  686. X  char from[80];
  687. X  char subj[80],out[100];
  688. X  FILE *tmp_fp;
  689. X  int ret;
  690. X  s_group *g_first,*g_temp;
  691. X  char group[80];
  692. X  statline("do you want to (r)ead news or (p)ost news","news");
  693. X  switch (getch()) {
  694. X  case 'r':
  695. X    g_temp=news_groups_menu(0,1); /* 0 = not human(n/a), 1 = reading */
  696. X/*    if (g_temp!=NULL)
  697. X      news_arts_menu(g_temp,world.turn);*/
  698. X    while(g_temp!=NULL)
  699. X      {
  700. X    news_arts_menu(g_temp,world.turn);
  701. X    g_temp=news_groups_menu(0,1); /* 0 = not human(n/a), 1=reading */
  702. X      }
  703. X    clear(); refresh();
  704. X    break;
  705. X  case 'p':
  706. X    sprintf(date,"Thon %d",world.turn);
  707. X    sprintf(from,"%s of %s",user.np->leader,user.np->name);
  708. X    clear();
  709. X    g_temp=news_groups_menu(1,0); /* 1=human, 0=posting(!reading) */
  710. X    clear();
  711. X    if(g_temp!=NULL)
  712. X      {
  713. X    strcpy(tmp_fname, "/usr/tmp/domXXXXXX");
  714. X    if (mktemp(tmp_fname) == NULL) {
  715. X      fprintf(stderr,"Error getting temp file name\n");
  716. X      fflush(stderr);
  717. X      return;
  718. X    }
  719. X    statline("Enter Subject","Posting News");
  720. X    mvaddstr(2,1,"Subject: ");
  721. X    wget_name(stdscr, subj);
  722. X/*    echo();
  723. X    nocbreak();
  724. X    refresh();
  725. X    scanw("%[^\n]",subj);
  726. X    noecho();
  727. X    cbreak();
  728. X    refresh();
  729. X*/
  730. X    cleanup();
  731. X    edit(tmp_fname);
  732. X    {
  733. X      init_screen();
  734. X/*      initscr();
  735. X      savetty();
  736. X      nonl();
  737. X      cbreak();
  738. X      noecho();
  739. X      clear();
  740. X*/
  741. X    }
  742. X    mvaddstr(2,0,"Choices: S)end news or A)bort posting ");
  743. X    refresh();
  744. X    not_done=1;
  745. X    while(not_done)
  746. X      {
  747. X        switch(getch()) {
  748. X        case 'S':
  749. X        case 's':
  750. X          mvaddstr(3,9,"Posting News...");
  751. X          refresh();
  752. X          post_news_file(tmp_fname, g_temp->name, subj, user.id);
  753. X          mvaddstr(3,24,"done.");
  754. X          refresh();
  755. X          not_done=0;
  756. X          unlink(tmp_fname);
  757. X          break;
  758. X        case 'A':
  759. X          mvaddstr(3,23,"OK. Aborting...");
  760. X          refresh();
  761. X          unlink(tmp_fname);
  762. X          not_done=0;
  763. X          break;
  764. X        } /* switch */
  765. X      } /* while */
  766. X    {
  767. X      cleanup();
  768. X      init_screen();
  769. X    }
  770. X      } /* if g_temp!=NULL */
  771. X    break;
  772. X  } /* switch */
  773. X  user.just_moved = 1;
  774. X} /* news */
  775. END_OF_FILE
  776. if test 19406 -ne `wc -c <'c_news.c'`; then
  777.     echo shar: \"'c_news.c'\" unpacked with wrong size!
  778. fi
  779. # end of 'c_news.c'
  780. fi
  781. if test -f 'economy.c' -a "${1}" != "-c" ; then 
  782.   echo shar: Will not clobber existing file \"'economy.c'\"
  783. else
  784. echo shar: Extracting \"'economy.c'\" \(18590 characters\)
  785. sed "s/^X//" >'economy.c' <<'END_OF_FILE'
  786. X/* economy.c -- routines which deal with the economy, revenue and
  787. X               expenses of all types.
  788. X */
  789. X
  790. X/*
  791. X * Copyright (C) 1990 Free Software Foundation, Inc.
  792. X * Written by the dominion project.
  793. X *
  794. X * This file is part of dominion.
  795. X *
  796. X * dominion is free software; you can redistribute it and/or
  797. X * modify it under the terms of the GNU General Public License as published
  798. X * by the Free Software Foundation; either version 1, or (at your option)
  799. X * any later version.
  800. X *
  801. X * This software is distributed in the hope that it will be useful,
  802. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  803. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  804. X * GNU General Public License for more details.
  805. X *
  806. X * You should have received a copy of the GNU General Public License
  807. X * along with this software; see the file COPYING.  If not, write to
  808. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  809. X */
  810. X
  811. X/* calc_revenue(np) - find the amount of tax revenue for a nation  */
  812. X/* calc_metal(np) - find the amount of metal produced by nation    */
  813. X/* calc_jewels(np) - find the amount of jewels produced by nation  */
  814. X/* calc_food(np) - find the amount of food produced by nation      */
  815. X/* calc_expend(np) - calculate a nation's expenditures             */
  816. X/* calc_expend_metal(np) - calculate metal expenditures for nation */
  817. X/* calc_expend_jewels(np) - calculate jewel expenditures for nation*/
  818. X/* calc_expend_food(np) - calculate food expenditures for a nation */
  819. X/* sector_metal(sp) - calculate metal produced in a single sector  */
  820. X/* sector_jewels(sp) - calculate jewels produced in single sector  */
  821. X/* sector_food(sp) - calculate food produced in a single sector    */
  822. X/* military_maint(np) - returns total amount of money spent for armies */
  823. X/* military_maint_metal(np) - total amount of metal spent for armies   */
  824. X/* military_maint_jewels(np) - total amount of jewels spent for armies */
  825. X/* army_maint_money(ap) - amount of money needed to maintain given army*/
  826. X/* construct_cost(type) - cost to construct object                 */
  827. X/* construct_cost_metal(type) - metal cost to construct object     */
  828. X/* get_employed(np) - how many employed in that nation             */
  829. X/* get_emp_met(np) - how many employed metal miners                */
  830. X/* get_emp_jws(np) - how many employed jewel miners                */
  831. X/* get_emp_farm(np) - how many employed farmers                    */
  832. X/* (same for unemployed)                                           */
  833. X/* get_avg_money(wp) - average money in the world                  */
  834. X/* emp_desire(np,x,y) - gives the employment desireability in x,y  */
  835. X/* n_workers(sp) - number of people employed in that sect.         */
  836. X/* prod_level(np) - Relative level of production of a nation       */
  837. X
  838. X#include "dominion.h"
  839. X#include "misc.h"
  840. X#include "army.h"
  841. X#include "costs.h"
  842. X#include "cur_stuff.h"
  843. X#include <stdio.h>
  844. X#include <ctype.h>
  845. X#include <signal.h>
  846. X#include <math.h>
  847. X
  848. Xextern Sworld world;
  849. Xextern struct s_desig_map desig_map[];
  850. Xextern struct s_altitude_map altitude_map[];
  851. Xextern struct item_map terrains[];
  852. Xextern struct item_map climates[];
  853. Xextern Suser user;
  854. Xextern int debug;
  855. Xextern int (*wrapx)(), (*wrapy)();
  856. X
  857. X#define PROD_POWER (7.0/6.0)
  858. X
  859. Xdouble prod_level(np)
  860. X     Snation *np;
  861. X{
  862. X  return (1.0 - pow((double)(np->taxes)/100.0,PROD_POWER));
  863. X}
  864. X
  865. X  /* calculate the amount of tax revenue for a given nation */
  866. Xcalc_revenue(np)
  867. X     Snation *np;
  868. X{
  869. X  Ssector *sp;
  870. X  struct pt_list *points;
  871. X  int income = 0, taxes = np->taxes, pop;
  872. X    /* first thing: run through the list of that nation's sectors
  873. X       and see what income might come from the various sectors
  874. X     */
  875. X  if ((points = np->ptlist) == NULL) {
  876. X    return 0;            /* nation has no sectors!! */
  877. X  }
  878. X  do {
  879. X    sp = &(world.map[points->pt.x][points->pt.y]);
  880. X    pop = n_workers(sp);
  881. X    income+=(taxes*prod_level(np)*pop*desig_map[sp->designation].revenue)/100;
  882. X  } while ((points = points->next) != NULL);
  883. X  return income;
  884. X}
  885. X
  886. X
  887. X/* int calc_metal (Snation *) -- calculates metal owned by all sectors owned.
  888. X   - Cycles through all sectors owned, and computes metal production for
  889. X     that sector.
  890. X   - Sums them up, and returns the total.
  891. X*/ 
  892. X
  893. Xint calc_metal (np)
  894. X     Snation *np;
  895. X{
  896. X  Ssector *sp;
  897. X  struct pt_list *points;
  898. X  int metal_total = 0;
  899. X  
  900. X  if ((points = np->ptlist) == NULL) {
  901. X    return 0;            /* nation has no sectors!! */
  902. X  }
  903. X  do {
  904. X    sp = &(world.map [points->pt.x][points->pt.y]);
  905. X    switch (sp->designation) {
  906. X    case D_METAL_MINE:
  907. X      metal_total += sector_metal(sp);
  908. X      break;
  909. X    default:
  910. X      break;
  911. X    }
  912. X  } while ((points = points->next) != NULL);
  913. X  
  914. X  return (metal_total);
  915. X}
  916. X
  917. X
  918. X/* int calc_jewels (Snation *) -- calculates jewels owned by all sectors owned.
  919. X *  - Cycles through all sectors owned.
  920. X *  - If sector is a jewel mine, computes the jewels by:
  921. X *        jewels_per_civilian * number_of_people
  922. X *  - returns summation.
  923. X */
  924. X
  925. Xint calc_jewels (np)
  926. XSnation *np;
  927. X{
  928. X  Ssector *sp;
  929. X  struct pt_list *points;
  930. X  int jewels_total = 0;
  931. X
  932. X  if ((points = np->ptlist) == NULL) {
  933. X    return 0;            /* nation has no sectors!! */
  934. X  }
  935. X  do {
  936. X    sp = &(world.map[points->pt.x][points->pt.y]);
  937. X    
  938. X    switch (sp->designation) {
  939. X    case D_JEWEL_MINE:
  940. X      jewels_total += sector_jewels(sp);
  941. X      break;
  942. X    default:
  943. X      break;
  944. X    }
  945. X  } while ((points = points->next) != NULL);
  946. X
  947. X  return (jewels_total);
  948. X}
  949. X
  950. X  /* how much food is produced in the nation */
  951. Xcalc_food(np)
  952. X     Snation *np;
  953. X{
  954. X  Ssector *sp;
  955. X  struct pt_list *points;
  956. X  int food_total = 0;
  957. X
  958. X  if ((points = np->ptlist) == NULL) {
  959. X    return 0;            /* nation has no sectors!! */
  960. X  }
  961. X  do {
  962. X    sp = &(world.map[points->pt.x][points->pt.y]);
  963. X    switch (sp->designation) {
  964. X    case D_FARM:
  965. X      food_total += sector_food(sp);
  966. X      break;
  967. X    default:
  968. X      break;
  969. X    }
  970. X  } while ((points = points->next) != NULL);
  971. X  
  972. X  return food_total;
  973. X}
  974. X
  975. X  /* calculate a nation's expenditures */
  976. Xcalc_expend(np)
  977. X     Snation *np;
  978. X{
  979. X  int percent;
  980. X
  981. X  percent = np->charity + np->tech_r_d + np->mag_r_d + np->spy_r_d;
  982. X
  983. X  return (percent*calc_revenue(np)) / 100 + military_maint(np)
  984. X    + non_profit_maint(np);;
  985. X}
  986. X
  987. Xcalc_expend_metal(np)
  988. X     Snation *np;
  989. X{
  990. X  int percent;
  991. X
  992. X  percent = np->tech_r_d_metal;
  993. X
  994. X  return (percent*calc_metal(np)) / 100 + military_maint_metal(np);
  995. X}
  996. X
  997. Xcalc_expend_jewels(np)
  998. X     Snation *np;
  999. X{
  1000. X  int percent;
  1001. X
  1002. X  percent = np->mag_r_d_jewels;
  1003. X
  1004. X  return (percent*calc_jewels(np)) / 100 + military_maint_jewels(np);
  1005. X}
  1006. X
  1007. Xcalc_expend_food(np)
  1008. X     Snation *np;
  1009. X{
  1010. X  int food_eaten;
  1011. X
  1012. X  food_eaten = (int) (get_n_civil(np) * EAT
  1013. X              + SOLD_EAT_FACTOR * get_n_soldiers(np) * EAT);
  1014. X
  1015. X  return food_eaten;
  1016. X}
  1017. X
  1018. X  /* now come a couple of routines that calculate
  1019. X     the amount of a resource (metal, jewels, food)
  1020. X     for a SINGLE sector
  1021. X   */
  1022. Xsector_metal(sp)
  1023. X     Ssector *sp;
  1024. X{
  1025. X  int i, j, n_refineries = 0;
  1026. X  float metal;
  1027. X  Snation *np = &world.nations[sp->owner];
  1028. X
  1029. X    /* see how many active refineries are close by.
  1030. X       a refinery is active if there are the minimum number
  1031. X       of people emplyed in it.
  1032. X     */
  1033. X  for (i = sp->loc.x-1; i <= sp->loc.x+1; ++i) {
  1034. X    for (j = sp->loc.y-1; j <= sp->loc.y+1; ++j) {
  1035. X      if ((world.map[(*wrapx)(i,j)][(*wrapy)(i,j)].designation == D_REFINERY)
  1036. X      &&
  1037. X      (world.map[(*wrapx)(i,j)][(*wrapy)(i,j)].n_people
  1038. X       >= desig_map[D_REFINERY].min_employed)) {
  1039. X    ++n_refineries;
  1040. X      }
  1041. X    }
  1042. X  }
  1043. X    /* add to metal production depending on the
  1044. X       number of refineries and the mining skill
  1045. X     */
  1046. X  metal = n_workers(sp) * (1.0 + np->mine_skill/100.0) * sp->metal;
  1047. X  metal *= (1.0 + REFINERY_FACT*n_refineries);
  1048. X  
  1049. X  return (int)(metal * prod_level(np));
  1050. X}
  1051. X
  1052. Xsector_jewels(sp)
  1053. X     Ssector *sp;
  1054. X{
  1055. X  Snation *np = &world.nations[sp->owner];
  1056. X  float jewels;
  1057. X  
  1058. X  jewels = n_workers(sp) * (1.0 + np->mine_skill/100.0) * sp->jewels;
  1059. X
  1060. X  return (int) (jewels * prod_level(np));
  1061. X}
  1062. X
  1063. Xsector_food(sp)
  1064. X     Ssector *sp;
  1065. X{
  1066. X  Snation *np = &world.nations[sp->owner];
  1067. X  float food;
  1068. X
  1069. X  food = (1.0 + np->farm_skill/100.0) * ((sp->soil+1)/6.0)
  1070. X    * n_workers(sp) * FOOD_PROD;
  1071. X
  1072. X  return (int) (food * prod_level(np));
  1073. X}
  1074. X
  1075. X  /* this returns the TOTAL amount of money spent
  1076. X     to maintain the nation's military forces
  1077. X   */
  1078. Xmilitary_maint(np)
  1079. X     Snation *np;
  1080. X{
  1081. X  Sarmy *ap;
  1082. X  int total = 0;
  1083. X
  1084. X  for (ap = np->armies; ap != NULL; ap = ap->next) {
  1085. X    total += army_maint_money(ap);
  1086. X  }
  1087. X
  1088. X  return total;
  1089. X}
  1090. X  /* this returns the TOTAL amount of metal spent
  1091. X     to maintain the nation's military forces
  1092. X   */
  1093. Xmilitary_maint_metal(np)
  1094. X     Snation *np;
  1095. X{
  1096. X  Sarmy *ap;
  1097. X  int total = 0;
  1098. X
  1099. X  for (ap = np->armies; ap != NULL; ap = ap->next) {
  1100. X    total += ap->n_soldiers * ap->metal_maint;
  1101. X  }
  1102. X
  1103. X  return total;
  1104. X}
  1105. X  /* this returns the TOTAL amount of jewels spent
  1106. X     to maintain the nation's military forces
  1107. X   */
  1108. Xmilitary_maint_jewels(np)
  1109. X     Snation *np;
  1110. X{
  1111. X  Sarmy *ap;
  1112. X  int total = 0;
  1113. X
  1114. X  for (ap = np->armies; ap != NULL; ap = ap->next) {
  1115. X    total += ap->n_soldiers * ap->jewel_maint;
  1116. X  }
  1117. X  return total;
  1118. X}
  1119. X  /* this returns the TOTAL amount of jewels spent
  1120. X     to maintain the nation's military forces
  1121. X   */
  1122. Xmilitary_maint_spell_pts(np)
  1123. X     Snation *np;
  1124. X{
  1125. X  Sarmy *ap;
  1126. X  int total = 0;
  1127. X  struct spirit_type *stype, *get_spirit_type();
  1128. X
  1129. X  for (ap = np->armies; ap != NULL; ap = ap->next) {
  1130. X/*    if (is_spirit(ap)) {
  1131. X      if ((stype = get_spirit_type(&user, ap->type)) == NULL) {
  1132. X    printf(
  1133. X    "\r\nBAD BUG: is_spirit(), but can't get which spirit from type %s\r\n",
  1134. X           ap->type);
  1135. X      } else {
  1136. X    total += (ap->n_soldiers * ap->spell_pts_maint) / stype->size;
  1137. X      }
  1138. X    }
  1139. X*/
  1140. X    if (ap->spell_pts_maint != 0)  {
  1141. X      total += get_spell_pts_maint(ap);
  1142. X    }
  1143. X  }
  1144. X  return total;
  1145. X}
  1146. X
  1147. X  /* this gives the money needed to maintain a given army */
  1148. Xarmy_maint_money(ap)
  1149. X     Sarmy *ap;
  1150. X{
  1151. X  int money_maint = 0, index;
  1152. X  extern struct army_type *army_types;
  1153. X
  1154. X  if (is_army(ap)) {
  1155. X    index = army_type_index(ap);
  1156. X    money_maint = army_types[index].money_maint * ap->n_soldiers;
  1157. X  }
  1158. X    /* in other cases, money maint is zero */
  1159. X
  1160. X  return  money_maint + ARMY_OVERHEAD;
  1161. X}
  1162. X
  1163. X  /* this returns the TOTAL amount of money spent to
  1164. X     maintain the nation's non-profit centers (hospitals  ...)
  1165. X   */
  1166. Xnon_profit_maint(np)
  1167. X     Snation *np;
  1168. X{
  1169. X  struct pt_list *ptlist = np->ptlist; /* nation's list of owned sectors */
  1170. X  Ssector *sp;
  1171. X  int total = 0;
  1172. X
  1173. X  for ( ; ptlist != NULL; ptlist = ptlist->next) {
  1174. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1175. X    switch (sp->designation) {
  1176. X    case D_UNIVERSITY:
  1177. X      total += UNIV_MAINT_COST;
  1178. X      break;
  1179. X    case D_HOSPITAL:
  1180. X      total += HOSPITAL_MAINT_COST;
  1181. X      break;
  1182. X    default:
  1183. X      break;
  1184. X    }
  1185. X  }
  1186. X  return total;
  1187. X}
  1188. X
  1189. Xget_n_students(np)
  1190. X     Snation *np;
  1191. X{
  1192. X  Ssector *sp;
  1193. X  struct pt_list *ptlist = np->ptlist;
  1194. X  int n = 0;
  1195. X
  1196. X  while (ptlist != NULL) {
  1197. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1198. X    if (sp->designation == D_UNIVERSITY) {
  1199. X      n += n_workers(sp);
  1200. X    }
  1201. X    ptlist = ptlist->next;
  1202. X  }
  1203. X  return n;
  1204. X}
  1205. X
  1206. Xget_n_priests (np)
  1207. X     Snation *np;
  1208. X{
  1209. X  Ssector *sp;
  1210. X  struct pt_list *ptlist = np->ptlist;
  1211. X  int n = 0;
  1212. X
  1213. X  while (ptlist != NULL) {
  1214. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1215. X    if (sp->designation == D_TEMPLE) {
  1216. X      n += n_workers(sp);
  1217. X    }
  1218. X    ptlist = ptlist->next;
  1219. X  }
  1220. X  return n;
  1221. X}
  1222. X
  1223. Xget_employed(np)
  1224. X     Snation *np;
  1225. X{
  1226. X  Ssector *sp;
  1227. X  struct pt_list *ptlist = np->ptlist;
  1228. X  int n = 0;
  1229. X
  1230. X  while (ptlist != NULL) {
  1231. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1232. X        /* only people who are employed */
  1233. X    n += n_workers(sp);
  1234. X    ptlist = ptlist->next;
  1235. X  }
  1236. X  return n;
  1237. X}
  1238. X
  1239. Xget_unemployed(np)
  1240. X     Snation *np;
  1241. X{
  1242. X  Ssector *sp;
  1243. X  struct pt_list *ptlist = np->ptlist;
  1244. X  int n = 0;
  1245. X
  1246. X  while (ptlist != NULL) {
  1247. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1248. X        /* only people who are un-employed */
  1249. X    n += max(0, sp->n_people - n_workers(sp));
  1250. X    ptlist = ptlist->next;
  1251. X  }
  1252. X  return n;
  1253. X}
  1254. X
  1255. Xget_emp_met(np)
  1256. X     Snation *np;
  1257. X{
  1258. X  Ssector *sp;
  1259. X  struct pt_list *ptlist = np->ptlist;
  1260. X  int n = 0;
  1261. X
  1262. X  while (ptlist != NULL) {
  1263. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1264. X        /* only people who are employed */
  1265. X    if (sp->designation == D_METAL_MINE) {
  1266. X      n += n_workers(sp);
  1267. X    }
  1268. X    ptlist = ptlist->next;
  1269. X  }
  1270. X  return n;
  1271. X}
  1272. X
  1273. Xget_unemp_met(np)
  1274. X     Snation *np;
  1275. X{
  1276. X  Ssector *sp;
  1277. X  struct pt_list *ptlist = np->ptlist;
  1278. X  int n = 0;
  1279. X
  1280. X  while (ptlist != NULL) {
  1281. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1282. X    if (sp->designation == D_METAL_MINE) {
  1283. X        /* only people who are un-employed */
  1284. X      n += max(0, sp->n_people - n_workers(sp));
  1285. X    }
  1286. X    ptlist = ptlist->next;
  1287. X  }
  1288. X  return n;
  1289. X}
  1290. X
  1291. Xget_emp_jwl(np)
  1292. X     Snation *np;
  1293. X{
  1294. X  Ssector *sp;
  1295. X  struct pt_list *ptlist = np->ptlist;
  1296. X  int n = 0;
  1297. X
  1298. X  while (ptlist != NULL) {
  1299. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1300. X        /* only people who are employed */
  1301. X    if (sp->designation == D_JEWEL_MINE) {
  1302. X      n += n_workers(sp);
  1303. X    }
  1304. X    ptlist = ptlist->next;
  1305. X  }
  1306. X  return n;
  1307. X}
  1308. X
  1309. Xget_unemp_jwl(np)
  1310. X     Snation *np;
  1311. X{
  1312. X  Ssector *sp;
  1313. X  struct pt_list *ptlist = np->ptlist;
  1314. X  int n = 0;
  1315. X
  1316. X  while (ptlist != NULL) {
  1317. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1318. X    if (sp->designation == D_JEWEL_MINE) {
  1319. X        /* only people who are un-employed */
  1320. X      n += max(0, sp->n_people - n_workers(sp));
  1321. X    }
  1322. X    ptlist = ptlist->next;
  1323. X  }
  1324. X  return n;
  1325. X}
  1326. X
  1327. Xget_emp_farm(np)
  1328. X     Snation *np;
  1329. X{
  1330. X  Ssector *sp;
  1331. X  struct pt_list *ptlist = np->ptlist;
  1332. X  int n = 0;
  1333. X
  1334. X  while (ptlist != NULL) {
  1335. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1336. X        /* only people who are employed */
  1337. X    if (sp->designation == D_FARM) {
  1338. X      n += n_workers(sp);
  1339. X    }
  1340. X    ptlist = ptlist->next;
  1341. X  }
  1342. X  return n;
  1343. X}
  1344. X
  1345. Xget_unemp_farm(np)
  1346. X     Snation *np;
  1347. X{
  1348. X  Ssector *sp;
  1349. X  struct pt_list *ptlist = np->ptlist;
  1350. X  int n = 0;
  1351. X
  1352. X  while (ptlist != NULL) {
  1353. X    sp = &world.map[ptlist->pt.x][ptlist->pt.y];
  1354. X    if (sp->designation == D_FARM) {
  1355. X        /* only people who are un-employed */
  1356. X      n += max(0, sp->n_people - n_workers(sp));
  1357. X    }
  1358. X    ptlist = ptlist->next;
  1359. X  }
  1360. X  return n;
  1361. X}
  1362. X
  1363. X  /* the service sector!! */
  1364. Xget_emp_serv(np)
  1365. X     Snation *np;
  1366. X{
  1367. X  return get_employed(np)-get_emp_met(np)-get_emp_jwl(np)-get_emp_farm(np);
  1368. X}
  1369. X
  1370. Xget_unemp_serv(np)
  1371. X     Snation *np;
  1372. X{
  1373. X  return get_unemployed(np)
  1374. X    - get_unemp_met(np) - get_unemp_jwl(np) - get_unemp_farm(np);
  1375. X}
  1376. X
  1377. X  /* tax revenue from the service sector */
  1378. Xcalc_serv_revenue(np)
  1379. X     Snation *np;
  1380. X{
  1381. X  Ssector *sp;
  1382. X  struct pt_list *points;
  1383. X  int income = 0;
  1384. X  int taxes = np->taxes;
  1385. X    /* first thing: run through the list of that nation's sectors
  1386. X       and see what income might come from the various sectors
  1387. X     */
  1388. X  if ((points = np->ptlist) == NULL) {
  1389. X    return 0;            /* nation has no sectors!! */
  1390. X  }
  1391. X  do {
  1392. X    sp = &(world.map[points->pt.x][points->pt.y]);
  1393. X    switch (sp->designation) {
  1394. X    case D_METAL_MINE:
  1395. X    case D_JEWEL_MINE:
  1396. X    case D_FARM:
  1397. X      break;
  1398. X    default:            /* other things (service sector) */
  1399. X      income += (taxes * prod_level(np)*n_workers(sp)*
  1400. X                            desig_map[sp->designation].revenue)/100;
  1401. X      break;
  1402. X    }
  1403. X  } while ((points = points->next) != NULL);
  1404. X  return income;
  1405. X}
  1406. X
  1407. X  /* average quantities of all nations in the world */
  1408. Xget_avg_money(wp)
  1409. X      Sworld *wp;
  1410. X{
  1411. X  Snation *np;
  1412. X  int i, n_nations = 0, total = 0;
  1413. X
  1414. X  for (i = 1; i < wp->n_nations; ++i) {
  1415. X    np = &wp->nations[i];
  1416. X    if (is_active_ntn(np)) {
  1417. X      ++n_nations;
  1418. X      total += np->money;
  1419. X    }
  1420. X  }
  1421. X  return n_nations ? total/n_nations : 0;
  1422. X}
  1423. X
  1424. Xget_avg_metal(wp)
  1425. X      Sworld *wp;
  1426. X{
  1427. X  Snation *np;
  1428. X  int i, n_nations = 0, total = 0;
  1429. X
  1430. X  for (i = 1; i < wp->n_nations; ++i) {
  1431. X    np = &wp->nations[i];
  1432. X    if (is_active_ntn(np)) {
  1433. X      ++n_nations;
  1434. X      total += np->metal;
  1435. X    }
  1436. X  }
  1437. X  return n_nations ? total/n_nations : 0;
  1438. X}
  1439. X
  1440. Xget_avg_jewels(wp)
  1441. X      Sworld *wp;
  1442. X{
  1443. X  Snation *np;
  1444. X  int i, n_nations = 0, total = 0;
  1445. X
  1446. X  for (i = 1; i < wp->n_nations; ++i) {
  1447. X    np = &wp->nations[i];
  1448. X    if (is_active_ntn(np)) {
  1449. X      ++n_nations;
  1450. X      total += np->jewels;
  1451. X    }
  1452. X  }
  1453. X  return n_nations ? total/n_nations : 0;
  1454. X}
  1455. X
  1456. Xget_avg_food(wp)
  1457. X      Sworld *wp;
  1458. X{
  1459. X  Snation *np;
  1460. X  int i, n_nations = 0, total = 0;
  1461. X
  1462. X  for (i = 1; i < wp->n_nations; ++i) {
  1463. X    np = &wp->nations[i];
  1464. X    if (is_active_ntn(np)) {
  1465. X      ++n_nations;
  1466. X      total += np->food;
  1467. X    }
  1468. X  }
  1469. X  return n_nations ? total/n_nations : 0;
  1470. X}
  1471. X
  1472. Xget_avg_civil(wp)
  1473. X      Sworld *wp;
  1474. X{
  1475. X  Snation *np;
  1476. X  int i, n_nations = 0, total = 0;
  1477. X
  1478. X  for (i = 1; i < wp->n_nations; ++i) {
  1479. X    np = &wp->nations[i];
  1480. X    if (is_active_ntn(np)) {
  1481. X      ++n_nations;
  1482. X      total += get_n_civil(np);
  1483. X    }
  1484. X  }
  1485. X  return n_nations ? total/n_nations : 0;
  1486. X}
  1487. X
  1488. Xget_avg_soldiers(wp)
  1489. X      Sworld *wp;
  1490. X{
  1491. X  Snation *np;
  1492. X  int i, n_nations = 0, total = 0;
  1493. X
  1494. X  for (i = 1; i < wp->n_nations; ++i) {
  1495. X    np = &wp->nations[i];
  1496. X    if (is_active_ntn(np)) {
  1497. X      ++n_nations;
  1498. X      total += get_n_soldiers(np);
  1499. X    }
  1500. X  }
  1501. X  return n_nations ? total/n_nations : 0;
  1502. X}
  1503. X
  1504. X
  1505. Xget_avg_sectors(wp)
  1506. X     Sworld *wp;
  1507. X{
  1508. X  Snation *np;
  1509. X  int i, n_nations = 0, total = 0;
  1510. X
  1511. X  for (i=1; i < wp->n_nations; i++) {
  1512. X    np = &wp->nations[i];
  1513. X    if (is_active_ntn(np)) {
  1514. X      ++n_nations;
  1515. X      total += np->n_sects;
  1516. X    }
  1517. X  }
  1518. X  return n_nations ? total/n_nations : 0;
  1519. X}
  1520. X
  1521. X
  1522. Xget_per_occu_land(wp)
  1523. X     Sworld *wp;
  1524. X{
  1525. X  int x, y, land = 0, n_occu = 0;
  1526. X
  1527. X  for (y = 0; y < wp->ymax; y++)
  1528. X    for (x = 0; x < wp->xmax; x++)
  1529. X      if (wp->map[x][y].altitude >= SEA_LEVEL) {
  1530. X    land++;
  1531. X    if (wp->map[x][y].owner != 0)
  1532. X      n_occu++;
  1533. X      }
  1534. X  return (n_occu*100)/land;
  1535. X}
  1536. X
  1537. Xget_per_occu_water(wp)
  1538. X     Sworld *wp;
  1539. X{
  1540. X  int x, y, water = 0, n_occu = 0;
  1541. X
  1542. X  for (y = 0; y < wp->ymax; y++)
  1543. X    for (x = 0; x < wp->xmax; x++)
  1544. X      if (wp->map[x][y].altitude < SEA_LEVEL) {
  1545. X    water++;
  1546. X    if (wp->map[x][y].owner != 0)
  1547. X      n_occu++;
  1548. X      }
  1549. X  if (water != 0) {
  1550. X    return (n_occu*100)/water;
  1551. X  } else {
  1552. X    return 0;
  1553. X  }
  1554. X}
  1555. X
  1556. X
  1557. X  /* return the number of active nations (including game master) */
  1558. Xget_n_act_ntn(wp)
  1559. X     Sworld *wp;
  1560. X{
  1561. X  int i, total = 0;
  1562. X
  1563. X  for (i = 0; i < wp->n_nations; ++i) {
  1564. X    if (is_active_ntn(&wp->nations[i])) {
  1565. X      ++total;
  1566. X    }
  1567. X  }
  1568. X  return total;
  1569. X}
  1570. X
  1571. Xn_workers(sp)
  1572. X     Ssector *sp;
  1573. X{
  1574. X  double race_factor;
  1575. X
  1576. X  race_factor = sqrt(world.nations[sp->owner].race.repro/10.0);
  1577. X return min(sp->n_people,
  1578. X        (int) (desig_map[sp->designation].max_employed*race_factor));
  1579. X}
  1580. X
  1581. Xint emp_desire(np, x, y)    /* desireability for employment */
  1582. X     Snation *np;
  1583. X     int x, y;
  1584. X{
  1585. X  int unemployed;
  1586. X  Ssector *sp = &world.map[x][y];
  1587. X
  1588. X/*  unemployed = min(0, n_workers(sp) - sp->n_people); */
  1589. X    /* what we return is the percentage of people employed */
  1590. X  return sp->n_people ? (100*n_workers(sp))/sp->n_people : 100;
  1591. X}
  1592. END_OF_FILE
  1593. if test 18590 -ne `wc -c <'economy.c'`; then
  1594.     echo shar: \"'economy.c'\" unpacked with wrong size!
  1595. fi
  1596. # end of 'economy.c'
  1597. fi
  1598. if test -f 'npc.c' -a "${1}" != "-c" ; then 
  1599.   echo shar: Will not clobber existing file \"'npc.c'\"
  1600. else
  1601. echo shar: Extracting \"'npc.c'\" \(19296 characters\)
  1602. sed "s/^X//" >'npc.c' <<'END_OF_FILE'
  1603. X   /* npc.c -- modules involved in NPC movemaking */
  1604. X
  1605. X/*
  1606. X * Copyright (C) 1990 Free Software Foundation, Inc.
  1607. X * Written by the dominion project.
  1608. X *
  1609. X * This file is part of dominion.
  1610. X *
  1611. X * dominion is free software; you can redistribute it and/or
  1612. X * modify it under the terms of the GNU General Public License as published
  1613. X * by the Free Software Foundation; either version 1, or (at your option)
  1614. X * any later version.
  1615. X *
  1616. X * This software is distributed in the hope that it will be useful,
  1617. X * but WITHOUT ANY WARRANTY; without even the implied warranty of
  1618. X * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1619. X * GNU General Public License for more details.
  1620. X *
  1621. X * You should have received a copy of the GNU General Public License
  1622. X * along with this software; see the file COPYING.  If not, write to
  1623. X * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  1624. X */
  1625. X#ifdef SYSV
  1626. X# include <string.h>
  1627. X#else
  1628. X# include <strings.h>
  1629. X#endif /* SYSV */
  1630. X
  1631. X#include "dominion.h"
  1632. X#include "misc.h"
  1633. X#include "army.h"
  1634. X#include <math.h>
  1635. X#include <curses.h>
  1636. X#include <stdio.h>
  1637. X#include <ctype.h>
  1638. X#include <signal.h>
  1639. X
  1640. Xextern Sworld world;
  1641. Xextern Suser user;
  1642. Xextern struct s_desig_map desig_map[];
  1643. Xextern int (*wrapx)(), (*wrapy)();
  1644. Xextern Sdiplo **allocate_diplo();
  1645. Xextern int debug;
  1646. Xextern struct army_type *army_types;
  1647. Xextern struct spirit_type *spirit_types;
  1648. X
  1649. Xstruct desire {
  1650. X  int base,final;
  1651. X};
  1652. X
  1653. Xfloat npc_food_need,npc_metal_need,npc_jewel_need,npc_money_need;
  1654. Xint opt_army_size,atwar,npc_specific;
  1655. X
  1656. X/*-----------------------------npc_moves()------------------------------------
  1657. X    This function makes the moves for an npc
  1658. X----------------------------------------------------------------------------*/
  1659. Xnpc_moves(np)
  1660. X     Snation *np;
  1661. X{
  1662. X  int i;
  1663. X  struct desire **des_array;
  1664. X
  1665. X  des_array = (struct desire **) malloc(world.xmax*sizeof(struct desire*));
  1666. X  for (i = 0; i < world.xmax; ++i)
  1667. X    des_array[i] = (struct desire *) malloc(world.ymax*sizeof(struct desire));
  1668. X  if (debug)
  1669. X    printf("doing init\n");
  1670. X  init_npc(np);
  1671. X/*  npc_needs(np); */
  1672. X  do_npc_draft(np);
  1673. X  if (debug)
  1674. X    printf("doing merge\n");
  1675. X  do_npc_merge(np);
  1676. X  if (debug)
  1677. X    printf("doing split\n");
  1678. X  do_npc_split(np);
  1679. X  if (debug)
  1680. X    printf("doing summon\n");
  1681. X  do_npc_summon(np);
  1682. X  if (debug)
  1683. X    printf("doing armies\n");
  1684. X  do_npc_armies(np,des_array);
  1685. X  if (debug)
  1686. X    printf("doing redesig\n");
  1687. X  do_npc_redesig(np);
  1688. X
  1689. X  for (i = 0; i < world.xmax; i++)    /* free desire array */
  1690. X    free(des_array[i]);
  1691. X  free(des_array);
  1692. X
  1693. X  for (i = 0; i < world.xmax; ++i) {    /* free visible sectors array */
  1694. X    free(user.visible_sectors[i]);
  1695. X  }
  1696. X  free(user.visible_sectors);
  1697. X
  1698. X  free_diplo(user.diplo_matrix, world.n_nations);
  1699. X}
  1700. X
  1701. X/*-------------------------------init_npc()----------------------------------
  1702. X    This is basically the function init_user, copied from user.c.  There
  1703. Xare some things that init_user does that this does not do.
  1704. X    Also, this function sets global varibles like needs and race-specific
  1705. Xarmy types.
  1706. X---------------------------------------------------------------------------*/
  1707. Xinit_npc(np)
  1708. X     Snation *np;
  1709. X{
  1710. X  int c,i,d;
  1711. X  FILE *fp, *fopen();
  1712. X  char line[EXECLEN];
  1713. X
  1714. X    /* find out which army types are available to the user */
  1715. X  user.avail_armies = NULL;
  1716. X  get_avail_armies(&user, np->tech_skill);
  1717. X
  1718. X    /*------ set npc_specific to be 1 + the index of the race 
  1719. X         specific army type, if any.  ---------------*/
  1720. X  npc_specific = 0;
  1721. X  if ((fp = fopen(RACES_FILE, "r")) != NULL) {
  1722. X    while (1) {
  1723. X      if (fgets(line, EXECLEN, fp) == NULL)
  1724. X        break;
  1725. X      if (strncmp(line, np->race.name, strlen(np->race.name)) == 0
  1726. X      && strncmp(line+strlen(np->race.name), "_armies:",
  1727. X             strlen("_armies:")) == 0) {
  1728. X        if (line[strlen(line)-1] == '\n') {
  1729. X          line[strlen(line)-1] = '\0';
  1730. X    }
  1731. X    npc_specific = army_type_index(strchr(line, ':')+1) + 1;
  1732. X      }
  1733. X    }
  1734. X    fclose(fp);
  1735. X  }
  1736. X
  1737. X  user.spirit_list = NULL;
  1738. X  get_spirits(&user, np->mag_skill);
  1739. X    /* now set fields for the ustruct */
  1740. X  user.underwater = 0;        /* user is not underwater at start */
  1741. X  if (np->race.pref_alt < 0) {
  1742. X    user.underwater = 1;    /* merfolk or whatever */
  1743. X  }
  1744. X    /* load user's diplomacy statuses, for fast access later;
  1745. X       also remember the initial values, so users cannot change
  1746. X       their status by more than one step at a time.
  1747. X     */
  1748. X  user.diplo_matrix = allocate_diplo(world.n_nations);
  1749. X/*  user.init_diplo = allocate_diplo(world.n_nations); */
  1750. X  read_in_diplo(user.diplo_matrix, world.n_nations);
  1751. X/*  read_initial_diplo(user.init_diplo, world.n_nations); */
  1752. X
  1753. X/* now do diplomacy and set the atwar variable to 1 if npc is at war */
  1754. X  do_npc_diplo(np);
  1755. X
  1756. X    /* load hanging spells, and put them in this user's list */
  1757. X  load_h_spells(&user);
  1758. X    /* calculate visibility matrix for this user.
  1759. X       this might depend on spells, so do it after
  1760. X       loading spells.
  1761. X     */
  1762. X  user.visible_sectors = (int **) malloc(world.xmax*sizeof(int *));
  1763. X  for (i = 0; i < world.xmax; ++i) {
  1764. X    user.visible_sectors[i] = (int *) malloc(world.ymax*sizeof(int));
  1765. X  }
  1766. X  find_visible_sectors(user.visible_sectors);
  1767. X
  1768. X
  1769. X/*  npc_money_need =(float)calc_expend(np)/((float)calc_revenue(np)+1.0);
  1770. X  npc_metal_need =(float)calc_expend_metal(np)/((float)calc_metal(np)+1.0)+.3;
  1771. Xnpc_jewel_need =(float)calc_expend_jewels(np)/((float)calc_jewels(np)+1.0)+.3;*/
  1772. X
  1773. X  npc_metal_need = atwar ? 1.3:1.0; /* for now */
  1774. X  npc_jewel_need = atwar ? 1.3:1.0; /* for now */
  1775. X  npc_food_need = (float)calc_expend_food(np)/((float)calc_food(np)+1.0);
  1776. X  if(atwar){
  1777. X    opt_army_size = get_n_soldiers(np)*2/np->n_sects;
  1778. X    opt_army_size=max(OCCUPYING_SOLDIERS*3/2,opt_army_size);
  1779. X  }
  1780. X  else{
  1781. X    opt_army_size = OCCUPYING_SOLDIERS;
  1782. X  }
  1783. X
  1784. X  if(debug)
  1785. X    printf("opt size = %d.\n",opt_army_size);
  1786. X
  1787. X  if(atwar){
  1788. X    np->taxes = 20;
  1789. X    np->tech_r_d_metal = 0;
  1790. X    if (next_thon_jewels(np) < MAGE_JEWELS_MAINT) {
  1791. X      np->mag_r_d_jewels = 0;
  1792. X    } else {
  1793. X      if (calc_jewels(np) * 2 > np->jewels) {
  1794. X    np->mag_r_d_jewels = np->jewels * 50 / calc_jewels(np);
  1795. X      } else {
  1796. X    np->mag_r_d_jewels = 100;
  1797. X      }
  1798. X    }
  1799. X    np->mag_r_d = 15;
  1800. X    np->tech_r_d = 15;
  1801. X  } else {
  1802. X    np->taxes = 10;
  1803. X    np->tech_r_d_metal = 30;
  1804. X    np->mag_r_d_jewels = 0;
  1805. X    np->mag_r_d = 30;
  1806. X    np->tech_r_d = 30;
  1807. X  }
  1808. X}
  1809. X
  1810. X/*---------------------------do_npc_draft()-----------------------------------
  1811. X    Draft armies.  This routine has been altered to take technology
  1812. Xlevel into account.
  1813. X----------------------------------------------------------------------------*/
  1814. Xdo_npc_draft(np)
  1815. X     Snation *np;
  1816. X{
  1817. X  Sarmy ap, make_army();
  1818. X  Ssector *sp;
  1819. X  Savail_army *can_draft;
  1820. X  struct army_type this_atype;
  1821. X  int max_sold,cur_sold,ngood,good_armies[MAX_TYPES],i,drafted;
  1822. X  int cut1,cut2,start,stop,step;
  1823. X  char type[NAMELEN];
  1824. X
  1825. X    /*-------- Initialize variables for npc drafting -------*/
  1826. X  if(atwar) max_sold = get_n_civil(np)*np->npc_agg/200;
  1827. X  else max_sold = get_n_civil(np)*np->npc_agg/300;
  1828. X
  1829. X  cut1 = max_sold*(np->npc_agg/2)/100;        /* -30 bonus cutoff */
  1830. X  cut2 = max_sold*(np->npc_agg/2 + 25)/100;    /* -1 to -29 bonus cutoff */
  1831. X  cur_sold = get_n_soldiers(np);
  1832. X  ngood = get_good_types(good_armies,cur_sold,cut1,cut2);
  1833. X
  1834. X    /*--- now draft from the cheap armies if we are desperate ------*/
  1835. X  if(cur_sold < cut2 || (cur_sold - cut2 < max_sold - cur_sold)){
  1836. X    start = 0;
  1837. X    stop = ngood;
  1838. X    step = 1;
  1839. X  } else{
  1840. X    start = ngood-1;
  1841. X    stop = -1;
  1842. X    step = -1;
  1843. X  }
  1844. X    /*--- get cut 2 out of the way if we have already passed it ---*/
  1845. X  if(cur_sold > cut2) cut2 = 2*max_sold;
  1846. X
  1847. X  if(ngood == 0)    /* no armies we want to draft */
  1848. X    return;
  1849. X
  1850. X        /*------ Now draft armies ---------*/
  1851. X  while(cur_sold < max_sold){
  1852. X    drafted = 0;
  1853. X    for(i = start;(i != stop) && (cur_sold < max_sold);i += step){
  1854. X      this_atype = army_types[good_armies[i]];
  1855. X      strcpy(type,this_atype.type);
  1856. X      sp = &world.map[np->capital.x][np->capital.y];
  1857. X      ap = make_army(type,type, opt_army_size, A_DEFEND, np->id, sp->loc);
  1858. X      ap.id = free_army_id(np);
  1859. X      ap.next = NULL;
  1860. X      if (ap.n_soldiers > sp->n_people || army_cost(&ap) > np->money ||
  1861. X            army_cost_metal(&ap) > np->metal) {
  1862. X        break;
  1863. X      }
  1864. X      ++np->n_armies;
  1865. X      cur_sold += opt_army_size;
  1866. X      drafted = 1;
  1867. X      if (debug)
  1868. X        printf("npc drafted %s\n",type);
  1869. X
  1870. X      if (np->armies == NULL) {
  1871. X        np->armies = (Sarmy *) malloc(sizeof(Sarmy));
  1872. X        *(np->armies) = ap;
  1873. X        np->armies->next = NULL;
  1874. X      } else {
  1875. X        insert_army_nation(np, &ap, -1);
  1876. X      }
  1877. X      insert_army_sector(sp, &ap);
  1878. X      sp->n_people -= ap.n_soldiers;
  1879. X      np->money -= army_cost(&ap);
  1880. X      np->metal -= army_cost_metal(&ap);
  1881. X    }
  1882. X  if(cur_sold > cut2){            /* need to recalc good types */
  1883. X    cut1 = max_sold*(np->npc_agg/2)/100;    /* -30 bonus cutoff */
  1884. X    cut2 = max_sold*(np->npc_agg/2 + 25)/100;    /* -1 to -29 bonus cutoff */
  1885. X    ngood = get_good_types(good_armies,cur_sold,cut1,cut2);
  1886. X    if(cur_sold > cut1) cut1 = 2*max_sold;
  1887. X    if(cur_sold > cut2) cut2 = 2*max_sold;
  1888. X  }
  1889. X  if(!drafted || !ngood)    /* No armies can be drafted anymore */
  1890. X    return;
  1891. X  }
  1892. X}
  1893. X
  1894. X/*----------------------------do_npc_summon()--------------------------------
  1895. X    Have the npc draft a mage, if necessary, and summon spirits.
  1896. XBasically, find the net spell points and draft the biggest spirit you can.
  1897. XDon't draft caravan spirits.
  1898. X---------------------------------------------------------------------------*/
  1899. Xdo_npc_summon(np)
  1900. XSnation *np;
  1901. X{
  1902. X  int have_mage = 0,sindex,net_points,badflags;
  1903. X  Sarmy army,make_army();
  1904. X  struct spirit_type this_stype;
  1905. X  Ssector *sp;
  1906. X  Sspirit *sptr,*tmp_sptr;
  1907. X
  1908. X  if(!atwar || np->spell_pts < 2)
  1909. X    return;
  1910. X
  1911. X  badflags = AF_INVERSE_ALT & AF_CARGO;
  1912. X  if (user.underwater)
  1913. X    badflags |= AF_LAND;
  1914. X  else
  1915. X    badflags |= AF_WATER;
  1916. X
  1917. X  sp = &world.map[np->capital.x][np->capital.y];
  1918. X
  1919. X  have_mage = get_first_mage(np);
  1920. X  if (!have_mage) {
  1921. X    if (np->jewels >= INITIATION_JEWELS && next_thon_jewels(np) > 6000)
  1922. X      init_npc_mage(np,sp);
  1923. X    else
  1924. X      return;            /* no mage, can't summon */
  1925. X  }
  1926. X  
  1927. X  net_points = new_spell_pts(np) - military_maint_spell_pts(np);
  1928. X  while(net_points){        /* while we can still summon */
  1929. X    tmp_sptr = 0;
  1930. X    for(sptr = user.spirit_list ; sptr ; sptr = sptr->next){
  1931. X      if (np->spell_pts < sptr->cost) 
  1932. X    break;
  1933. X      tmp_sptr = sptr;
  1934. X    }
  1935. X    if (!tmp_sptr)
  1936. X      break;
  1937. X
  1938. X    sindex = spirit_type_index(tmp_sptr->type);
  1939. X    this_stype = spirit_types[sindex];
  1940. X    while ((this_stype.flags & badflags) && sptr != user.spirit_list){
  1941. X      for (sptr = user.spirit_list ;sptr->next != tmp_sptr ;sptr = sptr->next);
  1942. X      sindex = spirit_type_index(sptr->type);
  1943. X      this_stype = spirit_types[sindex];
  1944. X      tmp_sptr = sptr;
  1945. X      }
  1946. X
  1947. X    if (this_stype.flags & badflags)
  1948. X      break;
  1949. X
  1950. X    if (debug)
  1951. X      printf("npc summons %s\n",tmp_sptr->type);
  1952. X
  1953. X    army = make_army(this_stype.type, this_stype.type, this_stype.size,
  1954. X             A_DEFEND, np->id, sp->loc);
  1955. X    army.id = free_army_id(np);
  1956. X    army.next = NULL;
  1957. X    army.flags = this_stype.flags;
  1958. X
  1959. X  /*============ now insert it into the list ============*/
  1960. X
  1961. X    ++np->n_armies;
  1962. X    if (np->armies == NULL) {         /* special case:  empty list */
  1963. X      np->armies = (Sarmy *) malloc(sizeof(Sarmy));
  1964. X      *(np->armies) = army;
  1965. X      np->armies->next = NULL;
  1966. X    } else {
  1967. X      insert_army_nation(np, &army, -1);
  1968. X    }
  1969. X    insert_army_sector(sp, &army);
  1970. X    np->spell_pts -= spirit_types[sindex].spell_pts_draft;
  1971. X    net_points = new_spell_pts(np) - military_maint_spell_pts(np);
  1972. X  }
  1973. X}
  1974. X
  1975. X/*-----------------------------do_npc_merge()--------------------------------
  1976. X    merge npc armies together.  If an army has less than an optimal
  1977. Xnumber of units, check for other armies of the npc that are reachable and
  1978. Xwithin NPC_VIEW sectors.  Move to the one that will give the greatest
  1979. Xmovement left and merge.  Prefer to merge with other armies that have
  1980. Xless than the optimal number.
  1981. X---------------------------------------------------------------------------*/
  1982. Xdo_npc_merge(np)
  1983. X  Snation *np;
  1984. X{
  1985. X  int i,tx,ty,x,y,finalmv;
  1986. X  Pt finalpos;
  1987. X  Sarmy *bestarmy,*ap,*tmpap,*get_army();
  1988. X  struct armyid *alist;
  1989. X  struct argument args[N_EXEC_ARGS];
  1990. X  struct tmp_map {
  1991. X    int mvcost,mvleft;
  1992. X  } legal_moves[NPC_SIDE][NPC_SIDE];
  1993. X
  1994. X  for(i = 0;i < NPC_SIDE; i++){            /* fill in border of legal mv */
  1995. X    legal_moves[0][i].mvleft = -2;
  1996. X    legal_moves[NPC_SIDE-1][i].mvleft = -2;
  1997. X    legal_moves[i][0].mvleft = -2;
  1998. X    legal_moves[i][NPC_SIDE-1].mvleft = -2;
  1999. X  }
  2000. X
  2001. X  for(ap = np->armies ;ap ;ap = ap->next){    /* for all npcs armies */
  2002. X    if(ap->n_soldiers >= max(opt_army_size*2/3,OCCUPYING_SOLDIERS))
  2003. X      continue;                    /* skip loop if army ok. */
  2004. X    if(is_mage(ap))
  2005. X      continue;
  2006. X    bestarmy = 0;
  2007. X    check_moves(np,ap,legal_moves);        /* new function */
  2008. X
  2009. X    /* now check for armies belonging to this player that can be moved to */
  2010. X
  2011. X /*   printf("%d needs to merge.\n",ap->id); */
  2012. X    for (x = ap->pos.x-NPC_VIEW; x <= ap->pos.x+NPC_VIEW; x++) {
  2013. X      for (y = ap->pos.y-NPC_VIEW; y <= ap->pos.y+NPC_VIEW; y++) {
  2014. X    alist = world.map[(*wrapx)(x,y)][(*wrapy)(x,y)].alist;
  2015. X    while(alist){
  2016. X      if(alist->owner == np->id){        /* if same owner */
  2017. X        tx = x - ap->pos.x + NPC_VIEW + 1;
  2018. X        ty = y - ap->pos.y + NPC_VIEW + 1;    /* coords in legal_move */
  2019. X        if(legal_moves[tx][ty].mvleft >= 0){
  2020. X          tmpap = get_army(np, alist->id);
  2021. X        /* printf("looking at army %d\n",tmpap->id); */
  2022. X          if(tmp_army_better(ap,tmpap,bestarmy) && tmpap != ap){
  2023. X        /* printf("best is %d\n",tmpap->id); */
  2024. X            bestarmy = tmpap;
  2025. X        finalpos.x = x;
  2026. X        finalpos.y = y;
  2027. X        finalmv = legal_moves[tx][ty].mvleft;
  2028. X              }
  2029. X        }
  2030. X      }
  2031. X      alist = alist->next;
  2032. X    }    /* while alist */
  2033. X      }        /* for y */
  2034. X    }        /* for x */
  2035. X
  2036. X  /* now move the army to the correct location and merge.  */
  2037. X    if(bestarmy){
  2038. X      if (debug)
  2039. X        printf("npc army %d merges with %d.\n",ap->id,bestarmy->id);
  2040. X      args[1].data.num = ap->id;
  2041. X      alist = world.map[(*wrapx)(x,y)][(*wrapy)(x,y)].alist;
  2042. X      args[2].data.num = (*wrapx)(finalpos.x,finalpos.y);
  2043. X      args[3].data.num = (*wrapy)(finalpos.x,finalpos.y);
  2044. X      args[4].data.num = finalmv;
  2045. X      cmd_amove(np,args);        /* move army to new location */
  2046. X      args[1].data.num = ap->id;
  2047. X      args[2].data.num = bestarmy->id;
  2048. X      cmd_amerge(np,args);
  2049. X    }
  2050. X  }        /* for ap */
  2051. X}
  2052. X
  2053. X/*--------------------------------do_npc_split()------------------------------
  2054. X    Split armies that have grown too large into manageable armies
  2055. X----------------------------------------------------------------------------*/
  2056. Xdo_npc_split(np)
  2057. XSnation *np;
  2058. X{
  2059. X  Sarmy *ap;
  2060. X  struct argument args[N_EXEC_ARGS];
  2061. X
  2062. X  for(ap = np->armies ;ap ;ap = ap->next){    /* for all npcs armies */
  2063. X    if(ap->n_soldiers < opt_army_size*2 || is_spirit(ap))
  2064. X      continue;                    /* skip loop if army ok. */
  2065. X    while(ap->n_soldiers >= opt_army_size*2){
  2066. X      if (debug)
  2067. X    printf ("npc splits %d troops from army %d\n",opt_army_size,ap->id);
  2068. X      args[1].data.num = ap->id;
  2069. X      args[2].data.num = opt_army_size;
  2070. X      cmd_asplit(np,args);
  2071. X    }
  2072. X  }
  2073. X}
  2074. X
  2075. X/*-------------------------------do_npc_armies()------------------------------
  2076. X    This routine moves npc armies to desirable sectors.  Des_array is
  2077. Xan array containing the desirability of each sector on the map.  legal_moves
  2078. Xis an array containing the sectors that the army can see, with the sectors
  2079. Xthat the army can move to marked with the number of movepoints the army will
  2080. Xhave left at that point.  The function looks for the most desirable sectors
  2081. Xthat the army can move to and puts them in the highlist array.  It then
  2082. Xrandomly picks a point from this array and moves the army to it.
  2083. X----------------------------------------------------------------------------*/
  2084. Xdo_npc_armies(np,des_array)
  2085. X  Snation *np;
  2086. X  struct desire **des_array;
  2087. X{
  2088. X  int i,x,y,tx,ty,des_here,high_des,nhigh;
  2089. X  struct pt highlist[NPC_SIDE*NPC_SIDE];
  2090. X  Sarmy *ap;
  2091. X  struct argument args[N_EXEC_ARGS];
  2092. X  struct tmp_map {
  2093. X    int mvcost,mvleft;
  2094. X  } legal_moves[NPC_SIDE][NPC_SIDE],final;
  2095. X
  2096. X  find_desire(np,des_array);            /* fill desireability array */
  2097. X  for(i = 0;i < NPC_SIDE; i++){            /* fill in border of legal mv */
  2098. X    legal_moves[0][i].mvleft = -2;
  2099. X    legal_moves[NPC_SIDE-1][i].mvleft = -2;
  2100. X    legal_moves[i][0].mvleft = -2;
  2101. X    legal_moves[i][NPC_SIDE-1].mvleft = -2;
  2102. X  }
  2103. X
  2104. X  /* Have NPC nation take sectors */
  2105. X  
  2106. X  if (np->n_armies == 0) {    /* If there are no armies, forget it */
  2107. X    return;
  2108. X  }
  2109. X  for (ap = np->armies; ap; ap = ap->next) {
  2110. X    if (debug)
  2111. X      printf("%d\n", ap->id);
  2112. X    if(is_mage(ap) && ap->n_soldiers == 1)
  2113. X      continue;
  2114. X    check_moves(np,ap,legal_moves);        /* new function */
  2115. X    high_des = -1;
  2116. X    for (x = ap->pos.x-NPC_VIEW; x <= ap->pos.x+NPC_VIEW; x++) {
  2117. X      for (y = ap->pos.y-NPC_VIEW; y <= ap->pos.y+NPC_VIEW; y++) {
  2118. X
  2119. X/* Now check if it's the most desireable sector so far */
  2120. X/* and if it can be moved to. */
  2121. X
  2122. X        if (good_altitude(&world.map[(*wrapx)(x,y)][(*wrapy)(x,y)],np)) {
  2123. X      des_here = des_array[(*wrapx)(x,y)][(*wrapy)(x,y)].final;
  2124. X      tx = x - ap->pos.x + NPC_VIEW + 1;
  2125. X      ty = y - ap->pos.y + NPC_VIEW + 1;
  2126. X      if (legal_moves[tx][ty].mvleft >= 0){
  2127. X        if(des_here > high_des) {
  2128. X          nhigh = 1;
  2129. X          highlist[0].x = x;
  2130. X          highlist[0].y = y;
  2131. X          high_des = des_here;
  2132. X        }
  2133. X        if(des_here == high_des) {
  2134. X          highlist[nhigh].x = x;
  2135. X          highlist[nhigh++].y = y;
  2136. X        }
  2137. X          }
  2138. X    }
  2139. X      }        /* end y loop */
  2140. X    }        /* enc x loop */
  2141. X
  2142. X    /* Move army to one of the desireable sectors and change status to OCCUPY */
  2143. X    /* Change the desireability of the sector so not all the armies go there */
  2144. X
  2145. X    i = RND() % nhigh;
  2146. X    tx = highlist[i].x - ap->pos.x + NPC_VIEW + 1;
  2147. X    ty = highlist[i].y - ap->pos.y + NPC_VIEW + 1;
  2148. X    x = (*wrapx)(highlist[i].x,highlist[i].y);
  2149. X    y = (*wrapy)(highlist[i].x,highlist[i].y);
  2150. X    args[1].data.num = ap->id;
  2151. X    args[2].data.num = x;
  2152. X    args[3].data.num = y;
  2153. X    args[4].data.num = legal_moves[tx][ty].mvleft;
  2154. X    cmd_amove(np,args);        /* move army to new location */
  2155. X    if(good_altitude(&world.map[x][y],np) || is_water(ap)){
  2156. X      args[2].data.num = A_OCCUPY;
  2157. X      cmd_astat(np,args);
  2158. X    }
  2159. X    des_array[x][y].final = des_array[x][y].final * opt_army_size /
  2160. X            (opt_army_size+ap->n_soldiers);
  2161. X  }
  2162. X}
  2163. X
  2164. X/*------------------------------do_npc_redesig()-------------------------------
  2165. X    Redesignate sectors that the npc owns.
  2166. X-----------------------------------------------------------------------------*/
  2167. Xdo_npc_redesig(np)
  2168. X     Snation *np;
  2169. X{
  2170. X  struct pt_list *Pointer;
  2171. X  int Loop,x,y;
  2172. X  /* Have NPC nation redesignate sectors */
  2173. X  
  2174. X  Pointer = np->ptlist;
  2175. X  for (Loop = 0; Loop < np->n_sects; Loop++) {
  2176. X    x = Pointer->pt.x;
  2177. X    y = Pointer->pt.y;
  2178. X    if (world.map[x][y].n_people > 0 &&
  2179. X    world.map[x][y].designation == D_NODESIG) {
  2180. X      if ((world.map[x][y].metal + world.map[x][y].jewels > 0)
  2181. X      && ((world.map[x][y].metal > world.map[x][y].soil - 6)
  2182. X      || (world.map[x][y].jewels > world.map[x][y].soil - 6))) {
  2183. X    if (world.map[x][y].metal > world.map[x][y].jewels) {
  2184. X      world.map[x][y].designation = D_METAL_MINE;
  2185. X      np->money -= desig_map[D_METAL_MINE].price;
  2186. X    } else {
  2187. X      world.map[x][y].designation = D_JEWEL_MINE;
  2188. X      np->money -= desig_map[D_JEWEL_MINE].price;
  2189. X    }
  2190. X      } else {
  2191. X    if (world.map[x][y].soil >= 0) {
  2192. X      world.map[x][y].designation = D_FARM;
  2193. X      np->money -= desig_map[D_FARM].price;
  2194. X    }
  2195. X      }
  2196. X    }
  2197. X  Pointer = Pointer->next;
  2198. X  }
  2199. X}
  2200. END_OF_FILE
  2201. if test 19296 -ne `wc -c <'npc.c'`; then
  2202.     echo shar: \"'npc.c'\" unpacked with wrong size!
  2203. fi
  2204. # end of 'npc.c'
  2205. fi
  2206. echo shar: End of archive 21 \(of 28\).
  2207. cp /dev/null ark21isdone
  2208. MISSING=""
  2209. 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
  2210.     if test ! -f ark${I}isdone ; then
  2211.     MISSING="${MISSING} ${I}"
  2212.     fi
  2213. done
  2214. if test "${MISSING}" = "" ; then
  2215.     echo You have unpacked all 28 archives.
  2216.     echo "Now execute ./do_cat.sh to build doc files"
  2217.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2218. else
  2219.     echo You still need to unpack the following archives:
  2220.     echo "        " ${MISSING}
  2221. fi
  2222. ##  End of shell archive.
  2223. exit 0
  2224.