always create C1/C2-style objects via the C1/C2-style constructor (SFC code changed...
[openc2e.git] / SFCFile.cpp
blobb16c46c553b87f213cd2030708edf8484318963f
1 /*
2 * SFCFile.cpp
3 * openc2e
5 * Created by Alyssa Milburn on Sat 21 Oct 2006.
6 * Copyright (c) 2006-2008 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 "SFCFile.h"
21 #include "World.h"
22 #include "Engine.h"
23 #include "MetaRoom.h"
24 #include "Room.h"
25 #include "exceptions.h"
28 * sfcdumper.py has better commentary on this format - use it for debugging
29 * and make sure to update it if you update this!
32 #define TYPE_MAPDATA 1
33 #define TYPE_CGALLERY 2
34 #define TYPE_CDOOR 3
35 #define TYPE_CROOM 4
36 #define TYPE_ENTITY 5
37 #define TYPE_COMPOUNDOBJECT 6
38 #define TYPE_BLACKBOARD 7
39 #define TYPE_VEHICLE 8
40 #define TYPE_LIFT 9
41 #define TYPE_SIMPLEOBJECT 10
42 #define TYPE_POINTERTOOL 11
43 #define TYPE_CALLBUTTON 12
44 #define TYPE_SCENERY 13
45 #define TYPE_OBJECT 100
47 #include <boost/format.hpp>
48 #define sfccheck(x) if (!(x)) throw creaturesException(std::string("failure while reading SFC file: '" #x "' in " __FILE__ " at line ") + boost::str(boost::format("%d") % __LINE__));
50 SFCFile::~SFCFile() {
51 // This contains all the objects we've constructed, so we can just zap this and
52 // everything neatly disappears.
53 for (std::vector<SFCClass *>::iterator i = storage.begin(); i != storage.end(); i++) {
54 delete *i;
58 void SFCFile::read(std::istream *i) {
59 ourStream = i;
61 mapdata = (MapData *)slurpMFC(TYPE_MAPDATA);
62 sfccheck(mapdata);
64 // TODO: hackery to seek to the next bit
65 uint8 x = 0;
66 while (x == 0) x = read8();
67 ourStream->seekg(-1, std::ios::cur);
69 uint32 numobjects = read32();
70 for (unsigned int i = 0; i < numobjects; i++) {
71 SFCObject *o = (SFCObject *)slurpMFC(TYPE_OBJECT);
72 sfccheck(o);
73 objects.push_back(o);
76 uint32 numscenery = read32();
77 for (unsigned int i = 0; i < numscenery; i++) {
78 SFCScenery *o = (SFCScenery *)slurpMFC(TYPE_SCENERY);
79 sfccheck(o);
80 scenery.push_back(o);
83 uint32 numscripts = read32();
84 for (unsigned int i = 0; i < numscripts; i++) {
85 SFCScript x;
86 x.read(this);
87 scripts.push_back(x);
90 scrollx = read32();
91 scrolly = read32();
93 // TODO
96 bool validSFCType(unsigned int type, unsigned int reqtype) {
97 if (reqtype == 0) return true;
98 if (type == reqtype) return true;
99 if ((reqtype == TYPE_OBJECT) && (type >= TYPE_COMPOUNDOBJECT)) return true;
100 if ((reqtype == TYPE_COMPOUNDOBJECT) && (type >= TYPE_COMPOUNDOBJECT) && (type <= TYPE_LIFT)) return true;
102 return false;
105 SFCClass *SFCFile::slurpMFC(unsigned int reqtype) {
106 sfccheck(!ourStream->fail());
108 // read the pid (this only works up to 0x7ffe, but we'll cope)
109 uint16 pid = read16();
111 if (pid == 0) {
112 // null object
113 return 0;
114 } else if (pid == 0xffff) {
115 // completely new class, read details
116 uint16 schemaid = read16();
117 uint16 strlen = read16();
118 char *temp = new char[strlen];
119 ourStream->read(temp, strlen);
120 std::string classname(temp, strlen);
121 delete[] temp;
123 pid = storage.size();
125 // push a null onto the stack
126 storage.push_back(0);
128 // set the types array as necessary
129 if (classname == "MapData")
130 types[pid] = TYPE_MAPDATA;
131 else if (classname == "CGallery")
132 types[pid] = TYPE_CGALLERY;
133 else if (classname == "CDoor")
134 types[pid] = TYPE_CDOOR;
135 else if (classname == "CRoom")
136 types[pid] = TYPE_CROOM;
137 else if (classname == "Entity")
138 types[pid] = TYPE_ENTITY;
139 else if (classname == "CompoundObject")
140 types[pid] = TYPE_COMPOUNDOBJECT;
141 else if (classname == "Blackboard")
142 types[pid] = TYPE_BLACKBOARD;
143 else if (classname == "Vehicle")
144 types[pid] = TYPE_VEHICLE;
145 else if (classname == "Lift")
146 types[pid] = TYPE_LIFT;
147 else if (classname == "SimpleObject")
148 types[pid] = TYPE_SIMPLEOBJECT;
149 else if (classname == "PointerTool")
150 types[pid] = TYPE_POINTERTOOL;
151 else if (classname == "CallButton")
152 types[pid] = TYPE_CALLBUTTON;
153 else if (classname == "Scenery")
154 types[pid] = TYPE_SCENERY;
155 else
156 throw creaturesException(std::string("SFCFile doesn't understand class name '") + classname + "'!");
157 } else if ((pid & 0x8000) != 0x8000) {
158 // return an existing object
159 pid -= 1;
160 sfccheck(pid < storage.size());
161 sfccheck(validSFCType(types[pid], reqtype));
162 SFCClass *temp = storage[pid];
163 sfccheck(temp);
164 return temp;
165 } else {
166 uint16 oldpid = pid;
167 // create a new object of an existing class
168 pid ^= 0x8000;
169 pid -= 1;
170 sfccheck(pid < storage.size());
171 sfccheck(!(storage[pid]));
174 SFCClass *newobj;
176 // construct new object of specified type
177 sfccheck(validSFCType(types[pid], reqtype));
178 switch (types[pid]) {
179 case TYPE_MAPDATA: newobj = new MapData(this); break;
180 case TYPE_CGALLERY: newobj = new CGallery(this); break;
181 case TYPE_CDOOR: newobj = new CDoor(this); break;
182 case TYPE_CROOM: newobj = new CRoom(this); break;
183 case TYPE_ENTITY: newobj = new SFCEntity(this); break;
184 case TYPE_COMPOUNDOBJECT: newobj = new SFCCompoundObject(this); break;
185 case TYPE_BLACKBOARD: newobj = new SFCBlackboard(this); break;
186 case TYPE_VEHICLE: newobj = new SFCVehicle(this); break;
187 case TYPE_LIFT: newobj = new SFCLift(this); break;
188 case TYPE_SIMPLEOBJECT: newobj = new SFCSimpleObject(this); break;
189 case TYPE_POINTERTOOL: newobj = new SFCPointerTool(this); break;
190 case TYPE_CALLBUTTON: newobj = new SFCCallButton(this); break;
191 case TYPE_SCENERY: newobj = new SFCScenery(this); break;
192 default:
193 throw creaturesException("SFCFile didn't find a valid type in internal variable, argh!");
196 if (validSFCType(types[pid], TYPE_COMPOUNDOBJECT)) reading_compound = true;
197 else if (types[pid] == TYPE_SCENERY) reading_scenery = true;
199 // push the object onto storage, and make it deserialize itself
200 types[storage.size()] = types[pid];
201 storage.push_back(newobj);
202 newobj->read();
204 if (validSFCType(types[pid], TYPE_COMPOUNDOBJECT)) reading_compound = false;
205 else if (types[pid] == TYPE_SCENERY) reading_scenery = false;
207 // return this new object
208 return newobj;
211 uint8 SFCFile::read8() {
212 char temp[1];
213 ourStream->read(temp, 1);
214 return temp[0];
217 uint16 SFCFile::read16() {
218 char temp[2];
219 ourStream->read(temp, 2);
220 uint16 *i = (uint16 *)&temp;
221 return swapEndianShort(*i);
224 uint32 SFCFile::read32() {
225 char temp[4];
226 ourStream->read(temp, 4);
227 uint32 *i = (uint32 *)&temp;
228 return swapEndianLong(*i);
231 std::string SFCFile::readstring() {
232 uint32 strlen = read8();
233 if (strlen == 0xff) {
234 strlen = read16();
235 if (strlen == 0xffff)
236 strlen = read32();
239 return readBytes(strlen);
242 std::string SFCFile::readBytes(unsigned int n) {
243 char *temp = new char[n];
244 ourStream->read(temp, n);
245 std::string t = std::string(temp, n);
246 delete[] temp;
247 return t;
250 void SFCFile::setVersion(unsigned int v) {
251 if (v == 0) {
252 sfccheck(world.gametype == "c1");
253 } else if (v == 1) {
254 sfccheck(world.gametype == "c2");
255 } else {
256 throw creaturesException(boost::str(boost::format("unknown version# %d") % v));
259 ver = v;
262 // ------------------------------------------------------------------
264 void MapData::read() {
265 // read version (0 = c1, 1 = c2)
266 unsigned int ver = read32();
267 sfccheck((ver == 0) || (ver == 1));
268 parent->setVersion(ver);
270 // discard unknown bytes
271 read32();
272 if (parent->version() == 1) {
273 read32();
274 read32();
277 // background sprite
278 background = (CGallery *)slurpMFC(TYPE_CGALLERY);
279 sfccheck(background);
281 // room data
282 uint32 norooms = read32();
283 for (unsigned int i = 0; i < norooms; i++) {
284 if (parent->version() == 0) {
285 CRoom *temp = new CRoom(parent);
286 temp->id = i;
287 temp->left = reads32();
288 temp->top = read32();
289 temp->right = reads32();
290 temp->bottom = read32();
291 temp->roomtype = read32();
292 sfccheck(temp->roomtype < 3);
293 rooms.push_back(temp);
294 } else {
295 CRoom *temp = (CRoom*)slurpMFC(TYPE_CROOM);
296 sfccheck(temp);
297 rooms.push_back(temp);
301 // read groundlevel data
302 if (parent->version() == 0) {
303 for (unsigned int i = 0; i < 261; i++) {
304 groundlevels[i] = read32();
307 readBytes(800); // TODO
311 MapData::~MapData() {
312 // In C1, we create rooms which aren't MFC objects, so we need to destroy them afterwards.
313 if (parent->version() == 0) {
314 for (std::vector<CRoom *>::iterator i = rooms.begin(); i != rooms.end(); i++) {
315 delete *i;
320 void CGallery::read() {
321 noframes = read32();
322 filename = parent->readBytes(4);
323 firstimg = read32();
325 // discard unknown bytes
326 read32();
328 for (unsigned int i = 0; i < noframes; i++) {
329 // discard unknown bytes
330 read8(); read8(); read8();
331 // discard width, height and offset
332 read32(); read32(); read32();
336 void CDoor::read() {
337 openness = read8();
338 otherroom = read16();
340 // discard unknown bytes
341 sfccheck(read16() == 0);
344 void CRoom::read() {
345 id = read32();
347 // magic constant?
348 sfccheck(read16() == 2);
350 left = read32();
351 top = read32();
352 right = read32();
353 bottom = read32();
355 for (unsigned int i = 0; i < 4; i++) {
356 uint16 nodoors = read16();
357 for (unsigned int j = 0; j < nodoors; j++) {
358 CDoor *temp = (CDoor*)slurpMFC(TYPE_CDOOR);
359 sfccheck(temp);
360 doors[i].push_back(temp);
364 roomtype = read32(); sfccheck(roomtype < 4);
366 floorvalue = read8();
367 inorganicnutrients = read8();
368 organicnutrients = read8();
369 temperature = read8();
370 heatsource = reads32();
372 pressure = read8();
373 pressuresource = reads32();
375 windx = reads32();
376 windy = reads32();
378 lightlevel = read8();
379 lightsource = reads32();
381 radiation = read8();
382 radiationsource = reads32();
384 // discard unknown bytes
385 readBytes(800);
387 uint16 nopoints = read16();
388 for (unsigned int i = 0; i < nopoints; i++) {
389 uint32 x = read32();
390 uint32 y = read32();
391 floorpoints.push_back(std::pair<uint32, uint32>(x, y));
394 // discard unknown bytes
395 sfccheck(read32() == 0);
397 music = readstring();
398 dropstatus = read32(); sfccheck(dropstatus < 3);
401 void SFCEntity::read() {
402 // read sprite
403 sprite = (CGallery *)slurpMFC(TYPE_CGALLERY);
404 sfccheck(sprite);
406 // read current frame and offset from base
407 currframe = read8();
408 imgoffset = read8();
410 // read zorder, x, y
411 zorder = reads32();
412 x = read32();
413 y = read32();
415 // check if this agent is animated at present
416 uint8 animbyte = read8();
417 if (animbyte) {
418 sfccheck(animbyte == 1);
419 haveanim = true;
421 // read the animation frame
422 animframe = read8();
424 // read the animation string
425 std::string tempstring;
426 if (parent->version() == 0) tempstring = readBytes(32);
427 else tempstring = readBytes(99);
428 // chop off non-null-terminated bits
429 animstring = std::string(tempstring.c_str());
430 } else haveanim = false;
432 if (parent->readingScenery()) return;
434 if (parent->readingCompound()) {
435 relx = read32();
436 rely = read32();
437 return;
440 // read part zorder
441 partzorder = read32();
443 // read bhvrclick
444 bhvrclick[0] = (signed char)read8();
445 bhvrclick[1] = (signed char)read8();
446 bhvrclick[2] = (signed char)read8();
448 // read BHVR touch
449 bhvrtouch = read8();
451 if (parent->version() == 0) return;
453 // read pickup handles/points
454 uint16 num_pickup_handles = read16();
455 for (unsigned int i = 0; i < num_pickup_handles; i++) {
456 pickup_handles.push_back(std::pair<uint32, uint32>(read32(), read32()));
458 uint16 num_pickup_points = read16();
459 for (unsigned int i = 0; i < num_pickup_points; i++) {
460 pickup_points.push_back(std::pair<uint32, uint32>(read32(), read32()));
464 void SFCObject::read() {
465 // read genus, family and species
466 if (parent->version() == 0) {
467 //sfccheck(read8() == 0);
468 read8(); // discard unused portion of CLAS, i guess (so far has been 0 or 255)
469 species = read8();
470 genus = read8();
471 family = read8();
472 } else {
473 genus = read8();
474 family = read8();
475 sfccheck(read16() == 0);
476 species = read16();
479 if (parent->version() == 0) {
480 // discard unknown byte
481 read8();
482 } else {
483 // read UNID
484 unid = read32();
486 // discard unknown byte
487 read8();
490 // read ATTR
491 if (parent->version() == 0)
492 attr = read8();
493 else
494 attr = read16();
496 // discard unknown bytes
497 if (parent->version() == 1)
498 sfccheck(read16() == 0);
500 // read unknown coords
501 left = read32();
502 top = read32();
503 right = read32();
504 bottom = read32();
506 // discard unknown bytes
507 read16();
509 // read ACTV
510 actv = read8();
512 // read sprite
513 sprite = (CGallery *)slurpMFC(TYPE_CGALLERY);
514 sfccheck(sprite);
516 tickreset = read32();
517 tickstate = read32();
518 sfccheck(tickreset >= tickstate);
520 // discard unknown bytes
521 sfccheck(read16() == 0);
523 // read currently-looping sound, if any
524 currentsound = readBytes(4);
525 if (currentsound[0] == 0)
526 currentsound.clear();
528 // read object variables
529 for (unsigned int i = 0; i < (parent->version() == 0 ? 3 : 100); i++)
530 variables[i] = read32();
532 if (parent->version() == 1) {
533 // read physics values
534 size = read8();
535 range = read32();
537 // TODO: this is mysterious and unknown
538 gravdata = read32();
540 // read physics values
541 accg = read32();
542 velx = reads32();
543 vely = reads32();
544 rest = read32();
545 aero = read32();
547 // discard unknown bytes
548 readBytes(6);
550 // read threats
551 threat = read8();
553 // read flags
554 uint8 flags = read8();
555 frozen = (flags & 0x02);
558 // read scripts
559 uint32 numscripts = read32();
560 for (unsigned int i = 0; i < numscripts; i++) {
561 SFCScript x;
562 x.read(parent);
563 scripts.push_back(x);
567 void SFCCompoundObject::read() {
568 SFCObject::read();
570 uint32 numparts = read32();
572 for (unsigned int i = 0; i < numparts; i++) {
573 SFCEntity *e = (SFCEntity *)slurpMFC(TYPE_ENTITY);
574 if (!e) {
575 sfccheck(i != 0);
576 // if entity is null, discard unknown bytes
577 readBytes(8);
579 if (i == 0) sfccheck((e->relx == 0) && (e->rely == 0));
581 // push the entity, even if it is null..
582 parts.push_back(e);
585 // read hotspot coordinates
586 for (unsigned int i = 0; i < 6; i++) {
587 hotspots[i].left = reads32();
588 hotspots[i].top = reads32();
589 hotspots[i].right = reads32();
590 hotspots[i].bottom = reads32();
593 // read hotspot function data
594 for (unsigned int i = 0; i < 6; i++) {
595 // (this is actually a map of function->hotspot)
596 hotspots[i].function = reads32();
599 if (parent->version() == 1) {
600 // read C2-specific hotspot function data (again, actually maps function->hotspot)
601 for (unsigned int i = 0; i < 6; i++) {
602 hotspots[i].message = read16();
603 sfccheck(read16() == 0);
605 for (unsigned int i = 0; i < 6; i++) {
606 hotspots[i].mask = read8();
611 void SFCBlackboard::read() {
612 SFCCompoundObject::read();
614 // read text x/y position and colours
615 if (parent->version() == 0) {
616 backgroundcolour = read8();
617 chalkcolour = read8();
618 aliascolour = read8();
619 textx = read8();
620 texty = read8();
621 } else {
622 backgroundcolour = read32();
623 chalkcolour = read32();
624 aliascolour = read32();
625 textx = read8();
626 texty = read8();
629 // read blackboard strings
630 for (unsigned int i = 0; i < (parent->version() == 0 ? 16 : 48); i++) {
631 uint32 value = read32();
632 std::string str = readBytes(11);
633 // chop off non-null-terminated bits
634 str = std::string(str.c_str());
635 strings.push_back(std::pair<uint32, std::string>(value, str));
639 void SFCVehicle::read() {
640 SFCCompoundObject::read();
642 xvec = reads32();
643 yvec = reads32();
644 bump = read8();
646 // discard unknown bytes
647 read16();
648 unsigned short x = read16();
649 if (parent->version() == 1)
650 sfccheck(x == 0);
651 read16();
652 sfccheck(read8() == 0);
654 // read cabin boundaries
655 cabinleft = read32();
656 cabintop = read32();
657 cabinright = read32();
658 cabinbottom = read32();
660 // discard unknown bytes
661 sfccheck(read32() == 0);
664 void SFCLift::read() {
665 SFCVehicle::read();
667 nobuttons = read32();
668 currentbutton = read32();
670 // discard unknown bytes
671 sfccheck(readBytes(5) == std::string("\xff\xff\xff\xff\x00", 5));
673 for (unsigned int i = 0; i < 8; i++) {
674 callbuttony[i] = read32();
676 // discard unknown bytes
677 sfccheck(read16() == 0);
680 if (parent->version() == 1) {
681 int somedata = read32();
682 alignwithcabin = (somedata != 0); // TODO: is this right?
686 void SFCSimpleObject::read() {
687 SFCObject::read();
689 entity = (SFCEntity *)slurpMFC(TYPE_ENTITY);
692 void SFCPointerTool::read() {
693 SFCSimpleObject::read();
695 // discard unknown bytes
696 if (parent->version() == 0)
697 readBytes(35);
698 else
699 readBytes(51);
702 void SFCCallButton::read() {
703 SFCSimpleObject::read();
705 ourLift = (SFCLift *)slurpMFC(TYPE_LIFT);
706 liftid = read8();
709 void SFCScript::read(SFCFile *f) {
710 if (f->version() == 0) {
711 eventno = f->read8();
712 species = f->read8();
713 genus = f->read8();
714 family = f->read8();
715 } else {
716 genus = f->read8();
717 family = f->read8();
718 eventno = f->read16();
719 species = f->read16();
721 data = f->readstring();
724 // ------------------------------------------------------------------
726 void SFCFile::copyToWorld() {
727 // add the map data
728 mapdata->copyToWorld();
730 // install scripts
731 for (std::vector<SFCScript>::iterator i = scripts.begin(); i != scripts.end(); i++) {
732 i->install();
735 // create normal objects
736 for (std::vector<SFCObject *>::iterator i = objects.begin(); i != objects.end(); i++) {
737 (*i)->copyToWorld();
740 // create scenery
741 for (std::vector<SFCScenery *>::iterator i = scenery.begin(); i != scenery.end(); i++) {
742 (*i)->copyToWorld();
745 // move the camera to the correct position
746 world.camera.moveTo(scrollx, scrolly, jump);
748 // patch agents
749 // TODO: do we really need to do this, and if so, should it be done here?
750 // I like this for now because it makes debugging suck a lot less - fuzzie
751 for (std::list<boost::shared_ptr<Agent> >::iterator i = world.agents.begin(); i != world.agents.end(); i++) {
752 boost::shared_ptr<Agent> a = (*i);
754 #define NUM_SFC_PATCHES 5
756 /* version, family, genus, species, variable# */
757 unsigned int patchdata[NUM_SFC_PATCHES][5] = {
758 { 1, 2, 20, 10, 10 }, // c2's Pitz
759 { 1, 2, 17, 2, 1 }, // c2's bees
760 { 1, 2, 1, 50, 0 }, // c2 flask thing
761 { 1, 2, 25, 1, 1}, // c2 tomatoes
762 { 1, 2, 25, 6, 1} // c2 nuts
765 for (unsigned int j = 0; j < NUM_SFC_PATCHES; j++) {
766 if (version() == patchdata[j][0] && a->family == patchdata[j][1] && a->genus == patchdata[j][2] && a->species == patchdata[j][3]) {
767 // patch variable to actually refer to an agent
768 unsigned int varno = patchdata[j][4];
769 for (std::vector<SFCObject *>::iterator i = objects.begin(); i != objects.end(); i++) {
770 if ((*i)->unid == (uint32)a->var[varno].getInt()) {
771 a->var[varno].setAgent((*i)->copiedAgent());
772 break;
776 if (a->var[varno].hasInt()) {
777 a->var[varno].setAgent(0);
778 // This is useful to enable when you're testing a new patch.
779 //std::cout << "Warning: Couldn't apply agent patch #" << j << "!" << std::endl;
786 #include "sprImage.h"
787 #include <iostream>
789 void MapData::copyToWorld() {
790 // find the background sprite
791 shared_ptr<creaturesImage> spr = world.gallery.getImage(background->filename);
792 sfccheck(spr);
794 // check for Terra Nornia's corrupt background sprite
795 if (background->filename == "buro") {
796 // apply stupid hack
797 // TODO: can't we have a better check, eg checking if offsets are identical?
798 std::cout << "Applying hack for probably-corrupt Terra Nornia background." << std::endl;
799 sprImage *buro = dynamic_cast<sprImage *>(spr.get());
800 if (buro)
801 buro->fixBufferOffsets();
804 // create the global metaroom
805 // TODO: hardcoded size bad?
806 unsigned int w = parent->version() == 0 ? 1200 : 2400;
807 MetaRoom *m = new MetaRoom(0, 0, 8352, w, background->filename, spr, true);
808 world.map.addMetaRoom(m);
810 for (std::vector<CRoom *>::iterator i = rooms.begin(); i != rooms.end(); i++) {
811 // retrieve our room data
812 CRoom *src = *i;
814 // create a new room, set the type
815 shared_ptr<Room> r(new Room(src->left, src->right, src->top, src->top, src->bottom, src->bottom));
816 r->type.setInt(src->roomtype);
818 // add the room to the world, ensure it matches the id we retrieved
819 unsigned int roomid = m->addRoom(r);
820 // TODO: correct check?
821 sfccheck(roomid == src->id);
823 if (parent->version() == 1) {
824 // set floor points
825 r->floorpoints = src->floorpoints;
827 // set CAs
828 r->intr.setInt(src->inorganicnutrients);
829 r->ontr.setInt(src->organicnutrients);
830 r->temp.setInt(src->temperature);
831 r->pres.setInt(src->pressure);
832 r->lite.setInt(src->lightlevel);
833 r->radn.setInt(src->radiation);
834 r->hsrc.setInt(src->heatsource);
835 r->psrc.setInt(src->pressuresource);
836 r->lsrc.setInt(src->lightsource);
837 r->rsrc.setInt(src->radiationsource);
839 // set wind x/y
840 r->windx = src->windx;
841 r->windy = src->windy;
843 r->dropstatus.setInt(src->dropstatus);
844 r->floorvalue.setInt(src->floorvalue);
846 r->music = src->music;
850 if (parent->version() == 0) {
851 for (unsigned int i = 0; i < 261; i++) {
852 world.groundlevels.push_back(groundlevels[i]);
855 return;
858 for (std::vector<CRoom *>::iterator i = rooms.begin(); i != rooms.end(); i++) {
859 CRoom *src = *i;
861 for (unsigned int j = 0; j < 4; j++) {
862 for (std::vector<CDoor *>::iterator k = src->doors[j].begin(); k < src->doors[j].end(); k++) {
863 CDoor *door = *k;
864 shared_ptr<Room> r1 = world.map.getRoom(src->id);
865 shared_ptr<Room> r2 = world.map.getRoom(door->otherroom);
867 if (r1->doors.find(r2) == r1->doors.end()) {
868 // create a new door between rooms!
869 RoomDoor *roomdoor = new RoomDoor();
870 roomdoor->first = r1;
871 roomdoor->second = r2;
872 roomdoor->perm = door->openness;
873 r1->doors[r2] = roomdoor;
874 r2->doors[r1] = roomdoor;
875 // TODO: ADDR adds to nearby?
876 } else {
877 // sanity check
878 RoomDoor *roomdoor = r1->doors[r2];
879 sfccheck(roomdoor->perm == door->openness);
885 // TODO: misc data?
888 void copyEntityData(SFCEntity *entity, DullPart *p) {
889 // pose
890 p->setBase(entity->imgoffset);
891 p->setPose(entity->currframe - entity->imgoffset);
893 // animation
894 if (entity->haveanim) {
895 for (unsigned int i = 0; i < entity->animstring.size(); i++) {
896 if (entity->animstring[i] == 'R')
897 p->animation.push_back(255);
898 else {
899 sfccheck(entity->animstring[i] >= 48 && entity->animstring[i] <= 57);
900 p->animation.push_back(entity->animstring[i] - 48);
904 // TODO: should make sure animation position == current pose
905 if (entity->animframe < p->animation.size()) {
906 if (p->animation[entity->animframe] == 255)
907 p->setFrameNo(0);
908 else
909 p->setFrameNo(entity->animframe);
910 } else p->animation.clear();
914 #include "CompoundAgent.h"
916 void SFCCompoundObject::copyToWorld() {
917 sfccheck(parts.size() > 0);
919 // construct our equivalent object, if necessary
920 if (!ourAgent)
921 ourAgent = new CompoundAgent(parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes);
922 ourAgent->setClassifier(family, genus, species);
924 // initialise the agent, move it into position
925 CompoundAgent *a = ourAgent;
926 a->finishInit();
927 a->moveTo(parts[0]->x, parts[0]->y);
928 a->queueScript(7); // enter scope
930 if (parent->version() == 1) world.setUNID(a, unid);
932 // TODO: c1 attributes!
933 // C2 attributes are a subset of c2e ones
934 a->setAttributes(attr);
936 a->actv.setInt(actv);
937 // TODO: this is to activate mover scripts in c1, does it apply to c2 too? is it correct at all?
938 if ((parent->version() == 0) && actv) { a->actv.setInt(0); a->queueScript(actv); }
940 // ticking
941 a->tickssincelasttimer = tickstate;
942 if (a->tickssincelasttimer == tickreset) a->tickssincelasttimer = 0;
943 a->timerrate = tickreset;
945 for (unsigned int i = 0; i < (parent->version() == 0 ? 3 : 100); i++)
946 a->var[i].setInt(variables[i]);
948 if (parent->version() == 1) {
949 a->size.setInt(size);
950 a->thrt.setInt(threat);
951 a->range.setInt(range);
952 a->accg.setInt(accg);
953 a->grav.setInt(gravdata == 0xFFFFFFFF ? 0 : 1); // TODO
954 a->velx.setInt(velx);
955 a->vely.setInt(vely);
956 a->rest.setInt(rest);
957 a->aero.setInt(aero);
958 a->paused = frozen; // TODO
961 for (unsigned int i = 0; i < parts.size(); i++) {
962 SFCEntity *e = parts[i];
963 if (!e) continue;
964 DullPart *p;
965 if (i == 0)
966 p = new DullPart(a, i, e->sprite->filename, e->sprite->firstimg, e->relx, e->rely, e->zorder);
967 else
968 p = new DullPart(a, i, e->sprite->filename, e->sprite->firstimg, e->relx, e->rely, e->zorder - parts[0]->zorder);
969 a->addPart(p);
971 copyEntityData(e, p);
974 // add hotspots
975 for (unsigned int i = 0; i < 6; i++) {
976 a->setHotspotLoc(i, hotspots[i].left, hotspots[i].top, hotspots[i].right, hotspots[i].bottom);
977 a->setHotspotFunc(i, hotspots[i].function);
978 if (parent->version() == 1) {
979 a->setHotspotFuncDetails(i, hotspots[i].message, hotspots[i].mask);
983 if (currentsound.size() != 0) {
984 a->playAudio(currentsound, true, true);
988 #include "SimpleAgent.h"
990 void SFCSimpleObject::copyToWorld() {
991 // construct our equivalent object
992 if (!ourAgent) {
993 ourAgent = new SimpleAgent(family, genus, species, entity->zorder, sprite->filename, sprite->firstimg, sprite->noframes);
995 SimpleAgent *a = ourAgent;
997 a->finishInit();
998 //a->moveTo(entity->x - (a->part(0)->getWidth() / 2), entity->y - (a->part(0) -> getHeight() / 2));
999 a->moveTo(entity->x, entity->y);
1000 a->queueScript(7); // enter scope
1002 if (parent->version() == 1) world.setUNID(a, unid);
1004 // copy data from ourselves
1006 // TODO: c1 attributes!
1007 // C2 attributes are a subset of c2e ones
1008 a->setAttributes(attr);
1010 a->actv.setInt(actv);
1011 // TODO: this is to activate mover scripts in c1, does it apply to c2 too? is it correct at all?
1012 if ((parent->version() == 0) && actv) a->queueScript(actv);
1014 // copy bhvrclick data
1015 a->clac[0] = entity->bhvrclick[0];
1016 a->clac[1] = entity->bhvrclick[1];
1017 a->clac[2] = entity->bhvrclick[2];
1019 // ticking
1020 a->tickssincelasttimer = tickstate;
1021 if (a->tickssincelasttimer == tickreset) a->tickssincelasttimer = 0;
1022 a->timerrate = tickreset;
1024 for (unsigned int i = 0; i < (parent->version() == 0 ? 3 : 100); i++)
1025 a->var[i].setInt(variables[i]);
1027 if (parent->version() == 1) {
1028 a->size.setInt(size);
1029 a->thrt.setInt(threat);
1030 a->range.setInt(range);
1031 a->accg.setInt(accg);
1032 a->grav.setInt(gravdata == 0xFFFFFFFF ? 0 : 1); // TODO
1033 a->velx.setInt(velx);
1034 a->vely.setInt(vely);
1035 a->rest.setInt(rest);
1036 a->aero.setInt(aero);
1037 a->paused = frozen; // TODO
1040 // copy data from entity
1041 DullPart *p = (DullPart *)a->part(0);
1042 copyEntityData(entity, p);
1044 // TODO: bhvr
1045 // TODO: pickup handles/points
1047 if (currentsound.size() != 0) {
1048 a->playAudio(currentsound, true, true);
1052 #include "PointerAgent.h"
1053 void SFCPointerTool::copyToWorld() {
1054 world.hand()->setClassifier(family, genus, species);
1055 world.hand()->setZOrder(entity->zorder);
1056 world.hand()->setHotspot(2, 2); // TODO: we should really copy this out of the SFC file (the first two numbers in the unknown data?)
1058 ourAgent = world.hand();
1059 SFCSimpleObject::copyToWorld(); // TODO: think about this call some more, is it appropriate for an already-finished agent?
1062 #include "Blackboard.h"
1064 void SFCBlackboard::copyToWorld() {
1065 ourAgent = new Blackboard(parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes, textx, texty, backgroundcolour, chalkcolour, aliascolour);
1066 Blackboard *a = dynamic_cast<Blackboard *>(ourAgent);
1068 SFCCompoundObject::copyToWorld();
1070 for (unsigned int i = 0; i < strings.size(); i++) {
1071 a->addBlackboardString(i, strings[i].first, strings[i].second);
1075 #include "Vehicle.h"
1077 void SFCVehicle::copyToWorld() {
1078 if (!ourAgent) {
1079 ourAgent = new Vehicle(parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes);
1081 Vehicle *a = dynamic_cast<Vehicle *>(ourAgent);
1082 assert(a);
1084 SFCCompoundObject::copyToWorld();
1086 // set cabin rectangle and plane
1087 a->setCabinRect(cabinleft, cabintop, cabinright, cabinbottom);
1088 a->cabinplane = 95; // TODO: arbitarily-chosen value (see also Vehicle constructor)
1090 // set bump, xvec and yvec
1091 a->bump = bump;
1092 a->xvec.setInt(xvec);
1093 a->yvec.setInt(yvec);
1096 #include "Lift.h"
1098 void SFCLift::copyToWorld() {
1099 Lift *a = new Lift(parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes);
1100 ourAgent = a;
1102 SFCVehicle::copyToWorld();
1104 // set current button
1105 a->currentbutton = a->newbutton = currentbutton;
1107 // set call button y locations
1108 for (unsigned int i = 0; i < nobuttons; i++) {
1109 a->callbuttony.push_back(callbuttony[i]);
1112 if (parent->version() == 1) {
1113 a->alignwithcabin = alignwithcabin;
1117 #include "CallButton.h"
1119 void SFCCallButton::copyToWorld() {
1120 CallButton *a = new CallButton(family, genus, species, entity->zorder, sprite->filename, sprite->firstimg, sprite->noframes);
1121 ourAgent = a;
1123 SFCSimpleObject::copyToWorld();
1125 // set lift
1126 sfccheck(ourLift->ourAgent);
1127 assert(dynamic_cast<Lift *>(ourLift->ourAgent));
1128 a->lift = ourLift->ourAgent;
1130 a->buttonid = liftid;
1133 void SFCScenery::copyToWorld() {
1134 SFCSimpleObject::copyToWorld();
1135 SpritePart *p = dynamic_cast<SpritePart *>(ourAgent->part(0));
1136 assert(p);
1137 p->is_transparent = true;
1140 #include <boost/format.hpp>
1141 #include <sstream>
1143 #include "caosScript.h"
1145 void SFCScript::install() {
1146 std::string scriptinfo = boost::str(boost::format("<SFC script %d, %d, %d: %d>") % (int)family % (int)genus % species % eventno);
1147 caosScript script(world.gametype, scriptinfo);
1148 std::istringstream s(data);
1149 try {
1150 script.parse(s);
1151 script.installInstallScript(family, genus, species, eventno);
1152 script.installScripts();
1153 } catch (creaturesException &e) {
1154 std::cerr << "installation of \"" << scriptinfo << "\" failed due to exception " << e.prettyPrint() << std::endl;
1155 } catch (std::exception &e) {
1156 std::cerr << "installation of \"" << scriptinfo << "\" failed due to exception " << e.what() << std::endl;
1160 /* vim: set noet: */