Commits

Patrick Dawson committed df3f05c

.

Comments (0)

Files changed (3)

     def __init__(self, fort):
         self.fort = fort
         self.img = None
+        self.tag = None
     def turn(self):
         pass
     
     def __init__(self, fort):
         self.fort = fort
         self.img = IL("plot_farm")
+        self.tag = FARM
     def turn(self):
         self.fort.res[FOOD] += 5
 
 class Barracks(Building):
     def __init__(self, fort):
         self.fort = fort
-        self.img = IL("plot_barracks")        
+        self.img = IL("plot_barracks")
+        self.tag = BARRACKS
     def turn(self):
         pass
     
         Character.__init__(self)
         self.name = "Militia"
         self.img = IL("militia")
+        self.tag = MILITIA
         self.hp = 6 # level 1 fighter
-        self.ac = 13 # leather
+        self.ac = 12 # leather
         self.dmg = (1,6) # short spear
         self.ab = 1
         self.str = 1
         Character.__init__(self)
         self.name = "Infantry"
         self.img = IL("infantry")
-        self.hp = 12 # level 2 fighter
-        self.ac = 16 # chainmail + shield
-        self.dmg = (1,8) # longsword
+        self.tag = INFANTRY
+        self.hp = 12
+        self.ac = 15
+        self.dmg = (1,8)
         self.ab = 2
         self.str = 2
         self.dex = 1
         Character.__init__(self)
         self.name = "Archer"
         self.img = IL("archer")
-        self.hp = 6
-        self.ac = 13
+        self.tag = ARCHER
+        self.hp = 8
+        self.ac = 12
         self.dmg = (1,8)
         self.ab = 1
         self.str = 0
         self.dex = 2
         
+class ArcherOnWall(Archer):
+    def __init__(self):
+        Archer.__init__(self)
+        self.name = "Archer-on-Wall"
+        self.ac = 14
+        self.dmg = (1,8,1)
+        self.ab = 3
+        
 class EnemyMilitia(Militia):
     def __init__(self):
         Militia.__init__(self)
         self.img = IL("enemy_militia")
         self.enemy = True
 
-class EnemyInfantry(Militia):
+class EnemyInfantry(Infantry):
     def __init__(self):
         Infantry.__init__(self)
         self.name = "Enemy Infantry"
         self.img = IL("enemy_infantry")
         self.enemy = True
 
-class EnemyArcher(Militia):
+class EnemyArcher(Archer):
     def __init__(self):
         Archer.__init__(self)
         self.name = "Enemy Archer"
 
 class GameEvents(object):
     attack = {
-        2 : [(EnemyMilitia,2)],
-        8 : [(EnemyMilitia,2),(EnemyArcher,2)],
-        12 : [(EnemyMilitia,2),(EnemyArcher,2),(EnemyInfantry,2)],
-        19 : [(EnemyMilitia,0),(EnemyArcher,4),(EnemyInfantry,6)],
+        5 : [(EnemyMilitia,2)],
+        9 : [(EnemyMilitia,2),(EnemyArcher,2)],
+        13 : [(EnemyMilitia,2),(EnemyArcher,2),(EnemyInfantry,1)],
+        16 : [(EnemyMilitia,2),(EnemyArcher,2),(EnemyInfantry,2)],
+        20 : [(EnemyMilitia,0),(EnemyArcher,4),(EnemyInfantry,6)],
     }
     win_turn = 21
 
             (BUILD,WALLS) : (WOOD,50),
             (TRAIN,MILITIA) : (FOOD,10),
             (TRAIN,INFANTRY) : (FOOD,25),
