Big-ball-of-mud commit because of a UI landmark
authorMartin Read <martin@blackswordsonics.com>
Sun, 9 Feb 2014 02:31:58 +0000 (02:31 +0000)
committerMartin Read <martin@blackswordsonics.com>
Sun, 9 Feb 2014 02:31:58 +0000 (02:31 +0000)
14 files changed:
MANIFEST
Makefile
combat.cc
default.permobjs
display-nc.cc
display.hh
log.cc [new file with mode: 0644]
main.cc
misc.cc
notify-local-tty.cc
notify.hh
objects.cc
u.cc
victrix-abyssi.hh

index 9825dbe..f8cff9b 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -12,6 +12,7 @@ display.hh
 display-nc.cc
 fov.cc
 fov.hh
+log.cc
 main.cc
 map.cc
 map.hh
index d84034e..b7843f6 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ include features.mk
 
 GENERATED_OBJS:=permobj.o
 GENERATED_SOURCE:=permobj.cc pobj_id.hh dirs.mk features.mk
-HANDWRITTEN_OBJS:=combat.o display-nc.o fov.o main.o map.o misc.o monsters.o mon2.o notify-local-tty.o objects.o permons.o pmon2.o rng.o sorcery.o u.o
+HANDWRITTEN_OBJS:=combat.o display-nc.o fov.o log.o main.o map.o misc.o monsters.o mon2.o notify-local-tty.o objects.o permons.o pmon2.o rng.o sorcery.o u.o
 OBJS:=$(GENERATED_OBJS) $(HANDWRITTEN_OBJS)
 GAME:=victrix-abyssi
 MAJVERS:=1
@@ -41,6 +41,9 @@ my-debworkflow: debianize-archive
        cp -R debian archive-test/$(ARCHIVEDIR)/debian
        (cd archive-test/$(ARCHIVEDIR) && debuild -uc -us)
 
+my-debclean:
+       -rm -rf archive-test
+
 clean:
        -rm -rf $(ARCHIVEDIR)
        -rm -f *.o $(GAME) *.tar.gz
@@ -48,6 +51,9 @@ clean:
 code-docs:
        doxygen Doxyfile
 
+code-docs-clean:
+       -rm -rf html latex
+
 install: all
        echo "man6dir is $(man6dir)"
        install -D $(GAME) $(DESTDIR)$(gamesdir)/$(GAME)
