Game.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. #include "Map.h"
  2. game CreateGame() {
  3. game G = NULL;
  4. G = malloc(sizeof(Game));
  5. if(G) {
  6. G->print = CursesPrint;
  7. G->pc = NULL;
  8. G->ZombieListHead = NULL;
  9. G->win = NULL;
  10. int y, x;
  11. getmaxyx(stdscr, y, x );
  12. G->win = newwin( y, x, 0, 0 );
  13. G->arena = NULL;
  14. int status_height = 0;
  15. G->arena = CreateSubwindow(G->win, y-status_height, x, 0, 0 );
  16. G->status = NULL;
  17. G->status = CreateSubwindow(G->win, status_height, x, y-status_height, 0 );
  18. G->gameMap = CreateMap(G);
  19. InitMap(G->gameMap);
  20. return G;
  21. } else {
  22. fprintf( L, "Fatal error: failed to assign memory in CreateGame().\n" );
  23. exit(EXIT_FAILURE);
  24. }
  25. }
  26. game NewGame() {
  27. game g = CreateGame();
  28. if( g == NULL ) return NULL;
  29. RandomMap(g->gameMap);
  30. g->pc = CreateCharacter(g);
  31. wrefresh(g->win);
  32. init_pc(g->pc);
  33. box(g->arena, 0, 0);
  34. wrefresh(g->arena);
  35. int nzombies = NumZombies(g->arena);
  36. g->ZombieListHead = CreateCreature(g);
  37. init_npc(g->ZombieListHead->Character);
  38. wrefresh(g->arena);
  39. int n = 1;
  40. while( n < nzombies ) {
  41. wrefresh(g->arena);
  42. creature Z = CreateCreature(g);
  43. init_npc(Z->Character);
  44. InsertCreatureNode( g->ZombieListHead, Z );
  45. ++n;
  46. }
  47. return g;
  48. }
  49. void RunGame( int load) {
  50. game g = NULL;
  51. if(load) {
  52. g = LoadGame();
  53. } else {
  54. g = NewGame();
  55. }
  56. if(g==NULL) {
  57. return;
  58. }
  59. wrefresh(g->arena);
  60. wrefresh(g->status);
  61. if(g!=NULL) {
  62. if(g->pc) g->print(g->pc);
  63. creature G = CreateCreature(g);
  64. G = g->ZombieListHead;
  65. while(G) {
  66. g->print(G->Character);
  67. G = G->Next;
  68. }
  69. PrintAllBuildings(g->gameMap, g->pc->pos);
  70. PlayLoop(g);
  71. if(G) {
  72. PurgeCreatureNode(G);
  73. DESTROY(G);
  74. }
  75. PurgeGame(g);
  76. DESTROY(g);
  77. }
  78. }
  79. void PlayLoop( game g ) {
  80. while(pc_play(g)) {
  81. PrintAllBuildings(g->gameMap, g->pc->pos);
  82. move_zombies(g);
  83. update_alertness(g);
  84. bite_check(g);
  85. }
  86. char ch;
  87. while( ( g->pc->win || g->pc->health <= 0 ) && ! (( ch = getch() ) == 'q') ){
  88. // Let the player revel in their victory or failure.
  89. }
  90. wrefresh(g->arena);
  91. wrefresh(g->status);
  92. }
  93. /*! Waits for player input. */
  94. int pc_play( game g ) {
  95. if( g->pc->health <= 0 ) {
  96. wattron( g->win, COLOR_PAIR(ACTIVE) | A_BOLD );
  97. int max_y, max_x;
  98. getmaxyx( g->win, max_y, max_x );
  99. mvwprintw( g->win, max_y/2, max_x/2, "YOU LOSE!!" );
  100. wstandend(g->win);
  101. wrefresh(g->win);
  102. return FALSE;
  103. }
  104. if( g->pc->fatigue > 0 ) {
  105. g->pc->fatigue--;
  106. }
  107. g->pc->exhausted = (!g->pc->exhausted && g->pc->fatigue >= max_fatigue -1) || (g->pc->exhausted && g->pc->fatigue > 0 );
  108. int ch = getch();
  109. int i;
  110. switch( ch ) {
  111. case 'K':
  112. for( i=0; i<= !g->pc->exhausted; i++ ) {
  113. mvrel( g->pc, -1, 0 );
  114. g->pc->fatigue += !g->pc->exhausted;
  115. }
  116. break;
  117. case 'k':
  118. mvrel( g->pc, -1, 0);
  119. break;
  120. case 'J':
  121. for( i=0; i<= !g->pc->exhausted; i++ ) {
  122. mvrel( g->pc, 1, 0 );
  123. g->pc->fatigue += !g->pc->exhausted;
  124. }
  125. break;
  126. case 'j':
  127. mvrel( g->pc, 1, 0);
  128. break;
  129. case 'H':
  130. for( i=0; i<=!g->pc->exhausted; i++ ) {
  131. mvrel( g->pc, 0, -1 );
  132. g->pc->fatigue += !g->pc->exhausted;
  133. }
  134. break;
  135. case 'h':
  136. mvrel( g->pc, 0, -1);
  137. break;
  138. case 'L':
  139. for( i=0; i<=!g->pc->exhausted; i++ ) {
  140. mvrel( g->pc, 0, 1 );
  141. g->pc->fatigue += !g->pc->exhausted;
  142. }
  143. break;
  144. case 'l':
  145. mvrel( g->pc, 0, 1);
  146. break;
  147. case 'w':
  148. SaveGame(g);
  149. break;
  150. case 'q': // ESC
  151. return FALSE;
  152. }
  153. if( g->pc->win ) {
  154. wattron( g->win, COLOR_PAIR(WINNING_GREEN) | A_BOLD );
  155. int max_y, max_x;
  156. getmaxyx( g->win, max_y, max_x );
  157. mvwprintw( g->win, max_y/2, max_x/2, "YOU WIN!!" );
  158. wstandend(g->win);
  159. wrefresh(g->win);
  160. return FALSE;
  161. }
  162. return TRUE;
  163. }
  164. void PurgeGame( game g ) {
  165. DestroyZombies( g );
  166. if( g->pc != NULL ) {
  167. PurgeCharacter( g->pc );
  168. free( g->pc );
  169. }
  170. g->print= NULL;
  171. g->pc = NULL;
  172. DestroyMap(g->gameMap);
  173. DestroyWindow(g->arena);
  174. DestroyWindow(g->status);
  175. DestroyWindow(g->win);
  176. }
  177. void DestroyZombies( game g ) {
  178. if( g == NULL ) return;
  179. if( g->ZombieListHead == NULL ) return;
  180. while( g->ZombieListHead->Next != NULL ) {
  181. creature G = g->ZombieListHead->Next;
  182. CutCreatureNode( g->ZombieListHead, G );
  183. if(G != NULL) {
  184. PurgeCreatureNode( G );
  185. DESTROY(G);
  186. }
  187. }
  188. if( g->ZombieListHead != NULL ) {
  189. PurgeCreatureNode( g->ZombieListHead );
  190. DESTROY( g->ZombieListHead );
  191. }
  192. }
  193. void LoadCharacter( game g, chr c ) {
  194. if( g == NULL || c == NULL ) return;
  195. if( c->ispc ) {
  196. LoadPlayerCharacter( g, c );
  197. } else {
  198. LoadZombie( g, c );
  199. }
  200. }
  201. void LoadPlayerCharacter( game g, chr c ) {
  202. if( g == NULL || c == NULL ) return;
  203. if( g->pc ) { // Start from scratch ...
  204. PurgeCharacter( g->pc );
  205. DESTROY(g->pc);
  206. }
  207. g->pc = CreateCharacter(g);
  208. CopyCharacter( g->pc, c );
  209. wrefresh(g->arena);
  210. }
  211. void LoadZombie( game g, chr z ) {
  212. if( g == NULL || z == NULL ) return;
  213. if( g->ZombieListHead != NULL ) {
  214. creature Z = CreateCreature(g);
  215. CopyCharacter( Z->Character, z );
  216. InsertCreatureNode( g->ZombieListHead, Z );
  217. } else {
  218. g->ZombieListHead = CreateCreature(g);
  219. CopyCharacter( g->ZombieListHead->Character, z );
  220. }
  221. wrefresh(g->arena);
  222. }
  223. /*! First increase or decrease zombie's alertness depending
  224. on player proximity. Then use alertness to check whether
  225. the zombie starts actively hunting. */
  226. void update_alertness( game g ) {
  227. creature Z = g->ZombieListHead;
  228. int d;
  229. while( Z != NULL ) {
  230. chr z = Z->Character;
  231. // If a zombie sees another zombie hunting, it increases
  232. // alertness.
  233. creature Z1 = g->ZombieListHead;
  234. int num_alert = 0;
  235. while(Z1 != NULL) {
  236. chr z1 = Z1->Character;
  237. d = distance(z1->pos, z->pos);
  238. num_alert += z1->alert && d <= zombie_sight_range && d > 0;
  239. Z1 = Z1->Next;
  240. }
  241. if(!z->alert) z->alertness += (randint(0, num_alert) != 0);
  242. d = distance( g->pc->pos, z->pos );
  243. if( d <= zombie_sight_range ) {
  244. if( z->alertness < max_alertness ) {
  245. z->alertness++;
  246. }
  247. } else if( z->alertness > 0 ) {
  248. if(randint(0, (d - z->alert)/(zombie_sight_range + z->alertness))) z->alertness--;
  249. }
  250. int check = randint( 0, max_alertness );
  251. if( ( z->alert && d > zombie_sight_range ) || ! z->alert ) {
  252. z->alert = ( check < z->alertness );
  253. }
  254. Z = Z->Next;
  255. }
  256. }
  257. void move_zombies( game g ) {
  258. creature Z = g->ZombieListHead;
  259. while( Z != NULL ) {
  260. chr z = Z->Character;
  261. if( ! z->alert ) {
  262. int check = randint(-1,1);
  263. if( check == 0 ) {
  264. mvrel( z, randint( -1, 1 ), 0 );
  265. } else if( check ==1 ) {
  266. mvrel( z, 0, randint( -1, 1 ) );
  267. }
  268. } else {
  269. int dx = g->pc->pos->x - z->pos->x;
  270. int dy = g->pc->pos->y - z->pos->y;
  271. // Axis 0 will be horizontal, axis 1 is vertical.
  272. int axis = randint( 0, 1 );
  273. if( abs( dx ) > abs( dy ) ) {
  274. axis = 0;
  275. } else if( abs( dx ) < abs( dy ) ) {
  276. axis = 1;
  277. }
  278. int h_blocked = blocked(g->arena, z->pos->y, z->pos->x + 2*(dx >= 0) - 1);
  279. int v_blocked = blocked(g->arena, z->pos->y + 2*(dy >= 0) - 1, z->pos->x);
  280. if(h_blocked && !v_blocked) axis = 1;
  281. if(v_blocked && !h_blocked) axis = 0;
  282. int dir = 0;
  283. if( axis == 0 ) { // move along x-axis.
  284. if( dx >= 0 ) {
  285. dir = 1;
  286. } else {
  287. dir = -1;
  288. }
  289. mvrel( z, 0, dir );
  290. } else {
  291. if( dy >= 0 ) {
  292. dir = 1;
  293. } else {
  294. dir = -1;
  295. }
  296. mvrel( z, dir, 0 );
  297. }
  298. }
  299. Z = Z->Next;
  300. }
  301. }
  302. void bite_check( game g ) {
  303. creature Z = g->ZombieListHead;
  304. while( Z != NULL ) {
  305. chr z = Z->Character;
  306. int d = distance( g->pc->pos, z->pos );
  307. if( d == 1 ) {
  308. g->pc->health -= randint( 0, 1 );
  309. }
  310. Z = Z->Next;
  311. }
  312. }
  313. void SaveGame( game g ) {
  314. FILE* sf = fopen( "game.save", "w+" );
  315. SaveCharacter( sf, g->pc );
  316. creature Z = g->ZombieListHead;
  317. while( Z != NULL ) {
  318. chr z = Z->Character;
  319. SaveCharacter( sf, z );
  320. Z = Z->Next;
  321. }
  322. SaveMap(sf, g->gameMap);
  323. fclose( sf );
  324. }
  325. void SaveCharacter( FILE* sf, chr c ) {
  326. if( ! c->ispc ) fprintf( sf, "n" ); // Put "n" on "npc"
  327. fprintf( sf, "pc { pos = ( %d, %d )", GetStat( c, "y" ), GetStat( c, "x" ) );
  328. int i;
  329. for( i=0; i < nattrs; ++i ) {
  330. attr* attr_pair = Attrs + i;
  331. if( strcmp( attr_pair->str, "x" ) != 0 && strcmp( attr_pair->str, "y" ) != 0 ) {
  332. fprintf( sf, ", %s = %d", attr_pair->str, GetStat( c, attr_pair->str ) );
  333. }
  334. }
  335. fprintf( sf, "}\n" );
  336. }
  337. void SaveMap( FILE* sf, map m ) {
  338. if(!m) return;
  339. fprintf(sf, "map { ");
  340. building B = m->BuildingListHead;
  341. block b = B->contents;
  342. if(b) fprintf(sf, "(%d, %d, %d, %d)", b->h, b->w, b->y, b->x);
  343. B = B->Next;
  344. while(B) {
  345. block b = B->contents;
  346. if(b) fprintf(sf, ", (%d, %d, %d, %d)", b->h, b->w, b->y, b->x);
  347. B = B->Next;
  348. }
  349. fprintf(sf, " }");
  350. }
  351. int InLineOfSight(coords c, coords z, map m) {
  352. if(!c || !z || !m) return FALSE;
  353. if(c->x == z->x && c->y == z->y) return TRUE;
  354. if(!m->BuildingListHead) return FALSE;
  355. building B = m->BuildingListHead;
  356. block b = NULL;
  357. coords u = CreateCoords(), v = CreateCoords();
  358. while(B) {
  359. b = B->contents;
  360. int x;
  361. for(x = b->x; x <= b->x + b->w - 1; x += b->w - 1) {
  362. u->x = x;
  363. u->y = b->y;
  364. v->x = x;
  365. v->y = b->y + b->h - 1;
  366. if(Intersects(c, z, u, v)) {
  367. return FALSE;
  368. }
  369. }
  370. int y;
  371. for(y = b->y; y <= b->y + b->h - 1; y += b->h - 1) {
  372. u->x = b->x;
  373. u->y = y;
  374. v->x = b->x + b->w - 1;
  375. v->y = y;
  376. if(Intersects(c, z, u, v)) {
  377. return FALSE;
  378. }
  379. }
  380. B = B->Next;
  381. }
  382. return TRUE;
  383. }