-            (TRAIN,ARCHER) : (FOOD,20),
+            (TRAIN,ARCHER) : (FOOD,15),
             (TRAIN,WORKER) : (FOOD,30),
         }
         self.gather = {
         self.free_plots = 6
         for b in self.buildings:
             self.free_plots -= 1
-            if type(b) == Barracks:
+            if b.tag == BARRACKS:
                 self.free_barracks += 1
         
         for task,arg in self.tasks:
         if self.turn in GameEvents.attack:
             self.start_battle(GameEvents.attack[self.turn])
         elif self.turn == GameEvents.win_turn:
-            for o in self.fort_observers:
-                o.fort_win()
+            self.fort_observer.fort_win()
             
     def start_battle(self, enemy_force):
         self.battle = Battle(self.battle_observer)
                 elif ptype == INFANTRY:
                     self.battle.defenders.append(Infantry())
                 elif ptype == ARCHER:
-                    self.battle.defenders.append(Archer())
+                    if self.walls is not None:
+                        self.battle.defenders.append(ArcherOnWall())
+                    else:
+                        self.battle.defenders.append(Archer())
 
         self.fort_observer.fort_start_battle()
         self.battle_observer.battle_start()
         self.observer = obs
         
     def tick(self):
+        if len(self.defenders) == 0:
+            self.observer.battle_lost()
+            return
+        elif len(self.attackers) == 0:
+            self.observer.battle_won()
+            return
+        
         if len(self.initiative) == 0:
             self._roll_initiative()
-            print self.initiative
         src = self.initiative.pop()[0]
         if src.hp > 0:
             tgt = self._pick_target(src)
-            self.observer.battle_miss(src,tgt)
+            self._unit_attack(src,tgt)
+        else:
+            self.tick()
             
     def _pick_target(self, src):
         opp = None
         self.initiative = sorted(ilist, key=lambda tup: tup[1], reverse=True)
         
     def _unit_attack(self, src, tgt):
-        # roll hit
-        # roll damage
-        pass
+        # roll to-hit
+        r = roll(1,20) + src.ab + src.str
+        if r >= tgt.ac:
+            dmg = roll(*src.dmg)
+            self.observer.battle_hit(src,tgt,dmg)
+            print '%s at %s hit for %d' % (tgt,tgt.pos,dmg)
+            tgt.hp -= dmg
+            if tgt.hp <= 0:
+                print '%s at %s died' % (tgt,tgt.pos)
+                if tgt in self.defenders:
+                    self.defenders.remove(tgt)
+                else:
+                    self.attackers.remove(tgt)
+                self.observer.battle_die(tgt)                
+        else:
+            self.observer.battle_miss(src,tgt)
+
+            
 ===============================================================================
-Fort in the Woods
+
+                           Fort in the Woods
+
 
 by Patrick Dawson <pat@dw.is>
 in Berlin, Germany
 for Ludum Dare 23, 2012-04-22
 ===============================================================================
 
+INTRODUCTION
 
-[intro text here]
-
-
-
+    You have been ordered to establish an outpost in enemy territory, a
+    safe haven for coordinating operations.
+    
+    After a few days of travel, your small, lightly equipped force finds a
+    spot hidden deep in the woods and clears the site.
+    
+    Now you must survive.
+    
+    Your fort will inevitably be discovered by enemy scouts, so train
+    additional troops to defend your position until reinforcements arrive.
+    
+    For 20 weeks, you're on your own.
 
 ===============================================================================
 
+TIPS
 
-[instructions + tips]
+    Farms produce 5 Food per turn.
 
-Farms produce 5 Food per turn.
+    You need a Barracks to train one military unit. Two Barracks let you train
+    two units per turn, etc.
 
-You need a Barracks to train one unit. Two Barracks let you train two units
-per turn, etc.
+    Walls give archers a bonus to attack and defense.
 
-
-
+    Combat is automated; you can only watch.
 
 ===============================================================================
 
-Tools used:
-- Editra
-- Paint.NET
-- sfxr
+ADDITIONAL CREDITS
 
-Libraries used:
-- PyGame <http://pygame.org>
-- sgc <https://launchpad.net/simplegc>
+    Tools used:
+    - Editra
+    - Paint.NET
+    - sfxr
 
-Other:
-- combat rules inspired by Basic Fantasy RPG <http://basicfantasy.org/>
+    Libraries used:
+    - PyGame <http://pygame.org>
+    - sgc <https://launchpad.net/simplegc>
+
+    Other:
+    - combat rules inspired by Basic Fantasy RPG <http://basicfantasy.org/>
 ===============================================================================
 from game import *
 from functools import partial
 from random import choice, randint
+import time
 
-FORT = Fort()
+FORT = None
 
 class Screen(object):
     def __init__(self, sm):
     def __init__(self, surface):
         self.screen = None
         self.surface = surface
+        self.reset()
+        
+    def reset(self):
+        global FORT
+        FORT = Fort()
+
         self.screen_cache = {
             MenuScreen : MenuScreen(self),
             IntroScreen : IntroScreen(self),
             BattleScreen : BattleScreen(self),
             WinScreen : WinScreen(self),
             LoseScreen : LoseScreen(self),
-        }
+        }        
         
     def change(self, new_screen):
         if self.screen is not None:
         Screen.__init__(self, sm)
         
         mytxt = """
-        You have been ordered to establish an outpost in enemy territory. Your
-        small, lightly equipped force finds a spot hidden deep in the woods and
-        clears the site.
+        You have been ordered to establish an outpost in enemy territory, a
+        safe haven for coordinating operations.
         
-        Now you must survive. Build farms or hunt to feed everyone, and train
-        troops to fend off attacks from enemy scouting parties.
+        After a few days of travel, your small, lightly equipped force finds a
+        spot hidden deep in the woods and clears the site.
         
-        Survive for 20 weeks until reinforcements arrive.
+        Now you must survive.
+        
+        Your fort will inevitably be discovered by enemy scouts, so train
+        additional troops to defend your position until reinforcements arrive.
+        
+        For 20 weeks, you're on your own.
         """
         
         self.txt = sgc.widgets.Label(text=mytxt, font=FC('Artifika-Regular', 16), pos=(100,200))
         self.add(self.txt)
         
