Commits

Peter Ward committed 52f4b56

make monsters attack people

  • Participants
  • Parent commits da43d4b

Comments (0)

Files changed (4)

+from gestures import GestureHandler
+from spells import SEQUENCES
+
+class Being(object):
+    def __init__(self, engine, name):
+        super(Being, self).__init__()
+        self.engine = engine
+        self.name = name
+
+    defense = 0
+    health = 0
+
+    def attack(self, strength):
+        self.engine.log('%s is attacked with %d strength' % (self, strength))
+        strength -= self.defense
+        if strength > 0:
+            self.health -= strength
+
+    def add_effect(self, on_start, time, on_finish):
+        self.engine.add_effect(on_start, time, on_finish)
+
+    def add_behaviour(self, func, delay_ms, precise=False):
+        self.engine.add_behaviour(self, func, delay_ms, precise)
+
+    _health = 0
+
+    def get_health(self):
+        return self._health
+
+    def set_health(self, health):
+        diff = health - self._health
+        if diff < 0:
+            self.engine.log('%s looses %d health' % (self, -diff))
+        elif diff != 0:
+            self.engine.log('%s gains %d health' % (self, diff))
+
+        self._health = health
+
+        health = max(health, 0)
+        if health == 0:
+            self.engine.log('%s has died' % self)
+            self.engine.remove(self)
+
+    health = property(get_health, set_health)
+
+class Warlock(Being):
+    _health = 20
+
+    def __init__(self, engine, name):
+        super(Warlock, self).__init__(engine, name)
+
+        self.sequences = SEQUENCES
+        self.gestures = GestureHandler(self.sequences)
+        self.current_target = None
+
+    def cast(self, spell, hand):
+        self.engine.cast(self, spell, self.current_target)
+
+    def __str__(self):
+        return self.name
+
+class Monster(Being):
+    def __init__(self, engine, name, strength):
+        super(Monster, self).__init__(engine, name)
+        self.strength = self._health = strength
+
+        self.add_behaviour(self.on_attack, 1000)
+
+    def on_attack(self):
+        target = self.engine.choose_random_enemy(self)
+        if target is None:
+            self.engine.log('%s wanders around aimlessly' % self)
+        else:
+            target.attack(self.strength)
+        return True
+
+    def __str__(self):
+        return self.name
-from gestures import GestureHandler
-from spells import SEQUENCES
+from collections import defaultdict
+from random import choice
 
-from random import choice
+# urwid.GLibEventLoop is using this binding
+import gobject
+
+from beings import Warlock, Monster
 
 WARLOCK_NAMES = ['Bob', 'Ivan', 'Ogden', 'Karth', 'Tiberius']
 MONSTER_NAMES = ['Kraw', 'Fingle', 'Fang', 'Darth']
 
-class Being(object):
-    def __init__(self, engine, name):
-        super(Being, self).__init__()
-        self.engine = engine
-        self.name = name
-
-    defense = 0
-    health = 0
-
-    def attack(self, strength):
-        self.engine.log('%s is attacked with %d strength' % (self, strength))
-        strength -= self.defense
-        if strength > 0:
-            self.health -= strength
-
-    def add_effect(self, on_start, time, on_finish):
-        self.engine.add_effect(on_start, time, on_finish)
-
-    _health = 0
-
-    def get_health(self):
-        return self._health
-
-    def set_health(self, health):
-        diff = health - self._health
-        if diff < 0:
-            self.engine.log('%s looses %d health' % (self, -diff))
-        elif diff != 0:
-            self.engine.log('%s gains %d health' % (self, diff))
-
-        self._health = health
-
-        health = max(health, 0)
-        if health == 0:
-            self.engine.log('%s has died' % self)
-            self.engine.remove(self)
-
-    health = property(get_health, set_health)
-
-class Warlock(Being):
-    _health = 20
-
-    def __init__(self, engine, name):
-        super(Warlock, self).__init__(engine, name)
-
-        self.sequences = SEQUENCES
-        self.gestures = GestureHandler(self.sequences)
-        self.current_target = None
-
-    def cast(self, spell, hand):
-        self.engine.cast(self, spell, self.current_target)
-
-    def __str__(self):
-        return self.name
-
-class Monster(Being):
-    def __init__(self, engine, name, strength):
-        super(Monster, self).__init__(engine, name)
-        self.strength = self._health = strength
-
-    def __str__(self):
-        return self.name
+def emit(handlers, *args):
+    return [
+        handler(*args)
+        for handler in handlers
+    ]
 
 class Engine(object):
     def __init__(self):
         self.sources = []
+        self.source_behaviours = defaultdict(list)
         self.effects = []
 
         self._log = []
 
+        self.on_update = []
+
     def add_warlock(self, name=None):
         if name is None:
             name = choice(WARLOCK_NAMES)
         self.log('%s cast %s at %s.' % (source, spell.name, target))
         spell(target)
 
+    def add_behaviour(self, source, func, delay_ms, precise=False):
+        '''
+        Add a function to be called every delay_ms while the source is able to
+        perform actions and not, for example, frozen due to a time stop.
+        '''
+        # currently, we don't have time stop, so we don't need that logic
+        if delay_ms % 1000 == 0 and not precise:
+            id = gobject.timeout_add_seconds(delay_ms / 1000, func)
+        else:
+            id = gobject.timeout_add(delay_ms, func)
+        self.source_behaviours[source].append(id)
+
     def log(self, message):
         self._log.append(message)
+        emit(self.on_update)
+
             for source in engine.sources
         )
     )
-
     gestures.set_text(str(player.gestures))
-
-    log.set_text('\n'.join(engine._log))
+    log.set_text('\n'.join(reversed(engine._log)))
 
 players = urwid.Text('')
 gestures = urwid.Text('')
 fill = urwid.Filler(pile, valign='top')
 
 update_display()
-loop = urwid.MainLoop(fill, unhandled_input=handle_input)
-loop.run()
+engine.on_update.append(
+    lambda: (update_display(), app.draw_screen())
+)
+
+event_loop = urwid.GLibEventLoop()
+app = urwid.MainLoop(
+    fill,
+    unhandled_input=handle_input,
+    event_loop=event_loop,
+)
+app.run()
         return fn
     return deco
 
-@spell('SD', 'Magic Missile', TARGET_SELF)
+@spell('SD', 'Magic Missile', TARGET_ENEMY)
 def magic_missile(target):
     target.attack(1)