index 0d87f00..ca028f4 100644 (file)
--- a/combat.cc
+++ b/combat.cc
@@ -225,20 +225,23 @@ test_unaffected:
         switch (dtype)
         {
         case DT_PHYS:
+        case DT_HELLFIRE:
+        case DT_KNOCKBACK:
             debug_player_resists_phys();
             unaffected = 0;
             /* Turn off the player's resistance, because they're
              * not supposed to have it! */
-            u.resistances[DT_PHYS] = 0;
+            u.resistances[dtype] = 0;
             goto test_unaffected;
         case DT_FIRE:
-            print_msg("The flames seem pleasantly warm.\n");
-            break;
         case DT_COLD:
-            print_msg("Its touch seems pleasantly cool.\n");
-            break;
         case DT_NECRO:
-            print_msg("Its touch makes you feel no deader.\n");
+        case DT_POISON:
+        case DT_DROWNING:
+        case DT_ELEC:
+            /* these are the only damage types you should be completely
+             * ignoring right now */
+            notify_player_ignore_damage(dtype);
             break;
         default:
             debug_bad_damage_type(dtype);
@@ -247,22 +250,7 @@ test_unaffected:
     }
     else
     {
-        switch (dtype)
-        {
-        default:
-        case DT_PHYS:
-            break;
-        case DT_FIRE:
-            print_msg("You are engulfed in flames.\n");
-            break;
-        case DT_COLD:
-            print_msg("You are covered in frost.\n");
-            break;
-        case DT_NECRO:
-            print_msg("You feel your life force slipping away.\n");
-            break;
-        }
-        print_msg("You take %d damage.\n", damage);
+        notify_player_touch_effect(dtype);
         if ((mptr->mon_id == PM_VAMPIRE) && !u.resists(DT_NECRO))
         {
             heal_mon(mon, damage * 2 / 5, 1);
@@ -341,7 +329,6 @@ int mshootu(int mon)
                 if (!unaffected)
                 {
                     damage = one_die(mptr->rdam);
-                    print_msg("You take %d damage.\n", damage);
                     damage_u(damage, DEATH_KILLED_MON, permons[mptr->mon_id].name);
                 }
                 display_update();
@@ -402,84 +389,5 @@ int mshootu(int mon)
     return 0;
 }
 
-#if 0
-static void flask_effect_weakness(Mon *mptr)
-{
-    if (!pmon_is_undead(mptr->mon_id))
-    {
-        print_msg("Your foe shrivels and twists horribly.\n");
-        mptr->hpmax = (mptr->hpmax + 1) / 2;
-        mptr->hpcur = (mptr->hpcur + 1) / 2;
-    }
-    else
-    {
-        print_msg("What does not live cannot degenerate.\n");
-    }
-}
-
-static void flask_effect_poison(Mon *mptr)
-{
-    print_msg("Your foe is drenched in contact poison.\n");
-    if (!pmon_resists_poison(mptr->mon_id))
-    {
-        damage_mon(mptr - monsters, inclusive_flat((mptr->hpmax + 5) / 6, (mptr->hpmax + 2) / 3), true);
-    }
-    else
-    {
-        print_msg("... to little effect.\n");
-    }
-}
-static void flask_effect_fire(Mon *mptr)
-{
-    print_msg("Your foe is drenched in burning oil.\n");
-    if (!pmon_resists_fire(mptr->mon_id))
-    {
-        damage_mon(mptr - monsters, 15 + dice(5, 4), true);
-    }
-    else
-    {
-        print_msg("... to little effect.\n");
-    }
-}
-#endif
-
-Action_cost throw_flask(int obj, Offset step)
-{
-    int i;
-    Coord c;
-    int mon;
-    void (*flask_effect)(Mon *);
-    switch (objects[obj].obj_id)
-    {
-#if 0
-    case PO_FLASK_WEAKNESS:
-        flask_effect = flask_effect_weakness;
-        break;
-    case PO_FLASK_POISON:
-        flask_effect = flask_effect_poison;
-        break;
-    case PO_FLASK_FIRE:
-        flask_effect = flask_effect_fire;
-        break;
-#endif
-    default:
-        debug_throw_non_flask();
-        return Cost_none;
-    }
-    for ((i = 1), (c = u.pos + step); i < 10; ++i, (c += step))
-    {
-        mon = lvl.mon_at(c);
-        if ((mon != NO_MON) && (monsters[mon].used))
-        {
-            Mon *mptr = monsters + mon;
-            flask_effect(mptr);
-            consume_obj(obj);
-            return Cost_std;
-        }
-    }
-    notify_no_flask_target();
-    return Cost_std;
-}
-
 /* combat.cc */
 // vim:cindent
index 74640d4..e519f96 100644 (file)
@@ -354,6 +354,8 @@ POWER2 10
 DEPTH 24
 DRESS
 
+# Mr Read would like to note that he invented the following item and its
+# game mechanics *before* becoming aware of the anime series _Kill la Kill_.
 ARMOUR set of ribbons
 PLURAL sets of ribbons
 DESC These ribbons, arranged as if to form an alleged garment, make your fingers tingle with magic.
index c5af9f0..87d9128 100644 (file)
@@ -49,18 +49,18 @@ WINDOW *status_window;
 WINDOW *world_window;
 WINDOW *message_window;
 WINDOW *inventory_window;
+WINDOW *fullscreen_window; /* discrete from stdscr because *twitch* */
 PANEL *status_panel;
 PANEL *world_panel;
 PANEL *message_panel;
 PANEL *inventory_panel;
+PANEL *fullscreen_panel;
 bool force_ascii;
 
-int wall_colour;
-int you_colour;
-int status_updated;
-int map_updated;
-int show_terrain;
-int hard_redraw;
+bool status_updated;
+bool map_updated;
+bool show_terrain;
+bool hard_redraw;
 
 struct Attr_wrapper 
 {
@@ -112,12 +112,26 @@ static cchar_t const *monster_char(int monster_id);
 static cchar_t const *terrain_char(Terrain terrain_type);
 static void draw_status_line(void);
 static void draw_world(void);
+static void draw_main_menu(void);
+static void run_main_menu(void);
 
 /* Static funcs */
+static void draw_main_menu(void)
+{
+    mvwprintw(fullscreen_window, 1, 18, "----====< Victrix Abyssi >====----\n");
+    mvwprintw(fullscreen_window, 3, 20,  "A roguelike game by Martin Read\n");
+    mvwprintw(fullscreen_window, 10, 25, "S)tart new game\n");
+    mvwprintw(fullscreen_window, 11, 25, "R)esume existing game\n");
+    mvwprintw(fullscreen_window, 12, 25, "Q)uit\n");
+    show_panel(fullscreen_panel);
+    update_panels();
+    doupdate();
+}
+
 static void draw_status_line(void)
 {
     mvwprintw(status_window, 0, 0, "%-16.16s", u.name);
-    mvwprintw(status_window, 0, 17, "HP: %03d/%03d", u.hpcur, u.hpmax);
+    mvwprintw(status_window, 0, 17, "HP: %3d/%03d", u.hpcur, u.hpmax);
     mvwprintw(status_window, 0, 30, "BOD: %02d/%02d", u.body - u.bdam, u.body);
     mvwprintw(status_window, 0, 62, "Exp: %d/%d", u.level, u.experience);
     mvwprintw(status_window, 1, 0, "DEF: %2d", u.defence);
@@ -377,7 +391,7 @@ void display_update(void)
  *
  * \todo Rename this and put appropriate glue elsewhere to make it work
  */
-int display_init(void)
+int launch_user_interface(void)
 {
     int i;
     int j;
@@ -433,8 +447,6 @@ int display_init(void)
     init_pair(Gcol_d_grey, COLOR_BLACK, COLOR_BLACK);
     init_pair(Gcol_purple, COLOR_MAGENTA, COLOR_BLACK);
     init_pair(Gcol_cyan, COLOR_CYAN, COLOR_BLACK);
-    wall_colour = Gcol_brown;
-    you_colour = Gcol_white;
     for (i = 0; i < DISP_HEIGHT; ++i)
     {
         for (j = 0; j < DISP_WIDTH; ++j)
@@ -459,30 +471,41 @@ int display_init(void)
     message_panel = new_panel(message_window);
     inventory_window = newwin(DISP_HEIGHT, 58, 0, DISP_WIDTH + 1);
     inventory_panel = new_panel(inventory_window);
+    fullscreen_window = newwin(24, 80, 0, 0);
+    fullscreen_panel = new_panel(fullscreen_window);
     wattr_set(inventory_window, colour_data[Gcol_l_grey].attr,
               colour_data[Gcol_l_grey].cpair, NULL);
     hide_panel(inventory_panel);
     clear();
+    curs_set(0);
     wclear(status_window);
     wclear(world_window);
     wclear(message_window);
     wclear(inventory_window);
+    wclear(fullscreen_window);
     scrollok(status_window, FALSE);
     scrollok(world_window, FALSE);
     scrollok(message_window, TRUE);
     scrollok(inventory_window, FALSE);
+    scrollok(fullscreen_window, FALSE);
     idcok(status_window, FALSE);
     idcok(world_window, FALSE);
     idcok(message_window, FALSE);
     idcok(inventory_window, FALSE);
-    mvwprintw(world_window, 7, 4,    "Victrix Abyssi");
-    //mvwprintw(world_window, 9, 2, "Seven-Day Roguelike");
-    mvwprintw(world_window, 11, 4,   "By Martin Read");
+    idcok(fullscreen_window, FALSE);
     wmove(message_window, 0, 0);
     map_updated = FALSE;
     status_updated = FALSE;
-    update_panels();
-    doupdate();
+    draw_main_menu();
+    run_main_menu();
+    if (!game_finished)
+    {
+        status_updated = 1;
+        map_updated = 1;
+        hard_redraw = 1;
+        display_update();
+        // WIP launch the game logic.
+    }
     return 0;
 }
 
@@ -491,10 +514,12 @@ int display_init(void)
 int read_input(char *buffer, int length)
 {
     echo();
+    curs_set(1);
     display_update();
     buffer[0] = '\0';
     wgetnstr(message_window, buffer, length);
     noecho();
+    curs_set(0);
     return strlen(buffer);
 }
 
@@ -974,10 +999,6 @@ void get_player_action(Action *act)
                 }
             }
             break;
-        /*case 't':
-            // nobbling flask-throwing for now, as part of the general
-            // revisting of ranged combat.
-            return THROW_FLASK;*/
         case 'w':
             {
                 int slot = inv_select(POCLASS_WEAPON, "wield", 1);
@@ -1179,7 +1200,6 @@ void print_help(void)
     print_msg("W   wear armour\n");
     print_msg("T   take off armour\n");
     print_msg("w   wield a weapon\n");
-    print_msg("t   throw a flask\n");
     print_msg("r   read a scroll\n");
     print_msg("q   quaff a potion\n");
     print_msg("e   eat something edible\n");
@@ -1247,5 +1267,85 @@ void touch_one_screen(Coord c)
     }
 }
 
+bool query_wizmode_death(void)
+{
+    int yn = getyn("Really die?");
+    if (yn != 1)
+    {
+        print_msg("You survived that attempt on your life.");
+        return false;
+    }
+    return true;
+}
+
+static void show_game_view(void)
+{
+    hide_panel(fullscreen_panel);
+    update_panels();
+    doupdate();
+    display_update();
+}
+
+static void run_main_menu(void)
+{
+    bool done = false;
+    char name[16];
+    do
+    {
+        int ch = wgetch(fullscreen_window);
+        switch (ch)
+        {
+        case 's':
+        case 'S':
+            mvwprintw(fullscreen_window, 10, 1, "\n");
+            mvwprintw(fullscreen_window, 11, 1, "\n");
+            mvwprintw(fullscreen_window, 12, 1, "\n");
+            mvwprintw(fullscreen_window, 13, 15, "Welcome, Princess. Remind me of your name?\n");
+            mvwprintw(fullscreen_window, 14, 1, "\n");
+            wmove(fullscreen_window, 14, 30);
+            update_panels();
+            doupdate();
+            echo();
+            curs_set(1);
+            mvwgetnstr(fullscreen_window, 14, 30, name, 16);
+            curs_set(0);
+            noecho();
+            new_game(name);
+            done = true;
+            show_game_view();
+            break;
+        case 'c':
+        case 'C':
+            // TODO implement configuration management
+            break;
+        case 'r':
+        case 'R':
+            // TODO implement loading properly.
+            {
+                int i;
+                i = load_game();
+                if (i != -1)
+                {
+                    done = true;
+                }
+                else
+                {
+                    mvwprintw(fullscreen_window, 14, 30, "No saved game found.\n");
+                }
+            }
+            break;
+        case 'q':
+        case 'Q':
+            done = true;
+            game_finished = true;
+            break;
+        }
+    } while (!done);
+    if (!game_finished)
+    {
+        show_game_view();
+    }
+}
+
 /* display-nc.cc */
 // vim:cindent
index 0a61376..5ca99b2 100644 (file)
@@ -32,7 +32,7 @@
 extern void print_msg(char const *fmt, ...);
 extern int read_input(char *buffer, int length);
 extern void print_help(void);
-extern int display_init(void);
+extern int launch_user_interface(void);
 extern void display_update(void);
 extern int display_shutdown(void);
 extern void newsym(Coord c);
@@ -46,13 +46,14 @@ extern void press_enter(void);
 extern void pressanykey(void);
 extern void show_discoveries(void);
 extern void touch_one_screen(Coord c);
+extern bool query_wizmode_death(void);
 
 /* "I've changed things that need to be redisplayed" flags. */
-extern int hard_redraw;
-extern int status_updated;
-extern int map_updated;
+extern bool hard_redraw;
+extern bool status_updated;
+extern bool map_updated;
 /* "Show the player the terrain only" flag. */
-extern int show_terrain;
+extern bool show_terrain;
 
 #endif
 
diff --git a/log.cc b/log.cc
new file mode 100644 (file)
index 0000000..86f60b4
--- /dev/null
+++ b/log.cc
@@ -0,0 +1,75 @@
+/* \file log.cc
+ * \brief death log handler for Victrix Abyssi
+ */
+
+/* Copyright 2014 Martin Read
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "victrix-abyssi.hh"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <time.h>
+#include <limits.h>
+#include <deque>
+#include <basedir.h>
+
+void log_death(Death d, char const *what)
+{
+    FILE *fp;
+    fp = fopen("victrix-abyssi.log", "a");
+    if (fp)
+    {
+        switch (d)
+        {
+        case DEATH_KILLED:
+            fprintf(fp, "%s was killed by %s.\n", u.name, what);
+            break;
+        case DEATH_KILLED_MON:
+            fprintf(fp, "%s was killed by a nasty %s.\n", u.name, what);
+            break;
+        case DEATH_BODY:
+            fprintf(fp, "%s's heart was stopped by %s.\n", u.name, what);
+            break;
+        case DEATH_AGILITY:
+            fprintf(fp, "%s's nerves were destroyed by %s.\n", u.name, what); 
+            break;
+        case DEATH_LASH:
+            fprintf(fp, "%s tasted the lash one time too many.\n", u.name);
+            break;
+        case DEATH_RIBBONS:
+            fprintf(fp, "%s looked good in ribbons.\n", u.name);
+            break;
+        }
+        fprintf(fp, "    %s died after %d ticks, with %d XP, on dungeon level %d.\n\n", u.name, game_tick, u.experience, depth);
+        fflush(fp);
+        fclose(fp);
+    }
+}
+
+/* log.cc */
+// vim:cindent:expandtab
diff --git a/main.cc b/main.cc
index 82fc23b..e94aa5a 100644 (file)
--- a/main.cc
+++ b/main.cc
@@ -52,8 +52,6 @@ Offset const Northwest = { -1, -1 };
 Offset const Stationary = { 0, 0 };
 
 void save_game(void);
-static void load_game(void);
-static void new_game(void);
 static void rebuild_mapobjs(void);
 static void rebuild_mapmons(void);
 static void main_loop(void);
@@ -112,18 +110,16 @@ void save_game(void)
     FILE *fp;
     uint32_t tmp;
     fp = fopen("victrix-abyssi.sav", "wb");
-    serialize_level(fp, &lvl);
-    fwrite(permobjs, NUM_OF_PERMOBJS, sizeof (Permobj), fp);
-    fwrite(monsters, MONSTERS_IN_PLAY, sizeof (Mon), fp);
-    fwrite(objects, OBJECTS_IN_PLAY, sizeof (Obj), fp);
-    /* Write out the depth */
-    tmp = htonl(depth);
-    fwrite(&tmp, 1, sizeof tmp, fp);
     /* Write out the player. */
     fwrite(&u, 1, sizeof u, fp);
-    /* Write out the tick number */
+    tmp = htonl(depth);
+    fwrite(&tmp, 1, sizeof tmp, fp);
     tmp = htonl(game_tick);
     fwrite(&tmp, 1, sizeof tmp, fp);
+    serialize_level(fp, &lvl);
+    fwrite(permobjs, sizeof (Permobj), NUM_OF_PERMOBJS, fp);
+    fwrite(monsters, sizeof (Mon), MONSTERS_IN_PLAY, fp);
+    fwrite(objects, sizeof (Obj), OBJECTS_IN_PLAY, fp);
     /* Clean up */
     fflush(fp);
     fclose(fp);
@@ -131,28 +127,32 @@ void save_game(void)
     return;
 }
 