-        self.btn_continue = MyButton(label="Continue", pos=(500,400))
+        self.btn_continue = MyButton(label="Continue")
+        self.btn_continue.rect.bottomright = (1024-100,768-100)
         self.btn_continue.click = self.clickContinue
         self.add(self.btn_continue)
         
         Screen.__init__(self, sm)
         
         mytxt = """
-        You have failed.
+        You have failed. Your fort is overrun.
         """
         
         self.txt = sgc.widgets.Label(text=mytxt, font=FC('Artifika-Regular', 16), pos=(200,200))
         self.add(self.txt)
+        
+        self.btn = MyButton(label="Try Again")
+        self.btn.rect.bottomright = (1024-100,768-100)
+        self.btn.click = self.clickTryAgain
+        self.add(self.btn)
+        
+    def clickTryAgain(self):
+        self.sm.reset()
+        self.sm.change(IntroScreen)
 
 class WinScreen(Screen):
     def __init__(self, sm):
         Screen.__init__(self, sm)
         
         mytxt = """
-        You have won.
+        You've managed to hold out long enough for reinforcements to arrive.
         """
         
         self.txt = sgc.widgets.Label(text=mytxt, font=FC('Artifika-Regular', 16), pos=(200,200))
         self.add(self.txt)
 
+        self.btn = MyButton(label="Quit")
+        self.btn.rect.bottomright = (1024-4,768-4)
+        self.btn.click = sys.exit
+        self.add(self.btn)
 
 class BattleScreen(Screen):
     def __init__(self, sm):
                 
         self.txt = TextLog(pos=(64,600))
         self.add(self.txt)
+        self._delayed_death = None # ugly hack
         
         FORT.battle_observe(self)
         
     def battle_start(self):
         self.txt.clear()
         self.txt.addLine('Combat begins!')
+        self.bf.start()
         self.bf.draw_canvas()
         
     def battle_hit(self, src, tgt, dmg):
         else:
             AudioMixer.play('hit1')
         self.bf.hit(src,tgt,dmg)
+        self.sm.surface.blit(self.bf.canvas, (64,8))
     
     def battle_miss(self, src, tgt):
         self.txt.addLine('%s misses!' % src)
         self.bf.miss(src,tgt)
     
     def battle_die(self, tgt):
-        pass
+        self._delayed_death = tgt
+        
+    def _battle_die(self, tgt):
+        self.txt.addLine('%s died!' % tgt)
+        if tgt.enemy:
+            AudioMixer.play('die1')
+        else:
+            AudioMixer.play('die2')
+            FORT.pop[tgt.tag] -= 1
+        self.bf.die(tgt)
     
     def battle_won(self):
         self.sm.change(FortScreen)
     def update(self, dt):
         self.sm.surface.blit(self.bf.canvas, (64,8))
         self.t += dt
-        if self.t >= 1000:
+        if self.t >= 750:
             self.t = 0
-            FORT.battle.tick()
+            if self._delayed_death is not None:
+                self._battle_die(self._delayed_death)
+                self._delayed_death = None
+            else:
+                FORT.battle.tick()
 
 
 class Battlefield(object):
     def hit(self, src, tgt, dmg):
         self.draw_canvas()
         self.canvas.blit(IL("unit_yellow"), (src.pos[0]*64,src.pos[1]*64))
