#include <sys/stat.h>
#include <time.h>
#include <limits.h>
+#include <deque>
/* Coord/Offset constants */
Coord const Nowhere = { INT_MIN, INT_MIN };
}
}
+void wrapped_system(char const *cmd)
+{
+ int i = system(cmd);
+ if (i != 0)
+ {
+ throw(i);
+ }
+}
+
+void wrapped_fread(void *buf, size_t size, size_t nmemb, FILE *fp)
+{
+ size_t i = fread(buf, size, nmemb, fp);
+ if (i != nmemb)
+ {
+ throw(i);
+ }
+}
+
void save_game(void)
{
FILE *fp;
uint32_t tmp;
+ int i;
fp = fopen("victrix-abyssi.sav", "wb");
serialize_level(fp, &lvl);
fwrite(permobjs, NUM_OF_PERMOBJS, sizeof (Permobj), fp);
fflush(fp);
fclose(fp);
/* Compress! */
- system("gzip victrix-abyssi.sav");
+ i = system("gzip victrix-abyssi.sav");
+ if (i != 0)
+ {
+ /// welp gzip failed
+ }
game_finished = 1;
return;
}
void load_game(void)
{
FILE *fp;
- system("gunzip victrix-abyssi.sav");
+ wrapped_system("gunzip victrix-abyssi.sav");
fp = fopen("victrix-abyssi.sav", "rb");
deserialize_level(fp, &lvl);
- fread(permobjs, NUM_OF_PERMOBJS, sizeof (Permobj), fp);
- fread(monsters, MONSTERS_IN_PLAY, sizeof (Mon), fp);
- fread(objects, OBJECTS_IN_PLAY, sizeof (Obj), fp);
+ wrapped_fread(permobjs, sizeof (Permobj), NUM_OF_PERMOBJS, fp);
+ wrapped_fread(monsters, sizeof (Mon), MONSTERS_IN_PLAY, fp);
+ wrapped_fread(objects, sizeof (Obj), OBJECTS_IN_PLAY, fp);
rebuild_mapobjs();
rebuild_mapmons();
- fread(&depth, 1, sizeof depth, fp);
+ wrapped_fread(&depth, 1, sizeof depth, fp);
depth = ntohl(depth);
- fread(&u, 1, sizeof u, fp);
- fread(&game_tick, 1, sizeof game_tick, fp);
+ wrapped_fread(&u, 1, sizeof u, fp);
+ wrapped_fread(&game_tick, 1, sizeof game_tick, fp);
fclose(fp);
look_around_you();
status_updated = 1;
unlink("victrix-abyssi.sav");
}
-int exclusive_flat(int lower, int upper)
-{
- return lower + one_die(upper - lower - 1);
-}
-
-int inclusive_flat(int lower, int upper)
-{
- return lower + zero_die(upper - lower + 1);
-}
-
Offset random_step(void)
{
switch (zero_die(8))
return Stationary;
}
-Coord inclusive_boxed(Coord topleft, Coord botright)
+void new_game(void)
{
- Coord c = { inclusive_flat(topleft.y, botright.y), inclusive_flat(topleft.x, botright.x) };
- return c;
+ u_init();
+ flavours_init();
+ make_new_level();
+ status_updated = 1;
+ map_updated = 1;
+ hard_redraw = 1;
+ print_msg("Initialisation complete.\n");
}
-Coord exclusive_boxed(Coord topleft, Coord botright)
+std::deque<Action> past_actions;
+
+enum Combo_phase
{
- Coord c = { exclusive_flat(topleft.y, botright.y), exclusive_flat(topleft.x, botright.x) };
- return c;
-}
+ Combo_invalid,
+ Combo_link,
+ Combo_finisher
+};
+/* \brief Process action combos
+ *
+ * This function is responsible for detecting whether the most recently
+ * attempted action is a possible step in a combo, a combo finisher, or a
+ * combo-invalid move (for example, quaffing a potion is a combo breaker). It
+ * uses the contents of the deque past_actions to make the decision.
+ *
+ * \param act Pointer to attempted action
+ * \param revised_act Pointer to storage location for revised action
+ * \return true if revised_act was written to; false otherwise
+ */
-int one_die(int sides)
+bool detect_combo(Action const *act, Action *revised_act)
{
- int rval;
- if (sides < 2)
+ //Combo_phase p;
+ // for now, we use if rather than switch because there are only two
+ // valid action types in a combo: move, and attack.
+ if (act->cmd == WALK)
{
- return 1;
+ *revised_act = *act;
+ return true;
}
- rval = 1 + (rng() / ((RNG_MAX / sides) + 1));
- return rval;
-}
-
-int zero_die(int sides)
-{
- int rval;
- if (sides < 2)
+ else if (act->cmd == ATTACK)
{
- return 0;
+ *revised_act = *act;
+ return true;
}
- rval = rng() / ((RNG_MAX / sides) + 1);
- return rval;
-}
-
-int dice(int count, int sides)
-{
- int total = 0;
- for ( ; count > 0; count--)
+ else
{
- total += one_die(sides);
+ return false;
}
- return total;
-}
-
-void new_game(void)
-{
- u_init();
- flavours_init();
- make_new_level();
- status_updated = 1;
- map_updated = 1;
- hard_redraw = 1;
- print_msg("Initialisation complete.\n");
}
Action_cost do_player_action(Action *act)
{
int slot;
- Action_cost cost;
Offset step;
+ Action redact;
+ bool rewritten = detect_combo(act, &redact);
+ if (rewritten)
+ {
+ act = &redact;
+ }
switch (act->cmd)
{
case WALK:
break;
case WEAR_ARMOUR:
- cost = Cost_none;
- if (u.armour != NO_OBJ)
- {
- print_msg("You are already wearing armour.\n");
- }
- else
- {
- slot = inv_select(POCLASS_ARMOUR, "wear", 0);
- if (slot != SLOT_CANCEL)
- {
- u.armour = u.inventory[slot];
- recalc_defence();
- if (objects[u.armour].obj_id == PO_SET_OF_RIBBONS)
- {
- print_msg("You grit your teeth, trying to get used to the tingle of\nthe ribbons' magic against your skin.\n");
- }
- else
- {
- print_msg("Wearing ");
- print_obj_name(u.armour);
- print_msg(".\n");
- }
- cost = Cost_std;
- }
- }
- return cost;
+ slot = act->details[0];
+ return wear_armour(slot);
case EMANATE_ARMOUR:
if (u.armour == NO_OBJ)
{
- print_msg("You are not wearing any armour.\n");
+ notify_emanate_no_armour();
return Cost_none;
}
return emanate_armour();
case ZAP_WEAPON:
if (u.weapon == NO_OBJ)
{
- print_msg("You have no weapon in hand.\n");
+ notify_zap_no_weapon();
return Cost_none;
}
return zap_weapon();
case MAGIC_RING:
if (u.weapon == NO_OBJ)
{
- print_msg("You are not wearing a ring.\n");
+ notify_magic_no_ring();
return Cost_none;
}
return magic_ring();
void main_loop(void)
{
int i;
- int action_speed;
+ int action_speed = 0;
print_msg("Welcome to the Abyss, Princess %s.\n", u.name);
print_msg("Press '?' for help.\n");
while (!game_finished)
{
- switch (game_tick % 4)
+ switch (game_tick & 3)
{
case 0:
case 2:
struct stat s;
int i;
display_init();
- memset(lvl.objs, -1, sizeof lvl.objs);
- memset(lvl.mons, -1, sizeof lvl.mons);
rng_init();
/* Do we have a saved game? */
i = stat("victrix-abyssi.sav.gz", &s);