Started to build Mapview-class. It acts as an observer for the Map.
[otium.git] / otium.py
blob419b035dedec448232baeba34539d653d22475e9
1 import curses
2 import random
3 import world
4 from world import Position
5 from world import Tile
6 from world import Symbol
7 from world import Object
8 from world import Map
9 from world import RectangleArea
10 from world import MapEvent
12 # Define the colors
13 BLACK = 0
14 BLUE = 1
15 CYAN = 2
16 GREEN = 3
17 MAGENTA = 4
18 RED = 5
19 WHITE = 6
20 YELLOW = 7
22 #Possible directions (points of the compass).
23 NORTH = Position(0,-1)
24 SOUTH = Position(0,1)
25 EAST = Position(1,0)
26 WEST = Position(-1,0)
27 NORTH_E = NORTH + EAST
28 NORTH_W = NORTH + WEST
29 SOUTH_E = SOUTH + EAST
30 SOUTH_W = SOUTH + WEST
32 # Maybe we should add keys for the intermediary points of the compass.
33 directions = { curses.KEY_LEFT: WEST,
34 curses.KEY_RIGHT: EAST,
35 curses.KEY_UP: NORTH,
36 curses.KEY_DOWN: SOUTH }
38 # Symbols for different
39 EMPTY = Symbol(' ', BLACK, ' ')
40 WATER = Symbol('=', BLUE, '=')
41 LAND = Symbol(':', GREEN, ':')
42 MOUNTAIN = Symbol('^', WHITE, '^')
43 FOREST = Symbol('&', GREEN, '&')
44 FIELD = Symbol('#', YELLOW, '#')
45 DESERT = Symbol('.', YELLOW, '.')
46 PLAYER = Symbol('@', WHITE, '@')
48 # FIXME/tuos: This is just a quick hack.
49 class Param:
50 def __init__(self, symbol, size, count):
51 self.symbol = symbol
52 self.size = size
53 self.count = count
55 # Initially generated symbols.
56 # Add new: Add symbol into the list below.
57 # First parameter tells how many lands, mountain ranges etc.
58 # Second tells how big they are going to be.
59 INITIAL_MAP_PARAMS = [ Param(LAND, 15, 30),
60 Param(MOUNTAIN, 10, 20),
61 Param(FOREST, 10, 10)]
63 # The player viewport size
64 PLAY_AREA_ROWS = 10
65 PLAY_AREA_COLS = 40
67 worldmap = Map(160, 40, WATER)
69 player = Object(Position(2,2), PLAYER, "Player.")
71 def create_tile(symbol, position, description, size):
72 if size < 0:
73 return
74 if not worldmap.has_position(position):
75 return
76 size -= 1
77 try:
78 worldmap.insert(Tile(position, symbol, description))
79 except:
80 return
81 create_tile(symbol, position + NORTH, description, size)
82 create_tile(symbol, position + SOUTH, description, size)
83 create_tile(symbol, position + WEST, description, size)
84 create_tile(symbol, position + EAST, description, size)
86 def generate_world():
87 """Generates the world."""
88 for param in INITIAL_MAP_PARAMS:
89 for i in range(param.count):
90 x = random.randint(0, worldmap.width() -1 )
91 y = random.randint(0, worldmap.height() - 1)
92 create_tile(param.symbol, Position(x, y), "Symbol description.", param.size)
94 class Mapview(RectangleArea):
96 def __init__(self, width, height, stdscr):
97 RectangleArea.__init__(self, width, height)
98 self.__width_offset__ = 0
99 self.__height_offset__ = 0
100 self.__stdscr__ = stdscr
102 def map_event(self, event):
103 self.__stdscr__.addstr(20, 20, "Unknown command.")
104 self.__stdscr__.refresh()
105 if event.type() == MapEvent.AFTER_INSERT:
106 self.draw_object(event.object())
108 def draw_object(self, object):
109 char = object.symbol().char()
110 color = object.symbol().color()
111 x = object.position().x() - self.__width_offset__
112 y = object.position().y() - self.__height_offset__
113 pos = Position(x,y)
114 if self.has_position(pos):
115 self.__stdscr__.addstr(y,x, char, curses.color_pair(color))
118 # FIXME/tuos: This method should be a part of screen/vieport
119 def draw_map(stdscr, player):
120 """Draws the map and the player to the screen."""
122 minrow = player.position().y() - PLAY_AREA_ROWS
123 maxrow = player.position().y() + PLAY_AREA_ROWS
124 mincol = player.position().x() - PLAY_AREA_COLS
125 maxcol = player.position().x() + PLAY_AREA_COLS
127 player_row_correction = 0
128 player_col_correction = 0
129 if minrow < 0:
130 player_row_correction = minrow
131 minrow = 0
132 maxrow = PLAY_AREA_ROWS*2
133 if worldmap.height() < maxrow:
134 player_row_correction = - (worldmap.height() - maxrow)
135 minrow = worldmap.height()
136 maxrow = worldmap.height()
137 if mincol < 0:
138 player_col_correction = mincol
139 mincol = 0
140 maxcol = PLAY_AREA_COLS*2
141 if worldmap.width() < maxcol:
142 player_col_correction = -(worldmap.width() - maxcol)
143 mincol = worldmap.width() - (PLAY_AREA_COLS*2)
144 maxcol = worldmap.width()
145 rown = 0
147 for row in range(minrow,maxrow):
148 coln = 0
149 for col in range(mincol,maxcol):
150 tile = worldmap.get(Position(col, row))
151 char = tile.symbol().char()
152 color = tile.symbol().color()
153 stdscr.addch(rown, coln, char, curses.color_pair(color))
154 coln += 1
155 rown += 1
157 stdscr.addstr(PLAY_AREA_ROWS + player_row_correction, PLAY_AREA_COLS + player_col_correction, "@", curses.color_pair(WHITE))
159 # FIXME/tuos: This method should be a part of screen/vieport
160 def init_curses():
161 curses.curs_set(0)
162 curses.init_pair(BLUE, curses.COLOR_BLUE, curses.COLOR_BLACK)
163 curses.init_pair(CYAN, curses.COLOR_CYAN, curses.COLOR_BLACK)
164 curses.init_pair(GREEN, curses.COLOR_GREEN, curses.COLOR_BLACK)
165 curses.init_pair(MAGENTA, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
166 curses.init_pair(RED, curses.COLOR_RED, curses.COLOR_BLACK)
167 curses.init_pair(WHITE, curses.COLOR_WHITE, curses.COLOR_BLACK)
168 curses.init_pair(YELLOW, curses.COLOR_YELLOW, curses.COLOR_BLACK)
170 def main(stdscr):
171 """Asks for input and executes commands until game ends."""
172 init_curses()
173 random.seed()
174 # mv = Mapview(PLAY_AREA_COLS, PLAY_AREA_ROWS, stdscr)
175 generate_world()
176 # worldmap.add_observer(mv)
177 # worldmap.remove_observer(mv)
178 end = False
179 while not end:
180 stdscr.clear()
181 draw_map(stdscr, player)
182 # mv.draw_object(player)
183 c = stdscr.getch()
184 if c == ord('q'):
185 end = True
186 continue
187 try:
188 commands[c]()
189 except:
190 stdscr.addstr(20, 20, "Unknown command.")
191 player.move(directions[c])
193 if __name__ == "__main__":
194 curses.wrapper(main)