-        self.canvas.blit(IL("unit_red"), (tgt.pos[0]*64,tgt.pos[1]*64))
+        #self.canvas.blit(IL("unit_red"), (tgt.pos[0]*64,tgt.pos[1]*64))
         self.canvas.blit(ImageLoader.damage(dmg), (tgt.pos[0]*64,tgt.pos[1]*64))
         
     def miss(self, src, tgt):
         self.draw_canvas()
         self.canvas.blit(IL("unit_yellow"), (src.pos[0]*64,src.pos[1]*64))
-        self.canvas.blit(IL("unit_red"), (tgt.pos[0]*64,tgt.pos[1]*64))
+        #self.canvas.blit(IL("unit_red"), (tgt.pos[0]*64,tgt.pos[1]*64))
+        
+    def die(self, tgt):        
+        self.draw_canvas()
+        
+    def start(self):
+        # deploy defenders
+        aslot = 0
+        fslot = 0
+        for d in FORT.battle.defenders:
+            pos = None
+            if d.tag == ARCHER:
+                pos = self.archer_slots[aslot]
+                aslot += 1
+            else:
+                pos = self.foot_slots[fslot]
+                fslot += 1
+            
+            d.pos = pos
+            
+        # deploy attackers
+        eslot = 0
+        for e in FORT.battle.attackers:
+            pos = self.enemy_slots[eslot]
+            eslot += 1
+            
+            e.pos = pos
         
     def draw_canvas(self):
         self.canvas.fill((100,100,100))
                         
                         
     def blit_defenders(self):
-        aslot = 0
-        fslot = 0
         for d in FORT.battle.defenders:
-            pos = None
-            if type(d) == Archer:
-                pos = self.archer_slots[aslot]
-                aslot += 1
-            else:
-                pos = self.foot_slots[fslot]
-                fslot += 1
-            
-            d.pos = pos
-            self.canvas.blit(d.img, (pos[0]*64,pos[1]*64))
+            self.canvas.blit(d.img, (d.pos[0]*64,d.pos[1]*64))
     
     def blit_attackers(self):
-        eslot = 0
-        for e in FORT.battle.attackers:
-            pos = self.enemy_slots[eslot]
-            eslot += 1
-            
-            e.pos = pos
-            self.canvas.blit(e.img, (pos[0]*64,pos[1]*64))
-                        
-                        
-        """                        
-        for pos in self.archer_slots:
-            self.canvas.blit(IL("archer"), (pos[0]*64,pos[1]*64))
-        for pos in self.foot_slots:
-            self.canvas.blit(IL("infantry"), (pos[0]*64,pos[1]*64))
-            
-        for n in range(3):
-            pos = choice(self.foot_slots)
-            self.canvas.blit(ImageLoader.damage(randint(6,15)), (pos[0]*64,pos[1]*64))
-            
-        pos = choice(self.enemy_slots)
-        self.canvas.blit(IL("unit_yellow"), (pos[0]*64,pos[1]*64))
-        
-        pos = choice(self.foot_slots)
-        self.canvas.blit(IL("unit_red"), (pos[0]*64,pos[1]*64))
-            
-        elist = [IL("enemy_militia"), IL("enemy_infantry"), IL("enemy_archer")]
-        for pos in self.enemy_slots:
-            self.canvas.blit(choice(elist), (pos[0]*64,pos[1]*64))
-        """
+        for a in FORT.battle.attackers:
+            self.canvas.blit(a.img, (a.pos[0]*64,a.pos[1]*64))
 
 
 class FortScreen(Screen):
         self.update_buttons()
         FORT.fort_observe(self)
         
+    def show(self):
+        Screen.show(self)
+        self.rd.blit_resources()
+        self.fs.draw_canvas()
+        self.update_buttons()        
+
+        
     def update_buttons(self):
         for btn, targs in self.task_map.items():
             if FORT.task_possible(*targs):
     def _doTask(self, task, arg=None):
         ok = FORT.assign(task, arg)
         if ok:
-            print 'ok'
             self.rd.blit_resources()
             self.fs.draw_canvas()
             self.update_buttons()
         FORT.next_turn()
         self.rd.blit_resources()
         self.fs.draw_canvas()
-        self.update_buttons()        
+        self.update_buttons()
         
     def fort_start_battle(self):
         self.sm.change(BattleScreen)
         
         self.canvas.blit(IL("log"), (0,64+16))
         self.canvas.blit(self.lbl_wood, (64,64+16))
-        print 'wood=', FORT.res[WOOD]
         wnum = self.nfont.render(str(FORT.res[WOOD]), True, WHITE)
         self.canvas.blit(wnum, (64+16, 64+16+24))