Hit points, oxygen, and death.
authorNeil Moore <neil@s-z.org>
Thu, 29 May 2008 05:28:24 +0000 (01:28 -0400)
committerNeil Moore <neil@s-z.org>
Thu, 29 May 2008 05:28:24 +0000 (01:28 -0400)
Change 'hand' slot abbreviation to 'W'.
Add new slot 'head' (abbreviated 'H').

Creatures have (by default) 10 HP, 10 max HP, and 10 rounds of oxygen.
Creatures have head slot by default.

New Creature methods:
  can_breathe(): can it breathe at the current location?
  breathe(): take a breath, or lose oxygen or HP.
  losehp(): lose HP and maybe die.
  die(): die (and relocate to nowhere).

Creature.invalidate: do nothing if we are nowhere.

New method AppUI.draw_stats to draw stats window with HP and oxygen.

New method AppUI.more to wait for the user to press space.

AppUI.message: clear the message area before writing a message.

thing.level(): return None if there is no location or level.

Update event loop:
  Draw stats.
  Have each player breathe.
  Check for dead players and remove them from the player list.

creature.py
roguelike.py
thing.py

index f2018b1..79c9f9f 100644 (file)
@@ -23,19 +23,26 @@ import loc
 import thing
 import ui
 
-slotabbrevs = { 'hand': 'H', 'arm': 'A', 'body': 'B' }
+slotabbrevs = { 'hand': 'W', 'arm': 'A', 'body': 'B', 'head': 'H' }
 
 class Creature(thing.Thing):
     def __init__(self, location=None):
         thing.Thing.__init__(self, location)
+
+        self.dead = False
+        self.hpmax = 10
+        self.hp = self.hpmax
+        self.oxygen = 10
+
         self.inv = loc.Inventory(self)
-        self.slots = { 'hand': None, 'arm': None, 'body': None }
+        self.slots = { 'hand': None, 'arm': None, 'body': None, 'head': None }
     def holding(self, name):
         return self.slots[name]
     def is_wielding(self, item):
         return item in self.slots
     def invalidate(self):
-        self.location.invalidate(important = True)
+        if self.location is not None:
+            self.location.invalidate(important = True)
     def vis_radius(self):
         return 5
     def can_see(self, y, x):
@@ -58,6 +65,30 @@ class Creature(thing.Thing):
 
     def is_creature(self):
         return True
+
+    def can_breathe(self):
+        return not isinstance(self.location, loc.Water)
+
+    def breathe(self):
+        if self.can_breathe():
+            if self.oxygen < 10:
+                self.oxygen += 1
+        else:
+            if self.oxygen > 0:
+                self.oxygen -= 1
+            else:
+                self.losehp(1, "asphyxia")
+
+    def losehp(self, n, cause):
+        if n >= self.hp:
+            self.die(cause)
+        else:
+            self.hp -= n
+
+    def die(self, cause):
+        self.dead = cause
+        self.place(None)
+
     def can_swim(self):
         return False
     def render(self, pic=None):
index cbffbf7..39adb8d 100755 (executable)
@@ -52,6 +52,14 @@ class AppUI:
         self.player = player
         self.invpanel.set_userptr(player.inv)
         self.set_level(player.level())
+    
+    def draw_stats(self):
+        pl = self.player
+        win = self.statpanel.window()
+        win.addstr(0, 1, "HP: %4d / %-4d   O2: %2d / 10"
+                % (pl.hp, pl.hpmax, pl.oxygen))
+        win.refresh()
+
 
     def __init__(self, stdscr, players):
         if AppUI.instance:
@@ -129,9 +137,8 @@ class AppUI:
 
     def message(self, msg=None):
         msgwin = self.msgpanel.window()
-        if msg == None:
-            msgwin.erase()
-        else:
+        msgwin.erase()
+        if msg is not None:
             msgwin.addnstr(0, 0, msg, self.scrw - 1, ui.Color('White').cp)
         msgwin.refresh()
 
@@ -146,6 +153,13 @@ class AppUI:
                     return None
         finally:
             self.message()
+    
+    def more(self):
+        try:
+            while self.mainpanel.window().getch() != curses.ascii.SP:
+                pass
+        finally:
+            self.message()
 
     def mapped(self, c):
         return self.keymap.has_key(c) and self.commands.has_key(self.keymap[c])
@@ -235,10 +249,10 @@ class AppUI:
             return False
         self.mainpanel.window().refresh()
         dirn = self.get_direction()
-        if dirn == None:
+        if dirn is None:
             return False
         dest = self.location().throwdest(dirn, it)
-        if dest == None:
+        if dest is None:
             return False
         it.place(dest)
         return True
@@ -254,14 +268,14 @@ class AppUI:
 
     def try_open(self):
         dirn = self.get_direction()
-        if dirn == None:
+        if dirn is None:
             return False
         loc = self.location().dir(dirn, 1)
         return loc.open()
 
     def try_close(self):
         dirn = self.get_direction()
-        if dirn == None:
+        if dirn is None:
             return False
         loc = self.location().dir(dirn, 1)
         return loc.close()
@@ -313,6 +327,7 @@ class AppUI:
     def event_loop(self):
         while 1:
             self.recenter()
+            self.draw_stats()
             self.level().draw()
             self.mainpanel.window().refresh()
             c = self.stdscr.getch()
@@ -325,6 +340,21 @@ class AppUI:
                 break
 
             self.level().affect_all()
+            dead = []
+            for pl in self.players:
+                pl.breathe()
+                if pl.dead:
+                    self.message("Player %s is dead: %s" % (pl, pl.dead))
+                    dead.append(pl)
+            for pl in dead:
+                self.players.remove(pl)
+            if len(self.players) == 0:
+                self.message("You have lost")
+                self.more()
+                return
+            elif len(dead) > 0:
+                self.switch()
+                    
 
 if __name__ == '__main__':
     def main(stdscr):
index 72cf2ad..f928878 100644 (file)
--- a/thing.py
+++ b/thing.py
@@ -135,7 +135,10 @@ class Thing (object):
     def is_scenery(self):
         return False
     def level(self):
-        return self.location.level()
+        try:
+            return self.location.level()
+        except AttributeError:
+            return None
     def place(self, location):
         if self.location is not None:
             self.location.remove(self)