home · contact · privacy
540f025cc7c1eb7792be1c35c3bd0bffe8189f67
[plomrogue] / src / server / run.c
1 /* src/server/run.c */
2
3 #include "run.h"
4 #include <stddef.h> /* NULL */
5 #include <stdint.h> /* uint8_t, uint16_t, uint32_t */
6 #include <stdio.h> /* FILE, sprintf() */
7 #include <stdlib.h> /* free() */
8 #include <string.h> /* strlen(), strncmp(), atoi() */
9 #include <unistd.h> /* access() */
10 #include "../common/readwrite.h" /* try_fopen(), try_fcose(), try_fwrite(),
11                                   * try_fgets(), try_fclose_unlink_rename(),
12                                   * textfile_sizes(), try_fputc()
13                                   */
14 #include "../common/rexit.h" /* exit_trouble() */
15 #include "ai.h" /* pretty_dumb_ai() */
16 #include "init.h" /* remake_world() */
17 #include "io.h" /* io_round() */
18 #include "map_object_actions.h" /* get_moa_id_by_name() */
19 #include "map_objects.h" /* struct MapObj, get_player() */
20 #include "world.h" /* global world */
21
22
23
24 /* Run the game world and its inhabitants (and their actions) until the player
25  * avatar is free to receive new commands (or is dead).
26  */
27 static void turn_over();
28
29 /* If "msg"'s first part matches "command_name", set player's MapObj's .command
30  * to the command's id and its .arg to a numerical value following in the latter
31  * part of "msg" (if no digits are found, use 0); then finish player's turn and
32  * turn game over to the NPCs via turn_over(); then return 1. Else, return 0.
33  */
34 static uint8_t apply_player_command(char * msg, char * command_name);
35
36
37
38 static void turn_over()
39 {
40     struct MapObj * player = get_player();
41     struct MapObj * map_object = player;
42     uint16_t start_turn = world.turn;
43     uint8_t first_round = 1;
44     while (    0 < player->lifepoints
45            || (0 == player->lifepoints && start_turn == world.turn))
46     {
47         if (NULL == map_object)
48         {
49             world.turn++;
50             map_object = world.map_objs;
51         }
52         if (0 < map_object->lifepoints)
53         {
54             if (0 == first_round && 0 == map_object->progress)
55             {
56                 if (map_object == player)
57                 {
58                     break;
59                 }
60                 pretty_dumb_ai(map_object);
61             }
62             first_round = 0;
63             map_object->progress++;
64             struct MapObjAct * moa = world.map_obj_acts;
65             while (moa->id != map_object->command)
66             {
67                 moa = moa->next;
68             }
69             if (map_object->progress == moa->effort)
70             {
71                 moa->func(map_object);
72                 map_object->progress = 0;
73             }
74         }
75         map_object = map_object->next;
76     }
77 }
78
79
80
81 static uint8_t apply_player_command(char * msg, char * command_name)
82 {
83     if (!strncmp(msg, command_name, strlen(command_name)))
84     {
85         struct MapObj * player = get_player();
86         player->arg = atoi(&(msg[strlen(command_name)]));
87         player->command = get_moa_id_by_name(command_name);
88         turn_over();
89         return 1;
90     }
91     return 0;
92 }
93
94
95
96 extern void obey_msg(char * msg, uint8_t do_record)
97 {
98     char * f_name = "obey_msg()";
99     if (   apply_player_command(msg, "wait")   /* TODO: Check for non-error   */
100         || apply_player_command(msg, "move")   /* return value of a modified  */
101         || apply_player_command(msg, "pick_up")/* get_moa_id_by_name(); if id */
102         || apply_player_command(msg, "drop")   /* found, execute on it what's */
103         || apply_player_command(msg, "use"));  /* in apply_player_command().  */
104     else
105     {
106         char * seed_command = "seed";
107         if (!strncmp(msg, seed_command, strlen(seed_command)))
108         {
109             remake_world(atoi(&(msg[strlen(seed_command)])));
110         }
111     }
112     if (do_record)
113     {
114         char path_tmp[strlen(world.path_record) + strlen(world.tmp_suffix) + 1];
115         sprintf(path_tmp, "%s%s", world.path_record, world.tmp_suffix);
116         FILE * file_tmp  = try_fopen(path_tmp, "w", f_name);
117         if (!access(world.path_record, F_OK))
118         {
119             FILE * file_read = try_fopen(world.path_record, "r", f_name);
120             uint32_t linemax = textfile_sizes(file_read, NULL);
121             char line[linemax + 1];
122             while (try_fgets(line, linemax + 1, file_read, f_name))
123             {
124                 try_fwrite(line, strlen(line), 1, file_tmp, f_name);
125             }
126             try_fclose(file_read, f_name);
127         }
128         try_fwrite(msg, strlen(msg), 1, file_tmp, f_name);
129         try_fputc('\n', file_tmp, f_name);
130         try_fclose_unlink_rename(file_tmp, path_tmp, world.path_record, f_name);
131     }
132 }
133
134
135
136 extern uint8_t io_loop()
137 {
138     char * f_name = "io_loop()";
139     while (1)
140     {
141         char * msg = io_round();
142         if (NULL == msg)
143         {
144             continue;
145         }
146         if (world.is_verbose)
147         {
148             exit_trouble(-1 == printf("Input: %s\n", msg), f_name, "printf()");
149         }
150         if (!strcmp("QUIT", msg))
151         {
152             free(msg);
153             return 1;
154         }
155         if (world.replay)
156         {
157             free(msg);
158             return 0;
159         }
160         obey_msg(msg, 1);
161         free(msg);
162     }
163 }