1 # ###################################################
2 # Copyright (C) 2008 The OpenAnno Team
4 # This file is part of OpenAnno.
6 # OpenAnno 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.
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.
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the
18 # Free Software Foundation, Inc.,
19 # 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 # ###################################################
31 from game
.gui
.selectiontool
import SelectionTool
32 from game
.world
.building
import building
33 from game
.world
.units
.ship
import Ship
34 from game
.world
.player
import Player
35 from game
.gui
.ingamegui
import IngameGui
36 from game
.gui
.ingamekeylistener
import IngameKeyListener
37 from game
.world
.island
import Island
38 from game
.dbreader
import DbReader
39 from game
.timer
import Timer
40 from game
.scheduler
import Scheduler
41 from game
.manager
import SPManager
42 from game
.view
import View
43 from game
.world
import World
44 from game
.entities
import Entities
45 from game
.util
import livingObject
, livingProperty
, WorldObject
47 class Session(livingObject
):
48 """Session class represents the games main ingame view and controls cameras and map loading.
50 This is the most important class if you are going to hack on OpenAnno, it provides most of
51 the important ingame variables that you will be constantly accessing by game.main.session.x
52 Here's a small list of commonly used attributes:
53 * manager - game.manager instance. Used to execute commands that need to be tick,
54 synchronized check the class for more information.
55 * scheduler - game.scheduler instance. Used to execute timed events that do not effect
57 * view - game.view instance. Used to control the ingame camera.
58 * entities - game.entities instance. used to hold preconstructed dummy classes from the db
59 for later initialization.
60 * ingame_gui - game.gui.ingame_gui instance. Used to controll the ingame gui.
61 * cursor - game.gui.{navigation/cursor/selection/building}tool instance. Used to controll
62 mouse events, check the classes for more info.
63 * selected_instances - Set that holds the currently selected instances (building, units).
66 For further digging you should now be checking out the load() function.
68 timer
= livingProperty()
69 manager
= livingProperty()
70 scheduler
= livingProperty()
71 view
= livingProperty()
72 entities
= livingProperty()
73 ingame_gui
= livingProperty()
74 keylistener
= livingProperty()
75 cursor
= livingProperty()
76 world
= livingProperty()
79 super(Session
, self
).begin()
85 self
.manager
= SPManager()
86 self
.scheduler
= Scheduler(self
.timer
)
87 self
.view
= View((15, 15))
88 self
.entities
= Entities()
91 self
.ingame_gui
= IngameGui()
92 self
.keylistener
= IngameKeyListener()
93 self
.cursor
= SelectionTool()
95 self
.selected_instances
= set()
96 self
.selection_groups
= [set()] * 10 # List of sets that holds the player assigned unit groups.
99 if game
.main
.settings
.savegame
.autosaveinterval
!= 0:
100 game
.main
.ext_scheduler
.add_new_object(self
.autosave
, self
.autosave
, game
.main
.settings
.savegame
.autosaveinterval
* 60, -1)
103 self
.scheduler
.rem_all_classinst_calls(self
)
106 self
.keylistener
= None
107 self
.ingame_gui
= None
110 self
.scheduler
= None
115 self
.selected_instances
= None
116 self
.selection_groups
= None
117 super(Session
, self
).end()
120 """Called automatically in an interval"""
121 self
.save(game
.main
.savegamemanager
.create_autosave_filename())
122 game
.main
.savegamemanager
.delete_dispensable_savegames(autosaves
= True)
125 """Called when user presses a hotkey"""
126 self
.save(game
.main
.savegamemanager
.create_quicksave_filename())
127 game
.main
.savegamemanager
.delete_dispensable_savegames(quicksaves
= True)
130 """Loads last quicksave"""
131 files
= game
.main
.savegamemanager
.get_quicksaves(include_displaynames
= False)[0]
133 game
.main
.showPopup("No quicksaves found", "You need to quicksave before you can quickload.")
136 game
.main
.loadGame(files
[-1])
138 def save(self
, savegame
):
140 @param savegame: the file, where the game will be saved
142 if os
.path
.exists(savegame
):
144 shutil
.copyfile('content/savegame_template.sqlite', savegame
)
146 db
= DbReader(savegame
)
148 print 'STARTING SAVING'
151 #self.manager.save(db)
153 self
.ingame_gui
.save(db
)
155 for instance
in self
.selected_instances
:
156 db("INSERT INTO selected(`group`, id) VALUES(NULL, ?)", instance
.getId())
157 for group
in xrange(len(self
.selection_groups
)):
158 for instance
in self
.selection_groups
[group
]:
159 db("INSERT INTO selected(`group`, id) VALUES(?, ?)", group
, instance
.getId())
161 print 'writing metadata'
162 game
.main
.savegamemanager
.write_metadata(db
)
164 print "Save exception", e
167 print 'FINISHED SAVING'
169 def record(self
, savegame
):
171 game
.main
.db("ATTACH ? AS demo", savegame
)
172 self
.manager
.recording
= True
174 def stop_record(self
):
175 assert(self
.manager
.recording
)
176 self
.manager
.recording
= False
177 game
.main
.db("DETACH demo")
179 def load(self
, savegame
, playername
= "", playercolor
= None):
181 @param savegame: path to the savegame database.
182 @param playername: string with the playername
183 @param playercolor: game.util.color instance with the player's color
185 db
= DbReader(savegame
) # Initialize new dbreader
186 self
.world
= World(db
) # Load game.world module (check game/world/__init__.py)
188 self
.world
.setupPlayer(playername
, playercolor
) # setup new player
189 self
.view
.load(db
) # load view
190 self
.manager
.load(db
) # load the manager (there might me old scheduled ticks.
191 self
.ingame_gui
.load(db
) # load the old gui positions and stuff
193 #self.view.center(((self.world.max_x - self.world.min_x) / 2.0), ((self.world.max_y - self.world.min_y) / 2.0))
195 for instance_id
in db("SELECT id FROM selected WHERE `group` IS NULL"): # Set old selected instance
196 obj
= WorldObject
.getObjectById(instance_id
[0])
197 self
.selected_instances
.add(obj
)
199 for group
in xrange(len(self
.selection_groups
)): # load user defined unit groups
200 for instance_id
in db("SELECT id FROM selected WHERE `group` = ?", group
):
201 self
.selection_groups
[group
].add(WorldObject
.getObjectById(instance_id
[0]))
203 self
.cursor
.apply_select() # Set cursor correctly, menus might need to be opened.
207 From here on you should digg into the classes that are loaded above, especially the world class.
208 (game/world/__init__.py). It's where the magic happens and all buildings and units are loaded.
211 def generateMap(self
):
212 """Generates a map."""
215 game
.main
.db("attach ':memory:' as map")
220 self
.view
.center(((self
.world
.max_x
- self
.world
.min_x
) / 2.0), ((self
.world
.max_y
- self
.world
.min_y
) / 2.0))
222 def speed_set(self
, ticks
):
223 old
= self
.timer
.ticks_per_second
224 self
.timer
.ticks_per_second
= ticks
225 self
.view
.map.setTimeMultiplier(float(ticks
) / float(game
.main
.settings
.ticks
.default
))
226 if old
== 0 and self
.timer
.tick_next_time
is None: #back from paused state
227 self
.timer
.tick_next_time
= time
.time() + (self
.paused_time_missing
/ ticks
)
228 elif ticks
== 0 or self
.timer
.tick_next_time
is None: #go into paused state or very early speed change (before any tick)
229 self
.paused_time_missing
= ((self
.timer
.tick_next_time
- time
.time()) * old
) if self
.timer
.tick_next_time
is not None else None
230 self
.timer
.tick_next_time
= None
232 self
.timer
.tick_next_time
= self
.timer
.tick_next_time
+ ((self
.timer
.tick_next_time
- time
.time()) * old
/ ticks
)
235 if self
.timer
.ticks_per_second
in game
.main
.settings
.ticks
.steps
:
236 i
= game
.main
.settings
.ticks
.steps
.index(self
.timer
.ticks_per_second
)
237 if i
+ 1 < len(game
.main
.settings
.ticks
.steps
):
238 self
.speed_set(game
.main
.settings
.ticks
.steps
[i
+ 1])
240 self
.speed_set(game
.main
.settings
.ticks
.steps
[0])
242 def speed_down(self
):
243 if self
.timer
.ticks_per_second
in game
.main
.settings
.ticks
.steps
:
244 i
= game
.main
.settings
.ticks
.steps
.index(self
.timer
.ticks_per_second
)
246 self
.speed_set(game
.main
.settings
.ticks
.steps
[i
- 1])
248 self
.speed_set(game
.main
.settings
.ticks
.steps
[0])
250 def speed_pause(self
):
251 if self
.timer
.ticks_per_second
!= 0:
252 self
.paused_ticks_per_second
= self
.timer
.ticks_per_second
255 def speed_unpause(self
):
256 if self
.timer
.ticks_per_second
== 0:
257 self
.speed_set(self
.paused_ticks_per_second
)
260 def speed_toggle_pause(self
):
261 if self
.timer
.ticks_per_second
== 0: