Advertisement
Guest User

Untitled

a guest
Nov 12th, 2015
232
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 13.17 KB | None | 0 0
  1. import sys, platform, os
  2. import time, random, math
  3.  
  4. class STATE:
  5.     ALIVE = 'alive'
  6.     DEAD = 'dead'
  7.     #POISONED = 'poisoned'
  8.  
  9. class MOVE:
  10.     UP = 'up'
  11.     DOWN = 'down'
  12.     LEFT = 'left'
  13.     RIGHT = 'right'
  14.  
  15. class FLAG:
  16.     ATTACK = 'Error in attack method'
  17.     UPDATE = 'Error in update method'
  18.     CLEAR = 'Error in clear screen method'
  19.     VALID = 'Error in valid move method'
  20.     E_TURN = 'Error in enemy turn function'
  21.     P_TURN = 'Error in player turn function'
  22.  
  23. class Entity(object):
  24.     '''Basic entity object
  25.        Has position and character.'''
  26.     def __init__(self, name, x, y, hp, strength, speed, char, state=STATE.ALIVE):
  27.         self.name = name
  28.         self.x = x
  29.         self.y = y
  30.         self.hp = hp
  31.         self.strength = strength
  32.         self.speed = speed
  33.         self.char = char
  34.         self.state = state
  35.  
  36.     def move(self, direction, board):
  37.         '''To update entity position
  38.            Takes direction and deals with collision.'''
  39.         if direction == MOVE.LEFT and board.is_valid_move(self, (self.x, self.y - 1)):
  40.             board.print_char(self)
  41.             self.y -= 1
  42.             return True
  43.         elif direction == MOVE.RIGHT and board.is_valid_move(self, (self.x, self.y + 1)):
  44.             board.print_char(self)
  45.             self.y += 1
  46.             return True
  47.         elif direction == MOVE.UP and board.is_valid_move(self, (self.x - 1, self.y)):
  48.             board.print_char(self)
  49.             self.x -= 1
  50.             return True
  51.         elif direction == MOVE.DOWN and board.is_valid_move(self, (self.x + 1, self.y)):
  52.             board.print_char(self)
  53.             self.x += 1
  54.             return True
  55.         else:
  56.             return False
  57.  
  58.     def attack(self, target, called_shot=False, part=''):
  59.         '''Deals with combat.'''
  60.         if self.distance(target) == 1:
  61.             if not called_shot:
  62.                 to_hit = random.randint(1, 21) # Roll
  63.                 if to_hit >= target.speed + 5: # If hit... (AC = 5 + target speed)
  64.                     target.hp -= self.strength # Deal damage (DAM = Self strength)
  65.                     print '{} hit!'.format(self.name) # Output
  66.                     time.sleep(0.5)
  67.                     return True # Return taken turn
  68.                 else:
  69.                     print '{} missed!'.format(self.name) # Else, miss
  70.                     time.sleep(0.5)
  71.                     return True # Return taken turn
  72.             elif called_shot: # Stronger hit
  73.                 to_hit = random.randint(1, 21) # Roll
  74.                 if to_hit >= target.speed + 10: # If hit...
  75.                     target.hp -= random.randint(1, 3) + self.strength # Deal damage (DAM = 1-3 + self strength)
  76.                     print '{} hits {}\'s {}!'.format(self.name, target.name.lower(), part) # Output
  77.                     time.sleep(0.5)
  78.                     return True # Return taken turn
  79.                 else:
  80.                     print '{} missed {}\'s {}!'.format(self.name, target.name.lower(), part) # Else, miss
  81.                     time.sleep(0.5)
  82.                     return True # Return taken turn
  83.             else:
  84.                 return FLAG.ATTACK
  85.         else:
  86.             print 'You can\'t hit from this far away' # Else the attacker is too far away
  87.             time.sleep(0.5)
  88.             return False # Return turn not taken
  89.  
  90.     def distance(self, target, pos=()):
  91.         '''Get distance from self to target.'''
  92.         if not pos: # If nothing passed to pos, then use entity coordinates
  93.             x, y = self.x, self.y
  94.         else:
  95.             x, y, = pos # else, use passed tuple
  96.         return math.sqrt((x - target.x)**2 + (y - target.y)**2) # Get distance
  97.  
  98.     def change_state(self, state):
  99.         '''Change Entity state. Only for death right now.
  100.            Soon for position also.'''
  101.         self.state = state
  102.         if self.state == STATE.DEAD:
  103.             self.char = '%'
  104.         else:
  105.             return
  106.  
  107.     def update(self):
  108.         '''Update Entity, check hp, xp, ect.'''
  109.         if self.name == 'Player':
  110.             if self.hp <= 0 and self.state == STATE.ALIVE: # If hp is 0 or below, change to dead
  111.                 self.change_state(STATE.DEAD)
  112.                 self.char = '%'
  113.             elif self.hp <= 0 and self.state == STATE.DEAD: # If dead, let the enemy take turns endlessly
  114.                     time.sleep(1)
  115.         elif self.name == 'Enemy':
  116.             if self.hp <= 0 and self.state == STATE.ALIVE: # Check for hp and death
  117.                 self.change_state(STATE.DEAD)
  118.                 self.char = '%'
  119.             elif self.hp <= 0 and self.state == STATE.DEAD: # Do nothing (May add end game function here)
  120.                     return
  121.  
  122. class Player(Entity):
  123.     '''Player specific entity.'''
  124.     # Unsure how to use this just yet
  125.     pass
  126.  
  127. class Enemy(Entity):
  128.     '''Enemy specific entity.'''
  129.     def __init__(self, name, x, y, char, state=STATE.ALIVE):
  130.         self.name = name
  131.         self.x = x
  132.         self.y = y
  133.         self.hp = random.randint(5, 13) # Hp is random
  134.         self.strength = random.randint(1, 2) # Str is random
  135.         self.speed = random.randint(1, 2) # Spd is random
  136.         self.char = char
  137.         self.state = state
  138.  
  139.     def move_toward(self, target, board, pos=()):
  140.         '''Moves enemy towards target.'''
  141.         possible_moves = (
  142.         (self.distance(target, (self.x, self.y + 1)), MOVE.RIGHT),
  143.         (self.distance(target, (self.x, self.y - 1)), MOVE.LEFT),
  144.         (self.distance(target, (self.x - 1, self.y)), MOVE.UP),
  145.         (self.distance(target, (self.x + 1, self.y)), MOVE.DOWN))
  146.  
  147.         small_key = sorted(possible_moves)[0] # Sort list to get shortest distance
  148.  
  149.         self.move(small_key[1], board) # Move that direction
  150.  
  151. class Board(object):
  152.     '''Board class to create empty grid of cells.'''
  153.     def __init__(self, width, height, entities, char='-'):
  154.         self.width = width
  155.         self.height = height
  156.         self.entities = entities
  157.         self.board = [[char] * width for _ in range(height)]
  158.  
  159.     def __str__(self):
  160.         '''To draw the board and all entities within.'''
  161.         self.clear_screen() # Clear to refresh
  162.         for entity in self.entities: # For each entity in list, draw them
  163.             self.board[entity.x][entity.y] = entity.char
  164.         for entity in self.entities: # For UI. Looking for a better way to do this
  165.             if entity.name == 'Player':
  166.                 print 'HP:' + str(entity.hp)
  167.         return '\n'.join(' '.join(line) for line in self.board) # Draw entire board
  168.  
  169.     def print_char(self, ent, char='-'):
  170.         '''Print a character to the board
  171.            Used to clear entities previous move.'''
  172.         self.board[ent.x][ent.y] = char
  173.  
  174.     def clear_screen(self): # Kinda obvious
  175.         if platform.system() == 'Linux':
  176.             os.system('clear')
  177.         elif platform.system() == 'Windows':
  178.             os.system('cls')
  179.         else:
  180.             return FLAG.CLEAR
  181.  
  182.     def is_vacant(self, x, y):
  183.         '''Checks the board for vacant cells
  184.            or cells occupied by corpses.'''
  185.         if self.board[x][y] == '-' or self.board[x][y] == '%':
  186.             return True
  187.         else:
  188.             return False
  189.  
  190.     def is_valid_move(self, ent, future_pos):
  191.         '''Collision. Checks all possible moves,
  192.            determines if the move is in the board
  193.            area, returns a list of valid moves.'''
  194.         moves = []
  195.         adj_cells = [(ent.x+1, ent.y),(ent.x-1, ent.y),
  196.                     (ent.x, ent.y+1),(ent.x, ent.y-1)]
  197.         for (x,y) in adj_cells:
  198.             if (0 <= x <= self.width - 1 and 0 <= y <= self.height - 1
  199.             and self.is_vacant(x, y)):
  200.                 moves.append((x,y))
  201.  
  202.         return future_pos in moves
  203.  
  204. ##
  205. # Functions
  206. ##
  207.  
  208. def type_text(string, sec):
  209.     '''Text 'typing' effect'''
  210.     for _ in string:
  211.         #sec = random.uniform((0.1, 0.2) if sec == 'random' else sec)
  212.         sys.stderr.write(_)
  213.         time.sleep(random.uniform(0.1, 0.2) if sec == 'random' else sec)
  214.  
  215. def enemy_turn(enemy, player, board):
  216.     '''Deals with enemy turns.'''
  217.     enemy.update() # Update enemy state
  218.  
  219.     if enemy.state == STATE.DEAD: # End turn if enemy is dead
  220.         return # Possibly a better way to do this?
  221.     else:
  222.         pass # Else, continue
  223.  
  224.     distance = enemy.distance(player, (enemy.x, enemy.y)) # Get player distance
  225.     if distance == 1 and player.state != STATE.DEAD: # If adjacent, attack
  226.         enemy.attack(player)
  227.     elif distance < 5 and player.state != STATE.DEAD: # Else, if player is close, move towards
  228.         enemy.move_toward(player, board, (enemy.x, enemy.y))
  229.     else:
  230.         moves = [MOVE.UP, MOVE.DOWN, MOVE.LEFT, MOVE.RIGHT] # Else, just move randomly
  231.         move = random.choice(moves)
  232.  
  233.         if not enemy.move(move, board): # If the move was invalid, get another chance
  234.             enemy_turn(enemy, player, board)
  235.         else:
  236.             return FLAG.E_TURN
  237.  
  238. def player_turn(player, enemy, board):
  239.     player.update() # Update player state
  240.  
  241.     if player.state == STATE.DEAD: # If dead, do not take turn
  242.         return
  243.     else:
  244.         pass # Else, continue
  245.  
  246.     m_actions = {
  247.     'move' : ['move', 'walk'],
  248.     'attack' : ['attack', 'hit'],
  249.     'die' : ['die'],
  250.     'kill' : ['kill'],
  251.     'pass' : ['pass', '']
  252.     }
  253.  
  254.     s_actions = {
  255.     'move' : ['up', 'down', 'left', 'right'],
  256.     'attack' : ['head', 'arms', 'legs', 'torso', 'chest',]
  257.     }
  258.  
  259.     choice = raw_input('What do you want to do? :> ').lower() # What to do?
  260.     parts = [x.strip() for x in choice.split(',')] # Break up input into a list
  261.     if len(parts) < 2: # If input contains only one word
  262.         if parts[0] in m_actions['move']: # If it is move, ask for direction
  263.             direction = raw_input('Which direction? :> ').lower()
  264.             parts.append(direction.strip()) # Append direction into parts
  265.             if parts[1] in s_actions['move']: # If the direction is in the sub action dict
  266.                 if not player.move(parts[1], board): # Move, if you can
  267.                     print board # If can't or bad input, retake turn
  268.                     player_turn(player, enemy, board)
  269.  
  270.         elif parts[0] in m_actions['attack']: # If input is attack
  271.             if not player.attack(enemy): # Attack, if you can
  272.                 print board # Else, retake turn
  273.                 player_turn(player, enemy, board)
  274.  
  275.         elif parts[0] in m_actions['die']: # Just for testing
  276.             player.state = STATE.DEAD
  277.  
  278.         elif parts[0] in m_actions['kill']: # Also for testing
  279.             enemy.state = STATE.DEAD    
  280.  
  281.         elif parts[0] in m_actions['pass']: # To pass turn
  282.             pass
  283.         else:
  284.             print board # If bad input, retake turn
  285.             player_turn(player, enemy, board)
  286.  
  287.     elif len(parts) == 2: # If parts holds two commands
  288.         if parts[0] in m_actions['move']: # If move in first place
  289.             if parts[1] in s_actions['move']: # If direction is in sub actions
  290.                 if not player.move(parts[1], board): # If can move, move
  291.                     print board # Else, retake turn
  292.                     player_turn(player, enemy, board)
  293.  
  294.         elif parts[0] in m_actions['attack']: # If attack in first place
  295.             if parts[1] in s_actions['attack']: # If body part in sub actions
  296.                 if not player.attack(enemy, True, parts[1]): # If can attack, attack
  297.                     print board # Else, retake turn
  298.                     player_turn(player, enemy, board)
  299.  
  300.         else: # For any bad input, retake turn
  301.             print board
  302.             player_turn(player, enemy, board)
  303.  
  304.     else: # For any bad input, retake turn
  305.         print board
  306.         player_turn(player, enemy, board)
  307.  
  308. def main():
  309.     ## Title ##
  310.     sys.stdout.write("\x1b]2;Grid_Battle V0.1\x07") # Title
  311.  
  312.     # Initiate #
  313.  
  314.     player = Player('Player', 0, 0, 10, 1, 1, 'o')
  315.     enemy = Enemy('Enemy', 4, 4, 'x')
  316.     objects = [player, enemy]
  317.     board = Board(5, 5, objects)
  318.  
  319.     print board # Clear screen and print board
  320.  
  321.     while True: # Main loop
  322.         turn = player.speed # Player turn. Amount of actions based on speed
  323.         while turn != 0 and enemy.hp > 0: # As long as turn and hp above 0
  324.             player_turn(player, enemy, board) # Take turn
  325.             turn -= 1 # Remove one turn
  326.             print board # Redraw
  327.  
  328.         turn = enemy.speed # Enemy turn.
  329.         while turn != 0 and player.hp > 0:
  330.             time.sleep(0.2) # Sleep for effect
  331.             enemy_turn(enemy, player, board)
  332.             turn -= 1
  333.             time.sleep(0.2)
  334.             print board
  335.             if player.hp <= 0: # If player is dead, break
  336.                 break
  337.  
  338.         print board # To clear some text
  339.  
  340.         if enemy.state == STATE.DEAD: # If enemy is dead
  341.             time.sleep(0.5)
  342.             board.clear_screen()
  343.             type_text('You won', 'random') # Crappy win screen
  344.             type_text('!!!', 0.5)
  345.             print # New line
  346.             break # Leave main loop
  347.         if player.state == STATE.DEAD: # If the player is dead
  348.             enemy_turn(enemy, player, board) # Enemy moves endlessly
  349.        
  350. if __name__ == '__main__':
  351.     main()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement