7f6bce6439b469d01b1cc9b1d28fdbc1efd6acb7
[roguelike.git] / creature.py
1 #! /usr/bin/env python
2 # -*- coding: utf-8 -*-
3
4 # Copyright © 2008 Neil Moore <neil@s-z.org>.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #  
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 import random
21
22 import loc
23 import thing
24 import ui
25
26 slotabbrevs = { 'hand': 'W', 'arm': 'A', 'body': 'B', 'head': 'H' }
27
28 class Creature(thing.Thing):
29     def __init__(self, location=None):
30         thing.Thing.__init__(self, location)
31
32         self.dead = False
33         self.hpmax = 10
34         self.hp = self.hpmax
35         self.oxygen = 10
36
37         self.inv = loc.Inventory(self)
38         self.slots = { 'hand': None, 'arm': None, 'body': None, 'head': None }
39     def holding(self, name):
40         return self.slots[name]
41     def is_wielding(self, item):
42         return item in self.slots
43     def invalidate(self):
44         if self.location is not None:
45             self.location.invalidate(important = True)
46     def vis_radius(self):
47         return 5
48     def can_see(self, y, x):
49         loc = self.location
50         if (y - loc.y)**2 + (x - loc.x)**2 <= self.vis_radius()**2:
51             return self.level().visible_path(loc.y, loc.x, y, x)
52         return False
53     def visibles(self):
54         vis = []
55         py = self.location.y
56         px = self.location.x
57         rad = self.vis_radius()
58         (ymin,xmin) = self.level().clip(py - rad, px - rad)
59         (ymax,xmax) = self.level().clip(py + rad, px + rad)
60         for y in range(ymin, ymax+1):
61             for x in range(xmin, xmax+1):
62                 if self.can_see(y,x):
63                     vis.append((y,x))
64         return vis
65
66     def is_creature(self):
67         return True
68
69     def can_breathe(self):
70         if isinstance(self.location, loc.Water):
71             # Check for water breathing
72             return False
73         else:
74             return True
75
76     def breathe(self):
77         if self.can_breathe():
78             if self.oxygen < 10:
79                 self.oxygen += 1
80         else:
81             if self.oxygen > 0:
82                 self.oxygen -= 1
83             else:
84                 self.losehp(1, "asphyxia")
85
86     def losehp(self, n, cause):
87         if n >= self.hp:
88             self.die(cause)
89         else:
90             self.hp -= n
91
92     def die(self, cause):
93         self.dead = cause
94         self.place(None)
95
96     def can_swim(self):
97         return False
98     def render(self, pic=None):
99         return ( "?", ui.Color('BrightMagenta').cp )
100     def move_north(self):
101         return self.try_move(self.location.north())
102     def move_south(self):
103         return self.try_move(self.location.south())
104     def move_west(self):
105         return self.try_move(self.location.west())
106     def move_east(self):
107         return self.try_move(self.location.east())
108     def pick_up(self):
109         it = self.location.top_item()
110         if it:
111             it.try_move(self.inv)
112             return True
113         else:
114             return False
115     def wield(self, item):
116         assert item in self.inv, (
117                 "%s is wielding item %s not in inventory" % (self, item))
118         assert item.wieldable(), (
119                 "%s trying to wield the unwieldable %s" % (self, item))
120         assert not item.wielded, (
121                 "%s trying to wield %s, already wielded by %s"
122                 % (self, item, item.wielded))
123         slot = item.slot
124         if self.holding(slot):
125             self.unwield(self.holding(slot))
126         self.slots[slot] = item
127         item.wielded = (self, slot)
128         return True
129
130     def unwield(self, item):
131         assert item in self.inv, (
132                 "%s is unwielding item %s not in inventory" % (self, item))
133         assert item.wielded, (
134                 "%s trying to unwield already unwielded %s" % (self, item))
135
136         (creat, slot) = item.wielded
137         assert creat is self, "%s unwielding %s's %s" % (self, creat, item)
138         assert self.holding(slot) is item, (
139                 "%s unwielding %s from wrong hand %s?" % (self, item, slot))
140
141         item.wielded = None
142         self.slots[slot] = None
143         return True
144
145 class Player(Creature):
146     def __init__(self, location=None):
147         Creature.__init__(self, location)
148         self.active = False
149     def render(self, pic=None):
150         return ("@", ui.Color(('Bright' if self.active else '') + 'Magenta').cp)
151     def can_swim(self):
152         return random.random() < .5