-void load_game(void)
+int load_game(void)
 {
     FILE *fp;
     fp = fopen("victrix-abyssi.sav", "rb");
+    if (!fp)
+    {
+        return -1;
+    }
+    wrapped_fread(&u, 1, sizeof u, fp);
+    wrapped_fread(&depth, 1, sizeof depth, fp);
+    depth = ntohl(depth);
+    wrapped_fread(&game_tick, 1, sizeof game_tick, fp);
+    game_tick = ntohl(game_tick);
     deserialize_level(fp, &lvl);
     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();
-    wrapped_fread(&depth, 1, sizeof depth, fp);
-    depth = ntohl(depth);
-    wrapped_fread(&u, 1, sizeof u, fp);
-    wrapped_fread(&game_tick, 1, sizeof game_tick, fp);
-    game_tick = ntohl(game_tick);
     fclose(fp);
     look_around_you();
     status_updated = 1;
     map_updated = 1;
     hard_redraw = 1;
-    print_msg("Game loaded.\n");
     unlink("victrix-abyssi.sav");
+    return 0;
 }
 
 Offset random_step(void)
@@ -179,15 +179,10 @@ Offset random_step(void)
     return Stationary;
 }
 
-void new_game(void)
+void new_game(char const *name)
 {
-    u_init();
-    flavours_init();
+    u_init(name);
     make_new_level();
-    status_updated = 1;
-    map_updated = 1;
-    hard_redraw = 1;
-    print_msg("Initialisation complete.\n");
 }
 
 std::deque<Action> past_actions;
