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