1 /*
2 Copyright (C) 2007, 2010 - Bit-Blot
3
4 This file is part of Aquaria.
5
6 Aquaria is free software; you can redistribute it and/or
7 modify it under the terms of the GNU General Public License
8 as published by the Free Software Foundation; either version 2
9 of the License, or (at your option) any later version.
10
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.
14
15 See the GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20 */
21 #include "DSQ.h"
22 #include "Game.h"
23
24 static std::string baseModPath = "./_mods/";
25
refreshBaseModPath()26 void refreshBaseModPath()
27 {
28 #if defined(BBGE_BUILD_UNIX)
29 baseModPath = dsq->getUserDataFolder() + "/_mods/";
30 #endif
31 }
32
Mod()33 Mod::Mod()
34 {
35 clear();
36
37 enqueueModStart = 0;
38
39 shuttingDown = false;
40 }
41
~Mod()42 Mod::~Mod()
43 {
44 modcache.clean();
45 }
46
47 /*
48 queue for actual stop and recache
49 which happens in game::applystate
50 */
shutdown()51 void Mod::shutdown()
52 {
53 shuttingDown = true;
54 }
55
isShuttingDown()56 bool Mod::isShuttingDown()
57 {
58 return shuttingDown;
59 }
60
clear()61 void Mod::clear()
62 {
63 active = false;
64 doRecache = 0;
65 debugMenu = false;
66 hasMap = false;
67 blockEditor = false;
68 mapRevealMethod = REVEAL_UNSPECIFIED;
69 }
70
isDebugMenu()71 bool Mod::isDebugMenu()
72 {
73 return debugMenu;
74 }
75
hasWorldMap()76 bool Mod::hasWorldMap()
77 {
78 return hasMap;
79 }
80
isEditorBlocked()81 bool Mod::isEditorBlocked()
82 {
83 return blockEditor;
84 }
85
loadModXML(XMLDocument * d,std::string modName)86 bool Mod::loadModXML(XMLDocument *d, std::string modName)
87 {
88 return readXML((baseModPath + modName + ".xml").c_str(), *d) == XML_SUCCESS;
89
90 }
91
getBaseModPath() const92 const std::string& Mod::getBaseModPath() const
93 {
94 refreshBaseModPath();
95
96 return baseModPath;
97 }
98
load(const std::string & p)99 void Mod::load(const std::string &p)
100 {
101 clear();
102
103 refreshBaseModPath();
104
105 name = p;
106 path = baseModPath + p + "/";
107
108 setLocalisationModPath(path);
109
110 setActive(true);
111
112 XMLDocument d;
113 loadModXML(&d, p);
114
115 XMLElement *mod = d.FirstChildElement("AquariaMod");
116 if (mod)
117 {
118 XMLElement *props = mod->FirstChildElement("Properties");
119 if (props)
120 {
121 props->QueryIntAttribute("recache", &doRecache);
122 props->QueryIntAttribute("debugMenu", &debugMenu);
123 props->QueryBoolAttribute("hasWorldMap", &hasMap);
124 props->QueryBoolAttribute("blockEditor", &blockEditor);
125
126 if (props->BoolAttribute("runBG"))
127 core->settings.runInBackground = true;
128
129 if (props->Attribute("worldMapRevealMethod"))
130 mapRevealMethod = (WorldMapRevealMethod) props->IntAttribute("worldMapRevealMethod");
131 }
132 }
133
134 dsq->secondaryTexturePath = path + "graphics/";
135
136 dsq->sound->audioPath2 = path + "audio/";
137 dsq->sound->setVoicePath2(path + "audio/");
138
139 SkeletalSprite::secondaryAnimationPath = path + "animations/";
140
141 dsq->particleBank2 = path + "particles/";
142 dsq->shotBank2 = path + "shots/";
143
144 Shot::loadShotBank(dsq->shotBank1, dsq->shotBank2);
145 particleManager->loadParticleBank(dsq->particleBank1, dsq->particleBank2);
146 }
147
getPath() const148 const std::string& Mod::getPath() const
149 {
150 return path;
151 }
152
getName() const153 const std::string& Mod::getName() const
154 {
155 return name;
156 }
157
recache()158 void Mod::recache()
159 {
160 if(doRecache)
161 {
162 dsq->precacher.clean();
163 dsq->unloadResources();
164 }
165
166 if(active)
167 {
168 modcache.setBaseDir(dsq->secondaryTexturePath);
169 std::string fname = path;
170 if(fname[fname.length() - 1] != '/')
171 fname += '/';
172 fname += "precache.txt";
173 fname = core->adjustFilenameCase(fname);
174 if (exists(fname))
175 {
176 modcache.precacheList(fname);
177 core->resetTimer();
178 }
179 }
180 else
181 {
182 modcache.clean();
183 }
184
185 if(doRecache)
186 {
187 dsq->precacher.precacheList("data/precache.txt");
188 dsq->reloadResources();
189 core->resetTimer();
190 }
191 }
192
start()193 void Mod::start()
194 {
195 dsq->overlay->color = 0;
196
197 dsq->toggleVersionLabel(0);
198 dsq->toggleCursor(0, 1);
199
200 float t = 1;
201 dsq->overlay->alpha.interpolateTo(1, t);
202 core->sound->fadeMusic(SFT_OUT, t*0.9f);
203
204 core->main(t);
205
206 core->sound->stopMusic();
207
208 enqueueModStart = 1;
209 dsq->recentSaveSlot = -1;
210 }
211
applyStart()212 void Mod::applyStart()
213 {
214 enqueueModStart = 0;
215
216 core->popAllStates();
217 core->clearGarbage();
218 recache();
219 dsq->continuity.reset();
220 dsq->scriptInterface.reset();
221
222 // load the mod-init.lua file
223 // which is in the root of the mod's folder
224 // e.g. _mods/recachetest/
225 std::string scriptPath = path + "mod-init.lua";
226 debugLog("scriptPath: " + scriptPath);
227 if (!dsq->runScript(scriptPath, "init"))
228 {
229 debugLog("MOD: runscript failed");
230 setActive(false);
231 dsq->title();
232 }
233 if (isActive() && dsq->game->sceneToLoad.empty())
234 {
235 debugLog("MOD: no scene loaded in mod-init");
236 setActive(false);
237 dsq->title();
238 }
239 else if (isActive())
240 {
241 }
242 }
243
isActive()244 bool Mod::isActive()
245 {
246 return active;
247 }
248
setActive(bool a)249 void Mod::setActive(bool a)
250 {
251 bool wasActive = active;
252
253 active = a;
254
255 if (wasActive != active)
256 {
257 if (!active)
258 {
259 dsq->unloadMods();
260
261 mapRevealMethod = REVEAL_UNSPECIFIED;
262 setLocalisationModPath("");
263 name = path = "";
264 dsq->secondaryTexturePath = "";
265 dsq->sound->audioPath2 = "";
266 dsq->sound->setVoicePath2("");
267 SkeletalSprite::secondaryAnimationPath = "";
268
269 dsq->particleBank2 = "";
270 dsq->shotBank2 = "";
271
272 Shot::loadShotBank(dsq->shotBank1, dsq->shotBank2);
273 particleManager->loadParticleBank(dsq->particleBank1, dsq->particleBank2);
274
275 dsq->setFilter(dsq->dsq_filter);
276
277 recache();
278 }
279 dsq->game->loadEntityTypeList();
280 }
281 }
282
stop()283 void Mod::stop()
284 {
285 setActive(false);
286
287 core->settings.runInBackground = false;
288 debugMenu = false;
289 shuttingDown = false;
290 dsq->scriptInterface.reset();
291 dsq->game->setWorldPaused(false);
292 }
293
update(float dt)294 void Mod::update(float dt)
295 {
296 if (enqueueModStart)
297 {
298 enqueueModStart = 0;
299
300 applyStart();
301 }
302 }
303
getTypeFromXML(XMLElement * xml)304 ModType Mod::getTypeFromXML(XMLElement *xml) // should be <AquariaMod>...</AquariaMod> - element
305 {
306 if(xml)
307 {
308 XMLElement *prop = xml->FirstChildElement("Properties");
309 if(prop)
310 {
311 const char *type = prop->Attribute("type");
312 if(type)
313 {
314 if(!strcmp(type, "mod"))
315 return MODTYPE_MOD;
316 else if(!strcmp(type, "patch"))
317 return MODTYPE_PATCH;
318 else
319 {
320 std::ostringstream os;
321 os << "Unknown mod type '" << type << "' in XML, default to MODTYPE_MOD";
322 debugLog(os.str());
323 }
324 }
325 }
326 }
327 return MODTYPE_MOD; // the default
328 }
329