@@ -198,6 +193,7 @@ enum Combo_phase
     Combo_link,
     Combo_finisher
 };
+
 /* \brief Process action combos
  *
  * This function is responsible for detecting whether the most recently
@@ -476,33 +472,49 @@ void main_loop(void)
 }
 
 xdgHandle victrix_xdg_handle;
+char const * victrix_data_home;
+char const * victrix_config_home;
+std::string our_data_dir;
+std::string our_config_dir;
 
-int main(void)
+void setup_dirs(void)
 {
-    struct stat s;
-    int i;
     xdgHandle * foo = xdgInitHandle(&victrix_xdg_handle);
     if (!foo)
     {
-        //// welp. Should probably throw a wobbly.
+        fputs("FATAL ERROR: libxdg-basedir handle initialization failed\n", stderr);
+        exit(1);
     }
-    // TODO actually have a config file!
-    display_init();
-    rng_init();
-    /* Do we have a saved game? */
-    i = stat("victrix-abyssi.sav.gz", &s);
-    if (!i)
+    victrix_data_home = xdgDataHome(foo);
+    victrix_config_home = xdgConfigHome(foo);
+    if (!victrix_data_home || !victrix_config_home)
     {
-        /* Yes! */
-        print_msg("Loading...\n");
-        load_game();
+        fputs("FATAL ERROR: libxdg-basedir functions failed to provide data and config homes\n", stderr);
+        exit(1);
     }
-    else
+    our_data_dir = victrix_data_home;
+    our_data_dir += "/com.blackswordsonics/victrix-abyssi";
+    /* TODO Make sure the directory exists. */
+    our_config_dir = victrix_config_home;
+    our_config_dir += "/com.blackswordsonics/victrix-abyssi";
+    /* TODO Make sure the directory exists. */
+}
+
+void load_config(void)
+{
+    // TODO actually do something here.
+}
+
+int main(void)
+{
+    setup_dirs();
+    load_config();
+    rng_init();
+    launch_user_interface();
+    if (!game_finished)
     {
-        /* No! */
-        new_game();
+        main_loop();
     }
-    main_loop();
     display_shutdown();
     return 0;
 }
diff --git a/misc.cc b/misc.cc
index 3e7a02c..fd75a0a 100644 (file)
--- a/misc.cc
+++ b/misc.cc
 
 char const *damtype_names[DT_COUNT] = {
     "physical damage",
-    "fire",
     "cold",
-    "electricity",
+    "fire",
     "necromantic force",
+    "electricity",
+    "hellfire",
     "poison",
     "knockback",
     "drowning",
 };
 
-/* main.c */
+/* misc.cc */
 // vim:cindent
index c14f3da..b3890af 100644 (file)
 #include <locale.h>
 #include <langinfo.h>
 
+void notify_player_heal(int amount, int boost, bool loud)
+{
+    status_updated = 1;
+    if (loud)
+    {
+        /* Tell the player how much better they feel. */
+        if (u.hpcur == u.hpmax)
+        {
+            print_msg("You feel great.\n");
+        }
+        else
+        {
+            print_msg("You feel %sbetter.\n", amount > 10 ? "much " : "");
+        }
+    }
+    else
+    {
+        /* Update the display. */
+        display_update();
+    }
+}
+
+void notify_death(Death d, char const *what)
+{
+    print_msg("\n\nTHOU ART SLAIN!\n\n");
+    switch (d)
+    {
+    case DEATH_KILLED:
+        print_msg("You were killed by %s.\n", what);
+        break;
+    case DEATH_KILLED_MON:
+        print_msg("You were killed by a nasty %s.\n", what);
+        break;
+    case DEATH_BODY:
+        print_msg("Your heart was stopped by %s.\n", what);
+        break;
+    case DEATH_AGILITY:
+        print_msg("Your nerves were destroyed by %s.\n", what); 
+        break;
+    case DEATH_LASH:
+        print_msg("You tasted the lash one time too many.\n");
+        break;
+    case DEATH_RIBBONS:
+        print_msg("You looked good in ribbons.\n");
+        break;
+    }
+    print_msg("Your game lasted %d ticks.\n", game_tick);
+    print_msg("You killed monsters worth %d experience.\n", u.experience);
+}
+
 /*! \brief The player has gained a level
  */
 void notify_level_gain(void)
@@ -74,6 +124,30 @@ void notify_hp_gain(int amount)
     print_msg("You gained %d hit points.\n", amount);
 }
 
+void notify_body_restore(void)
+{
+    status_updated = 1;
+    print_msg("You feel less feeble.\n");
+}
+
+void notify_agility_restore(void)
+{
+    status_updated = 1;
+    print_msg("You feel less clumsy.\n");
+}
+
+void notify_agility_drain(int amount)
+{
+    status_updated = 1;
+    print_msg("You feel clumsy!\n");
+}
+
+void notify_body_drain(int amount)
+{
+    status_updated = 1;
+    print_msg("You feel weaker!\n");
+}
+
 void notify_player_teleport(void)
 {
     print_msg("You are whisked away!\n");
@@ -360,6 +434,86 @@ void notify_armour_equip(void)
     }
 }
 
+void notify_player_touch_effect(Damtyp dt)
+{
+    switch (dt)
+    {
+    default:
+    case DT_PHYS:
+        break;
+    case DT_FIRE:
+        print_msg("You are engulfed in flames.\n");
+        break;
+    case DT_COLD:
+        print_msg("You are covered in frost.\n");
+        break;
+    case DT_NECRO:
+        print_msg("You feel your life force slipping away.\n");
+        break;
+    case DT_ELEC:
+        print_msg("Your muscles spasm agonizingly.\n");
+        break;
+    }
+}
+
+void notify_player_damage_taken(int amount)
+{
+    print_msg("You take %d damage.\n", amount);
+}
+
+void notify_player_ignore_damage(Damtyp dt)
+{
+    switch (dt)
+    {
+    case DT_FIRE:
+        print_msg("The feel a pleasant warmth.\n");
+        break;
+    case DT_COLD:
+        print_msg("You feel a pleasant chill.\n");
+        break;
+    case DT_ELEC:
+        print_msg("You feel a pleasant tingle.\n");
+        break;
+    case DT_NECRO:
+        print_msg("You feel no deader than before.\n");
+        break;
+    case DT_DROWNING:
+        print_msg("TODO: Find a good way to express not-drowning.\n");
+        break;
+    case DT_POISON:
+        print_msg("You feel vaguely queasy for a moment.\n");
+        break;
+    default:
+        print_msg("BUG: You shouldn't be resisting damage type %d\n", (int) dt);
+        break;
+    }
+}
+
+void notify_item_explodes_flames(int obj)
+{
+    print_msg("The %s explodes in flames!\n", permobjs[objects[obj].obj_id].name);
+}
+
+void notify_read_scroll_protection(void)
+{
+    print_msg("You feel like something is helping you.\n");
+}
+
+void notify_dress_shredded(void)
+{
+    print_msg("Your dress has been reduced to a tattered wreck.\n");
+}
+
+void notify_eat_food(bool ravenous)
+{
+    print_msg(ravenous ? "You ravenously devour your food!\n" : "You eat some food.\n");
+}
+
+void notify_quaff_potion_restoration(void)
+{
+    print_msg("This potion makes you feel warm all over.\n");
+}
+
 /* Debugging notifications */
 
 void debug_bad_monspell(int spell)
@@ -422,5 +576,20 @@ void debug_put_on_uncarried_ring(void)
     print_msg("BUG: attempting to put on uncarried ring.\n");
 }
 
-/* display-nc.cc */
+void debug_read_non_scroll(void)
+{
+    print_msg("Impossible: reading non-scroll\n");
+}
+
+void debug_eat_non_food(int obj)
+{
+    print_msg("Error: attempt to eat non-food (%d)!\n", objects[obj].obj_id);
+}
+
+void debug_quaff_non_potion(void)
+{
+    print_msg("Impossible: quaffing non-potion\n");
+}
+
+/* notify-local-tty.cc */
 // vim:cindent
index 5139973..847f5e3 100644 (file)
--- a/notify.hh
+++ b/notify.hh
 #define NOTIFY_HH
 
 // Player status changes
+void notify_death(Death d, char const *what);
+void notify_player_heal(int amount, int boost, bool loud);
 void notify_level_gain(void);
 void notify_agility_gain(int amount);
 void notify_body_gain(int amount);
+void notify_agility_restore(void);
+void notify_body_restore(void);
+void notify_agility_drain(int amount);
+void notify_body_drain(int amount);
 void notify_hp_gain(int amount);
 void notify_player_teleport(void);
 void notify_player_telefail(void);
@@ -44,6 +50,8 @@ void notify_wither_recovered(void);
 void notify_protection_lost(void);
 void notify_wasted_gain(void);
 
+// Resistance notifications
+
 // Player movement notifications
 void notify_start_lavawalk(void);
 void notify_blocked_lava(void);
@@ -53,6 +61,7 @@ void notify_cant_go(void);
 
 // Unsorted notifications
 void notify_obj_at(Coord c);
+void notify_dress_shredded(void);
 
 // Item manipulation notifications
 void notify_magic_no_ring(void);
@@ -60,6 +69,14 @@ void notify_emanate_no_armour(void);
 void notify_zap_no_weapon(void);
 void notify_armour_equip(void);
 
+// Magic item use releated notifications
+void notify_read_scroll_protection(void);
+
+void notify_quaff_potion_restoration(void);
+
+void notify_item_explodes_flames(int obj);
+void notify_eat_food(bool ravenous);
+
 // combat notifications
 void notify_swing_bow(void);
 void notify_no_attackee(void);
@@ -74,6 +91,9 @@ void notify_player_shot_terrain(int obj, Coord c);
 void notify_mon_hit_armour(int mon);
 void notify_mon_missed_player(int mon);
 void notify_mon_hit_player(int mon);
+void notify_player_damage_taken(int amount);
+void notify_player_touch_effect(Damtyp dt);
+void notify_player_ignore_damage(Damtyp dt);
 
 // Sorcery notifications
 void notify_summon_help(int mon, bool success);
@@ -94,13 +114,15 @@ void debug_agility_gain(int amount);
 void debug_bad_monspell(int spell);
 void debug_player_resists_phys(void);
 void debug_bad_damage_type(int dt);
-void debug_throw_non_flask(void);
 void debug_unimplemented(void);
 void debug_wear_while_wearing(void);
 void debug_wear_uncarried_armour(void);
 void debug_remove_no_ring(void);
 void debug_put_on_second_ring(void);
 void debug_put_on_uncarried_ring(void);
+void debug_eat_non_food(int obj);
+void debug_read_non_scroll(void);
+void debug_quaff_non_potion(void);
 
 #endif
 
index d2ea374..aa843da 100644 (file)
@@ -64,22 +64,14 @@ Action_cost read_scroll(int obj)
         teleport_u();
         break;
     case PO_FIRE_SCROLL:
-        print_msg("The scroll explodes in flames!\n");
+        notify_item_explodes_flames(obj);
         if (u.resistances[DT_FIRE])
         {
-            if (objects[u.ring].obj_id == PO_FIRE_RING)
-            {
-                print_msg("Your ring glows, and the flames seem cool.\n");
-                break;
-            }
+            notify_player_ignore_damage(DT_FIRE);
         }
         else
         {
-            i = damage_u(dice(4, 10), DEATH_KILLED, "searing flames");
-            if (!i)
-            {
-                print_msg("That hurt!\n");
-            }
+            damage_u(dice(4, 10), DEATH_KILLED, "searing flames");
         }
         for (i = 0; i < MONSTERS_IN_PLAY; ++i)
         {
@@ -87,15 +79,15 @@ Action_cost read_scroll(int obj)
             {
                 if (!pmon_resists_fire(monsters[i].mon_id))
                 {
-                    print_mon_name(i, 3);
-                    print_msg(" is burned.\n");
+                    //print_mon_name(i, 3);
+                    //print_msg(" is burned.\n");
                     damage_mon(i, dice(4, 10), true);
                 }
             }
         }
         break;
     case PO_PROTECTION_SCROLL:
-        print_msg("You feel like something is helping you.\n");
+        notify_read_scroll_protection();
         if (!u.protection)
         {
             /* Do not prolong existing protection, only grant
@@ -104,22 +96,23 @@ Action_cost read_scroll(int obj)
         }
         if (u.withering)
         {
-            print_msg("Your limbs straighten.\n");
             u.withering = 0;
+            notify_wither_recovered();
         }
         if (u.armourmelt)
         {
-            print_msg("Your armour regains its strength.\n");
             u.armourmelt = 0;
+            notify_armourmelt_recovered();
         }
         if (u.leadfoot)
         {
-            print_msg("You shed your feet of lead.\n");
             u.leadfoot = 0;
+            notify_leadfoot_recovered();
         }
+        recalc_defence();
         break;
     default:
-        print_msg("Impossible: reading non-scroll\n");
+        debug_read_non_scroll();
         return Cost_none;
     }
     consume_obj(obj);
@@ -144,7 +137,7 @@ bool consume_obj(int obj)
                     objects[obj].used = true;
                     objects[obj].durability = 50 + zero_die(51);
                     objects[obj].obj_id = PO_RAGGED_SHIFT;
-                    print_msg("Your dress has been reduced to a tattered wreck.\n");
+                    notify_dress_shredded();
                 }
                 else
                 {
@@ -184,7 +177,7 @@ Action_cost eat_food(int obj)
     Obj *optr = objects + obj;
     if (permobjs[optr->obj_id].poclass != POCLASS_FOOD)
     {
-        print_msg("Error: attempt to eat non-food (%d)!\n", optr->obj_id);
+        debug_eat_non_food(obj);
         return Cost_none;
     }
     if (optr->obj_id == PO_DEVIL_SPLEEN)
@@ -198,14 +191,12 @@ Action_cost eat_food(int obj)
         {
             gain_agility(1);
         }
-    }
-    else if (u.food < 0)
-    {
-        print_msg("You ravenously devour your food!\n");
+        // TODO
+        // gain_power(Power_demonic);
     }
     else
     {
-        print_msg("You eat some food.\n");
+        notify_eat_food(u.food < 0);
     }
     u.food += 1500;
     status_updated = 1;
@@ -233,37 +224,21 @@ Action_cost quaff_potion(int obj)
         }
         break;
     case PO_RESTORATION_POTION:
-        print_msg("This potion makes you feel warm all over.\n");
+        notify_quaff_potion_restoration();
         status_updated = 1;
-        if (!zero_die(2))
+        if (u.bdam && ((!u.adam) || zero_die(2)))
         {
-            if (u.adam)
-            {
-                u.adam = 0;
-                print_msg("You feel less clumsy.\n");
-            }
-            else if (u.bdam)
-            {
-                u.bdam = 0;
-                print_msg("You feel less feeble.\n");
-            }
+            u.bdam = 0;
+            notify_body_restore();
         }
-        else
+        else if (u.adam)
         {
-            if (u.bdam)
-            {
-                u.bdam = 0;
-                print_msg("You feel less feeble.\n");
-            }
-            else if (u.adam)
-            {
-                u.adam = 0;
-                print_msg("You feel less clumsy.\n");
-            }
+            u.adam = 0;
+            notify_agility_restore();
         }
         break;
     default:
-        print_msg("Impossible: quaffing non-potion\n");
+        debug_quaff_non_potion();
         return Cost_none;
     }
     consume_obj(obj);
diff --git a/u.cc b/u.cc
index 931bdf6..910830d 100644 (file)
--- a/u.cc
+++ b/u.cc
@@ -202,7 +202,6 @@ int gain_body(int amount)
 
 int drain_body(int amount, char const *what, int permanent)
 {
-    print_msg("You feel weaker!\n");
     if (permanent)
     {
         u.body -= amount;
@@ -211,10 +210,9 @@ int drain_body(int amount, char const *what, int permanent)
     {
         u.bdam += amount;
     }
-    status_updated = 1;
+    notify_body_drain(amount);
     if ((u.body - u.bdam) < 0)
     {
-        print_msg("Your heart is too weak to beat.\n");
         return do_death(DEATH_BODY, what);
     }
     display_update();
@@ -242,14 +240,13 @@ int gain_agility(int amount)
     }
     else
     {
-        print_msg("You feel disappointed.\n");
+        notify_wasted_gain();
         return 0;
     }
 }
 
 int drain_agility(int amount, char const *what, int permanent)
 {
-    print_msg("You feel clumsy!\n");
     if (permanent)
     {
         u.agility -= amount;
@@ -258,10 +255,9 @@ int drain_agility(int amount, char const *what, int permanent)
     {
         u.adam += amount;
     }
-    status_updated = 1;
+    notify_agility_drain(amount);
     if ((u.agility - u.adam) < 0)
     {
-        print_msg("You forget how to breathe.\n");
         return do_death(DEATH_AGILITY, what);
     }
     recalc_defence();
@@ -272,6 +268,7 @@ int damage_u(int amount, Death d, char const *what)
 {
     u.hpcur -= amount;
     status_updated = 1;
+    notify_player_damage_taken(amount);
     if (u.hpcur < 0)
     {
         u.hpcur = 0;
@@ -286,115 +283,47 @@ void heal_u(int amount, int boost, int loud)
     {
         if (boost)
         {
+            boost = 1;
             u.hpmax++;
         }
         amount = u.hpmax - u.hpcur;
     }
-    u.hpcur += amount;
-    /* Touch the status line */
-    status_updated = 1;
-    if (loud)
-    {
-        /* Tell the player how much better they feel. */
-        if (u.hpcur == u.hpmax)
-        {
-            print_msg("You feel great.\n");
-        }
-        else
-        {
-            print_msg("You feel %sbetter.\n", amount > 10 ? "much " : "");
-        }
-    }
     else
     {
-        /* Update the display. */
-        display_update();
+        boost = 0;
+        u.hpcur += amount;
     }
+    notify_player_heal(amount, boost, loud);
     return;
 }
 
 int do_death(Death d, char const *what)
 {
-    // GRATIUTOUS INITIALIZATION: The idiot bastard compiler's inadequate
-    // control flow analysis shits itself when using debuild/dh's default
-    // CXXFLAGS settings.
-    FILE *fp = 0;
-    int really = 0;
+    bool really = true;
 
     if (wizard_mode)
     {
-        really = getyn("Really die? ");
-        if (really != 1)
-        {
-            u.hpcur = u.hpmax;
-            u.adam = 0;
-            u.bdam = 0;
-            status_updated = 1;
-            print_msg("You survived that attempt on your life.");
-            return 0;
-        }
+        really = query_wizmode_death();
     }
-    if (!wizard_mode)
+    if (!really)
     {
-        fp = fopen("victrix-abyssi.log", "a");
+        heal_u(1000, 0, true);
+        u.adam = 0;
+        u.bdam = 0;
+        recalc_defence();
+        status_updated = 1;
+        display_update();
     }
-    print_msg("\n\nTHOU ART SLAIN!\n\n");
-    game_finished = 1;
-    switch (d)
+    else
     {
-    case DEATH_KILLED:
-        print_msg("You were killed by %s.\n", what);
-        if (!wizard_mode)
-        {
-            fprintf(fp, "%s was killed by %s.\n", u.name, what);
-        }
-        break;
-    case DEATH_KILLED_MON:
-        print_msg("You were killed by a nasty %s.\n", what);
-        if (!wizard_mode)
-        {
-            fprintf(fp, "%s was killed by a nasty %s.\n", u.name, what);
-        }
-        break;
-    case DEATH_BODY:
-        print_msg("Your heart was stopped by %s.\n", what);
-        if (!wizard_mode)
-        {
-            fprintf(fp, "%s's heart was stopped by %s.\n", u.name, what);
-        }
-        break;
-    case DEATH_AGILITY:
-        print_msg("Your nerves were destroyed by %s.\n", what); 
+        game_finished = 1;
         if (!wizard_mode)
         {
-            fprintf(fp, "%s's nerves were destroyed by %s.\n", u.name, what); 
+            log_death(d, what);
         }
-        break;
-    case DEATH_LASH:
-        print_msg("You tasted the lash one time too many.\n");
-        if (!wizard_mode)
-        {
-            fprintf(fp, "%s tasted the lash one time too many.\n", u.name);
-        }
-        break;
-    case DEATH_RIBBONS:
-        print_msg("You looked good in ribbons.\n");
-        if (!wizard_mode)
-        {
-            fprintf(fp, "%s looked good in ribbons.\n", u.name);
-        }
-        break;
+        notify_death(d, what);
     }
-    if (!wizard_mode)
-    {
-        fprintf(fp, "    %s died after %d ticks, with %d XP, on dungeon level %d.\n\n", u.name, game_tick, u.experience, depth);
-        fflush(fp);
-        fclose(fp);
-    }
-    print_msg("Your game lasted %d ticks.\n", game_tick);
-    print_msg("You killed monsters worth %d experience.\n", u.experience);
-
-    return 1;
+    return really;
 }
 
 void write_char_dump(void)
@@ -427,46 +356,16 @@ void write_char_dump(void)
     fclose(fp);
 }
 
-void u_init(void)
+void u_init(char const *name)
 {
-    char * hasslash = NULL;
-    int i;
-    u.name[16] = '\0';
-    do {
-        print_msg("What is your name, stranger?\n");
-        i = read_input(u.name, 16);
-        if (i == 0)
-        {
-            /* Default name is Matilda, in honour of Matilda of England
-             * (aka Empress Matilda) and of Matilda di Canossa, Margravine
-             * regnant of Tuscany. */
-            strcpy(u.name, "Matilda");
-        }
-        else
-        {
-            hasslash = strchr(u.name, '/');
-            /* Now that we create a named dump file, we must not
-             * permit the player's name to contain a slash, colon,
-             * or backslash. */
-            if (hasslash)
-            {
-                print_msg("No slashes permitted.\n");
-                continue;
-            }
-            hasslash = strchr(u.name, '\\');
-            if (hasslash)
-            {
-                print_msg("No backslashes permitted.\n");
-                continue;
-            }
-            hasslash = strchr(u.name, ':');
-            if (hasslash)
-            {
-                print_msg("No colons permitted.\n");
-                continue;
-            }
-        }
-    } while (hasslash != NULL);
+    if (!name || !*name)
+    {
+        strcpy(u.name, "Matilda");
+    }
+    else
+    {
+        strncpy(u.name, name, 16);
+    }
     u.body = 10;
     u.bdam = 0;
     u.agility = 10;
index ce8c7de..70e87a6 100644 (file)
@@ -102,7 +102,8 @@ enum Gamecolour
 /* XXX enum damtyp - types of damage. */
 enum Damtyp {
     DT_PHYS = 0, DT_COLD, DT_FIRE, DT_NECRO,
-    DT_ELEC, DT_POISON, DT_KNOCKBACK, DT_DROWNING
+    DT_ELEC, DT_HELLFIRE, DT_POISON,
+    DT_KNOCKBACK, DT_DROWNING
 };
 #define DT_COUNT (1 + DT_DROWNING)
 
@@ -203,6 +204,8 @@ extern int game_tick;
 extern bool wizard_mode;
 extern void wrapped_system(char const *cmd);
 extern void wrapped_fread(void *buf, size_t size, size_t nmemb, FILE *stream);
+extern void new_game(char const *name);
+extern int load_game(void);
 
 /* XXX misc.c data and funcs */
 extern char const *damtype_names[DT_COUNT];
@@ -212,8 +215,10 @@ extern bool po_is_stackable(int po);
 extern void damage_obj(int obj);
 extern int evasion_penalty(int obj);
 
+/* XXX  log.cc */
+void log_death(Death d, char const *what);
 /* XXX u.c data and funcs */
-extern void u_init(void);
+extern void u_init(char const *name);
 extern void write_char_dump(void);
 extern int do_death(Death d, char const *what);
 extern void heal_u(int amount, int boost, int loud);