add wraparound support to C2 physics
[openc2e.git] / caosVM_resources.cpp
blob4053d181a216aadb66204f1dc50d6137907a8fda
1 /*
2 * caosVM_resources.cpp
3 * openc2e
5 * Created by Alyssa Milburn on Sun Jun 13 2004.
6 * Copyright (c) 2004 Alyssa Milburn. All rights reserved.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
20 #include "caosVM.h"
21 #include "caosScript.h" // PRAY INJT
22 #include "World.h"
23 #include "Catalogue.h"
24 #include <boost/format.hpp>
25 #include <boost/filesystem/convenience.hpp>
26 namespace fs = boost::filesystem;
28 bool prayInstall(std::string name, unsigned int type, bool actually_install) {
29 std::string directory = world.praymanager.getResourceDir(type);
30 caos_assert(!directory.empty());
32 fs::path dir = fs::path(world.getUserDataDir(), fs::native) / fs::path(directory, fs::native);
33 if (!fs::exists(dir))
34 fs::create_directory(dir);
35 caos_assert(fs::exists(dir) && fs::is_directory(dir));
37 fs::path outputfile = dir / fs::path(name, fs::native);
38 if (fs::exists(outputfile)) {
39 // TODO: update file if necessary? check it's not a directory :P
40 return true;
43 fs::path possiblefile = fs::path(directory, fs::native) / fs::path(name, fs::native);
44 if (!world.findFile(possiblefile.native_directory_string()).empty()) {
45 // TODO: we need to return 'okay' if the file exists anywhere, but someone needs to work out update behaviour (see other comment above, also)
46 return true;
49 std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
50 if (i == world.praymanager.blocks.end()) {
51 std::cout << "PRAY FILE: couldn't find block " << name << std::endl;
52 return false;
55 prayBlock *p = i->second;
56 if (p->type != "FILE") {
57 std::cout << "PRAY FILE: block " << name << " is " << p->type << " not FILE" << std::endl;
58 // TODO: correct behaviour? possibly not..
59 return false;
62 if (!actually_install) {
63 // TODO: work out if we've tested enough
64 return true;
67 p->load();
68 std::ofstream output(outputfile.native_directory_string().c_str(), std::ios::binary);
69 output.write((char *)p->getBuffer(), p->getSize());
70 // p->unload();
72 if (type == 7) {
73 output.flush(); output.close();
74 // TODO: verify it is a catalogue file first, perhaps?
75 catalogue.addFile(outputfile);
78 return true;
81 int prayInstallDeps(std::string name, bool actually_install) {
82 std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
83 caos_assert(i != world.praymanager.blocks.end());
85 prayBlock *p = i->second;
86 p->parseTags();
88 std::map<std::string, int>::iterator j = p->integerValues.find("Agent Type");
89 if (j == p->integerValues.end()) {
90 return -1;
92 // I have no idea what this is, so let's just error out when it's not zero, pending fix. - fuzzie
93 caos_assert(j->second == 0);
95 j = p->integerValues.find("Dependency Count");
96 if (j == p->integerValues.end()) {
97 return -2;
99 int nodeps = j->second; caos_assert(nodeps >= 0);
101 for (int z = 1; z <= nodeps; z++) {
102 std::string depcatname = boost::str(boost::format("Dependency Category %d") % z);
103 std::string depname = boost::str(boost::format("Dependency %d") % z);
104 j = p->integerValues.find(depcatname);
105 if (j == p->integerValues.end()) {
106 return (-2 - nodeps - z);
108 int depcat = j->second; caos_assert(depcat >= 0 && depcat <= 11);
109 std::map<std::string, std::string>::iterator k = p->stringValues.find(depname);
110 if (k == p->stringValues.end()) {
111 return (-2 - z);
113 std::string dep = k->second;
115 // TODO: CL docs say 2*count to 3*count is the category ID for that dependency being invalid
116 if (!prayInstall(dep, depcat, actually_install)) {
117 return z;
121 return 0;
124 //used by PRAY BACK, PRAY FORE, PRAY NEXT and PRAY PREV to implement their functionality
125 std::string findBlock(std::string type, std::string last, bool forward, bool loop) {
126 prayBlock *firstblock = 0, *currblock = 0;
127 bool foundblock = false;
129 if (world.praymanager.blocks.size() == 0) return ""; // We definitely can't find anything in that case!
131 // Where do we start?
132 std::map<std::string, prayBlock *>::iterator i;
133 if (forward)
134 i = world.praymanager.blocks.begin();
135 else {
136 i = world.praymanager.blocks.end();
137 i--;
140 // Loop through all the blocks.
141 while (true) {
142 if (i->second->type == type) {
143 currblock = i->second;
145 // Store the first block if we didn't already find one, for possible use later.
146 if (!firstblock)
147 firstblock = currblock;
149 // If this is the resource we want, grab it!
150 if (foundblock)
151 return currblock->name;
153 // If this is the resource we're looking for, make a note to grab the next one.
154 if (last == currblock->name)
155 foundblock = true;
158 // Step through the list. Break if we need to.
159 if (!forward && i == world.praymanager.blocks.begin()) break;
160 if (forward) i++; else i--;
161 if (forward && i == world.praymanager.blocks.end()) break;
164 if (foundblock && loop) return firstblock->name; // loop around to first-found block
165 else if (!foundblock && currblock) return firstblock->name; // default to first-found block (XXX this is in direct opposition to what CAOS docs say!)
167 return ""; // yarr, failure.
171 PRAY AGTI (integer) resource (string) tag (string) default (integer)
172 %status maybe
174 using the specified resource, returns the integer value associated with the given tag,
175 or default if the tag doesn't exist
177 void caosVM::v_PRAY_AGTI() {
178 VM_PARAM_INTEGER(_default)
179 VM_PARAM_STRING(tag)
180 VM_PARAM_STRING(resource)
182 std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(resource);
183 caos_assert(i != world.praymanager.blocks.end());
185 prayBlock *p = i->second;
186 p->parseTags();
187 if (p->integerValues.find(tag) == p->integerValues.end())
188 result.setInt(_default);
189 else
190 result.setInt(p->integerValues[tag]);
194 PRAY AGTS (string) resource (string) tag (string) default (string)
195 %status maybe
197 using the specified resource, returns the string value associated with the given tag,
198 or default if the tag doesn't exist
200 void caosVM::v_PRAY_AGTS() {
201 VM_PARAM_STRING(_default)
202 VM_PARAM_STRING(tag)
203 VM_PARAM_STRING(resource)
205 std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(resource);
206 caos_assert(i != world.praymanager.blocks.end());
208 prayBlock *p = i->second;
209 p->parseTags();
210 if (p->stringValues.find(tag) == p->stringValues.end())
211 result.setString(_default);
212 else
213 result.setString(p->stringValues[tag]);
217 PRAY BACK (string) type (string) last (string)
218 %status maybe
220 returns the name of the resource of the specified type which is immediately previous to last
221 see PRAY PREV if you want to loop around
223 void caosVM::v_PRAY_BACK() {
224 VM_PARAM_STRING(last)
225 VM_PARAM_STRING(type)
227 result.setString(findBlock(type, last, false, false));
231 PRAY COUN (integer) type (string)
232 %status maybe
234 return the number of resources of the specified type available
236 void caosVM::v_PRAY_COUN() {
237 VM_PARAM_STRING(type)
239 unsigned int count = 0;
240 for (std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.begin(); i != world.praymanager.blocks.end(); i++)
241 if (i->second->type == type)
242 count++;
244 result.setInt(count);
248 PRAY DEPS (integer) name (string) install (integer)
249 %status maybe
251 void caosVM::v_PRAY_DEPS() {
252 VM_PARAM_INTEGER(install)
253 VM_PARAM_STRING(name)
255 result.setInt(prayInstallDeps(name, install != 0));
259 PRAY EXPO (integer) type (string)
260 %status stub
262 void caosVM::v_PRAY_EXPO() {
263 VM_PARAM_STRING(type)
265 result.setInt(0); // TODO
269 PRAY FILE (integer) name (integer) type (integer) install (integer)
270 %status maybe
272 install a file with given resource name and type
273 if install is 0, the install doesn't actually happen, it's just tested
274 returns 0 on success, 1 on failure
276 void caosVM::v_PRAY_FILE() {
277 VM_PARAM_INTEGER(install)
278 VM_PARAM_INTEGER(type)
279 VM_PARAM_STRING(name)
281 if (prayInstall(name, type, (install != 0)))
282 result.setInt(0);
283 else
284 result.setInt(1);
288 PRAY FORE (string) type (string) last (string)
289 %status maybe
291 returns the name of the resource of the specified type which is immediately after last
292 see PRAY NEXT if you want to loop around
294 void caosVM::v_PRAY_FORE() {
295 VM_PARAM_STRING(last)
296 VM_PARAM_STRING(type)
298 result.setString(findBlock(type, last, true, false));
302 PRAY GARB (command) force (integer)
303 %status stub
305 if force is 0, make the pray manager garbage-collect resources
306 otherwise, make the pray manager empty its cache entirely
308 recommended to be called after intensive PRAY usage, eg agent installation
310 void caosVM::c_PRAY_GARB() {
311 VM_PARAM_INTEGER(force)
313 // TODO
317 PRAY IMPO (integer) moniker (string) doit (integer) keepfile (integer)
318 %status stub
320 void caosVM::v_PRAY_IMPO() {
321 VM_PARAM_INTEGER(keepfile)
322 VM_PARAM_INTEGER(doit)
323 VM_PARAM_STRING(moniker)
325 result.setInt(4); // TODO
329 PRAY INJT (integer) name (string) install (integer) report (variable)
330 %status maybe
332 void caosVM::v_PRAY_INJT() {
333 VM_PARAM_VARIABLE(report)
334 VM_PARAM_INTEGER(install)
335 VM_PARAM_STRING(name)
337 // Try installing the dependencies.
338 int r = prayInstallDeps(name, install != 0);
339 if (r != 0) {
340 result.setInt(-3);
341 report->setInt(r);
342 return;
345 // Now grab the relevant block..
346 std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
347 caos_assert(i != world.praymanager.blocks.end());
348 prayBlock *p = i->second;
349 p->parseTags();
351 // .. grab the script count ..
352 std::map<std::string, int>::iterator j = p->integerValues.find("Script Count");
353 if (j == p->integerValues.end()) {
354 result.setInt(-3); // TODO: this isn't really a dependency fail, what do I do here?
355 return;
357 int noscripts = j->second; caos_assert(noscripts >= 0);
359 // .. and iterate over the scripts.
360 for (int z = 1; z <= noscripts; z++) {
361 // First, retrieve the script.
362 std::string scriptname = boost::str(boost::format("Script %d") % z);
363 std::map<std::string, std::string>::iterator k = p->stringValues.find(scriptname);
364 if (k == p->stringValues.end()) {
365 result.setInt(-1);
366 report->setString(scriptname);
367 return;
369 std::string script = k->second;
371 if (!install) continue;
373 // Then, execute it.
374 caosVM *vm = world.getVM(NULL);
375 try {
376 std::istringstream iss(script);
377 caosScript script(world.gametype, name + " - PRAY " + scriptname);
378 script.parse(iss);
379 script.installScripts();
380 vm->resetCore();
381 vm->runEntirely(script.installer);
382 } catch (std::exception &e) {
383 world.freeVM(vm);
384 result.setInt(-2);
385 report->setString(scriptname + " error: " + e.what());
386 std::cerr << "PRAY INJT caught exception trying to inject " << name << " - PRAY " << scriptname << ": " << e.what() << std::endl;
387 return;
389 world.freeVM(vm);
392 result.setInt(0);
396 PRAY KILL (integer) resource (string)
397 %status stub
399 deletes from disk the file containing the given resource
401 returns 1 upon success, or 0 upon failure (typically no such resource)
403 void caosVM::v_PRAY_KILL() {
404 VM_PARAM_STRING(resource)
406 result.setInt(0); // TODO
410 PRAY MAKE (integer) journalspot (integer) journalname (string) prayspot (integer) name (string) report (variable)
411 %status stub
413 void caosVM::v_PRAY_MAKE() {
414 VM_PARAM_VARIABLE(report)
415 VM_PARAM_STRING(name)
416 VM_PARAM_INTEGER(prayspot)
417 VM_PARAM_STRING(journalname)
418 VM_PARAM_INTEGER(journalspot)
420 result.setInt(1); // TODO
421 report->setString("hat u");
425 NET: MAKE (integer) journalspot (integer) journalname (integer) user (string) report (variable)
426 %status stub
428 Networking is not supported in openc2e, so conveniently fails.
430 void caosVM::v_NET_MAKE() {
431 VM_PARAM_VARIABLE(report)
432 VM_PARAM_STRING(user)
433 VM_PARAM_STRING(journalname)
434 VM_PARAM_INTEGER(journalspot)
436 result.setInt(1);
437 report->setString("Networking unsupported.");
441 PRAY NEXT (string) type (string) last (string)
442 %status maybe
444 returns the name of the resource of the specified type which is immediately after last
445 see PRAY FORE if you don't want to loop around
447 void caosVM::v_PRAY_NEXT() {
448 VM_PARAM_STRING(last)
449 VM_PARAM_STRING(type)
451 result.setString(findBlock(type, last, true, true));
455 PRAY PREV (string) type (string) last (string)
456 %status maybe
458 returns the name of the resource of the specified type which is immediately previous to last
459 see PRAY BACK if you don't want to loop around
461 void caosVM::v_PRAY_PREV() {
462 VM_PARAM_STRING(last)
463 VM_PARAM_STRING(type)
465 result.setString(findBlock(type, last, false, true));
469 PRAY REFR (command)
470 %status maybe
472 make the pray manager check for deleted/new files in the resource directory
474 void caosVM::c_PRAY_REFR() {
475 world.praymanager.update();
479 PRAY TEST (integer) name (string)
480 %status maybe
482 void caosVM::v_PRAY_TEST() {
483 VM_PARAM_STRING(name)
485 std::map<std::string, prayBlock *>::iterator i = world.praymanager.blocks.find(name);
486 if (i == world.praymanager.blocks.end())
487 result.setInt(0);
488 else {
489 prayBlock *p = i->second;
490 if (p->isLoaded())
491 result.setInt(1);
492 else if (p->isCompressed())
493 result.setInt(3);
494 else
495 result.setInt(2);
499 /* vim: set noet: */