handle drops before the drop script is fired, move the C1 snapping code to after...
[openc2e.git] / SFCFile.cpp
blobfa366920aaab7113844df1b1d9c077dfd01d75d4
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 read32(); // TODO
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 // discard unknown bytes
681 if (parent->version() == 1)
682 read32();
685 void SFCSimpleObject::read() {
686 SFCObject::read();
688 entity = (SFCEntity *)slurpMFC(TYPE_ENTITY);
691 void SFCPointerTool::read() {
692 SFCSimpleObject::read();
694 // discard unknown bytes
695 if (parent->version() == 0)
696 readBytes(35);
697 else
698 readBytes(51);
701 void SFCCallButton::read() {
702 SFCSimpleObject::read();
704 ourLift = (SFCLift *)slurpMFC(TYPE_LIFT);
705 liftid = read8();
708 void SFCScript::read(SFCFile *f) {
709 if (f->version() == 0) {
710 eventno = f->read8();
711 species = f->read8();
712 genus = f->read8();
713 family = f->read8();
714 } else {
715 genus = f->read8();
716 family = f->read8();
717 eventno = f->read16();
718 species = f->read16();
720 data = f->readstring();
723 // ------------------------------------------------------------------
725 void SFCFile::copyToWorld() {
726 // add the map data
727 mapdata->copyToWorld();
729 // install scripts
730 for (std::vector<SFCScript>::iterator i = scripts.begin(); i != scripts.end(); i++) {
731 i->install();
734 // create normal objects
735 for (std::vector<SFCObject *>::iterator i = objects.begin(); i != objects.end(); i++) {
736 (*i)->copyToWorld();
739 // create scenery
740 for (std::vector<SFCScenery *>::iterator i = scenery.begin(); i != scenery.end(); i++) {
741 (*i)->copyToWorld();
744 // move the camera to the correct position
745 world.camera.moveTo(scrollx, scrolly, jump);
747 // patch agents
748 // TODO: do we really need to do this, and if so, should it be done here?
749 // I like this for now because it makes debugging suck a lot less - fuzzie
750 for (std::list<boost::shared_ptr<Agent> >::iterator i = world.agents.begin(); i != world.agents.end(); i++) {
751 boost::shared_ptr<Agent> a = (*i);
753 #define NUM_SFC_PATCHES 5
755 /* version, family, genus, species, variable# */
756 unsigned int patchdata[NUM_SFC_PATCHES][5] = {
757 { 1, 2, 20, 10, 10 }, // c2's Pitz
758 { 1, 2, 17, 2, 1 }, // c2's bees
759 { 1, 2, 1, 50, 0 }, // c2 flask thing
760 { 1, 2, 25, 1, 1}, // c2 tomatoes
761 { 1, 2, 25, 6, 1} // c2 nuts
764 for (unsigned int j = 0; j < NUM_SFC_PATCHES; j++) {
765 if (version() == patchdata[j][0] && a->family == patchdata[j][1] && a->genus == patchdata[j][2] && a->species == patchdata[j][3]) {
766 // patch variable to actually refer to an agent
767 unsigned int varno = patchdata[j][4];
768 for (std::vector<SFCObject *>::iterator i = objects.begin(); i != objects.end(); i++) {
769 if ((*i)->unid == (uint32)a->var[varno].getInt()) {
770 a->var[varno].setAgent((*i)->copiedAgent());
771 break;
775 if (a->var[varno].hasInt()) {
776 a->var[varno].setAgent(0);
777 // This is useful to enable when you're testing a new patch.
778 //std::cout << "Warning: Couldn't apply agent patch #" << j << "!" << std::endl;
785 #include "sprImage.h"
786 #include <iostream>
788 void MapData::copyToWorld() {
789 // find the background sprite
790 shared_ptr<creaturesImage> spr = world.gallery.getImage(background->filename);
791 sfccheck(spr);
793 // check for Terra Nornia's corrupt background sprite
794 if (background->filename == "buro") {
795 // apply stupid hack
796 // TODO: can't we have a better check, eg checking if offsets are identical?
797 std::cout << "Applying hack for probably-corrupt Terra Nornia background." << std::endl;
798 sprImage *buro = dynamic_cast<sprImage *>(spr.get());
799 if (buro)
800 buro->fixBufferOffsets();
803 // create the global metaroom
804 // TODO: hardcoded size bad?
805 unsigned int w = parent->version() == 0 ? 1200 : 2400;
806 MetaRoom *m = new MetaRoom(0, 0, 8352, w, background->filename, spr, true);
807 world.map.addMetaRoom(m);
809 for (std::vector<CRoom *>::iterator i = rooms.begin(); i != rooms.end(); i++) {
810 // retrieve our room data
811 CRoom *src = *i;
813 // create a new room, set the type
814 shared_ptr<Room> r(new Room(src->left, src->right, src->top, src->top, src->bottom, src->bottom));
815 r->type.setInt(src->roomtype);
817 // add the room to the world, ensure it matches the id we retrieved
818 unsigned int roomid = m->addRoom(r);
819 // TODO: correct check?
820 sfccheck(roomid == src->id);
822 if (parent->version() == 1) {
823 // set floor points
824 r->floorpoints = src->floorpoints;
826 // set CAs
827 r->intr.setInt(src->inorganicnutrients);
828 r->ontr.setInt(src->organicnutrients);
829 r->temp.setInt(src->temperature);
830 r->pres.setInt(src->pressure);
831 r->lite.setInt(src->lightlevel);
832 r->radn.setInt(src->radiation);
833 r->hsrc.setInt(src->heatsource);
834 r->psrc.setInt(src->pressuresource);
835 r->lsrc.setInt(src->lightsource);
836 r->rsrc.setInt(src->radiationsource);
838 // set wind x/y
839 r->windx = src->windx;
840 r->windy = src->windy;
842 r->dropstatus.setInt(src->dropstatus);
843 r->floorvalue.setInt(src->floorvalue);
845 r->music = src->music;
849 if (parent->version() == 0) return;
851 for (std::vector<CRoom *>::iterator i = rooms.begin(); i != rooms.end(); i++) {
852 CRoom *src = *i;
854 for (unsigned int j = 0; j < 4; j++) {
855 for (std::vector<CDoor *>::iterator k = src->doors[j].begin(); k < src->doors[j].end(); k++) {
856 CDoor *door = *k;
857 shared_ptr<Room> r1 = world.map.getRoom(src->id);
858 shared_ptr<Room> r2 = world.map.getRoom(door->otherroom);
860 if (r1->doors.find(r2) == r1->doors.end()) {
861 // create a new door between rooms!
862 RoomDoor *roomdoor = new RoomDoor();
863 roomdoor->first = r1;
864 roomdoor->second = r2;
865 roomdoor->perm = door->openness;
866 r1->doors[r2] = roomdoor;
867 r2->doors[r1] = roomdoor;
868 // TODO: ADDR adds to nearby?
869 } else {
870 // sanity check
871 RoomDoor *roomdoor = r1->doors[r2];
872 sfccheck(roomdoor->perm == door->openness);
878 // TODO: misc data?
881 void copyEntityData(SFCEntity *entity, DullPart *p) {
882 // pose
883 p->setBase(entity->imgoffset);
884 p->setPose(entity->currframe - entity->imgoffset);
886 // animation
887 if (entity->haveanim) {
888 for (unsigned int i = 0; i < entity->animstring.size(); i++) {
889 if (entity->animstring[i] == 'R')
890 p->animation.push_back(255);
891 else {
892 sfccheck(entity->animstring[i] >= 48 && entity->animstring[i] <= 57);
893 p->animation.push_back(entity->animstring[i] - 48);
897 // TODO: should make sure animation position == current pose
898 if (entity->animframe < p->animation.size()) {
899 if (p->animation[entity->animframe] == 255)
900 p->setFrameNo(0);
901 else
902 p->setFrameNo(entity->animframe);
903 } else p->animation.clear();
907 #include "CompoundAgent.h"
909 void SFCCompoundObject::copyToWorld() {
910 sfccheck(parts.size() > 0);
912 // construct our equivalent object, if necessary
913 if (!ourAgent)
914 ourAgent = new CompoundAgent(family, genus, species, parts[0]->zorder, parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes);
916 // initialise the agent, move it into position
917 CompoundAgent *a = ourAgent;
918 a->finishInit();
919 a->moveTo(parts[0]->x, parts[0]->y);
920 a->queueScript(7); // enter scope
922 if (parent->version() == 1) world.setUNID(a, unid);
924 // TODO: c1 attributes!
925 // C2 attributes are a subset of c2e ones
926 a->setAttributes(attr);
928 a->actv.setInt(actv);
929 // TODO: this is to activate mover scripts in c1, does it apply to c2 too? is it correct at all?
930 if ((parent->version() == 0) && actv) { a->actv.setInt(0); a->queueScript(actv); }
932 // ticking
933 a->tickssincelasttimer = tickstate;
934 if (a->tickssincelasttimer == tickreset) a->tickssincelasttimer = 0;
935 a->timerrate = tickreset;
937 for (unsigned int i = 0; i < (parent->version() == 0 ? 3 : 100); i++)
938 a->var[i].setInt(variables[i]);
940 if (parent->version() == 1) {
941 a->size.setInt(size);
942 a->thrt.setInt(threat);
943 a->range.setInt(range);
944 a->accg.setInt(accg);
945 a->grav.setInt(gravdata == 0xFFFFFFFF ? 0 : 1); // TODO
946 a->velx.setInt(velx);
947 a->vely.setInt(vely);
948 a->rest.setInt(rest);
949 a->aero.setInt(aero);
950 a->paused = frozen; // TODO
953 for (unsigned int i = 0; i < parts.size(); i++) {
954 SFCEntity *e = parts[i];
955 if (!e) continue;
956 DullPart *p;
957 if (i == 0) {
958 p = (DullPart *)a->part(0);
959 } else {
960 p = new DullPart(a, i, e->sprite->filename, e->sprite->firstimg, e->relx, e->rely, e->zorder - parts[0]->zorder);
961 a->addPart(p);
964 copyEntityData(e, p);
967 // add hotspots
968 for (unsigned int i = 0; i < 6; i++) {
969 a->setHotspotLoc(i, hotspots[i].left, hotspots[i].top, hotspots[i].right, hotspots[i].bottom);
970 a->setHotspotFunc(i, hotspots[i].function);
971 if (parent->version() == 1) {
972 a->setHotspotFuncDetails(i, hotspots[i].message, hotspots[i].mask);
976 if (currentsound.size() != 0) {
977 a->playAudio(currentsound, true, true);
981 #include "SimpleAgent.h"
983 void SFCSimpleObject::copyToWorld() {
984 // construct our equivalent object
985 if (!ourAgent) {
986 ourAgent = new SimpleAgent(family, genus, species, entity->zorder, sprite->filename, sprite->firstimg, sprite->noframes);
988 SimpleAgent *a = ourAgent;
990 a->finishInit();
991 //a->moveTo(entity->x - (a->part(0)->getWidth() / 2), entity->y - (a->part(0) -> getHeight() / 2));
992 a->moveTo(entity->x, entity->y);
993 a->queueScript(7); // enter scope
995 if (parent->version() == 1) world.setUNID(a, unid);
997 // copy data from ourselves
999 // TODO: c1 attributes!
1000 // C2 attributes are a subset of c2e ones
1001 a->setAttributes(attr);
1003 a->actv.setInt(actv);
1004 // TODO: this is to activate mover scripts in c1, does it apply to c2 too? is it correct at all?
1005 if ((parent->version() == 0) && actv) a->queueScript(actv);
1007 // copy bhvrclick data
1008 a->clac[0] = entity->bhvrclick[0];
1009 a->clac[1] = entity->bhvrclick[1];
1010 a->clac[2] = entity->bhvrclick[2];
1012 // ticking
1013 a->tickssincelasttimer = tickstate;
1014 if (a->tickssincelasttimer == tickreset) a->tickssincelasttimer = 0;
1015 a->timerrate = tickreset;
1017 for (unsigned int i = 0; i < (parent->version() == 0 ? 3 : 100); i++)
1018 a->var[i].setInt(variables[i]);
1020 if (parent->version() == 1) {
1021 a->size.setInt(size);
1022 a->thrt.setInt(threat);
1023 a->range.setInt(range);
1024 a->accg.setInt(accg);
1025 a->grav.setInt(gravdata == 0xFFFFFFFF ? 0 : 1); // TODO
1026 a->velx.setInt(velx);
1027 a->vely.setInt(vely);
1028 a->rest.setInt(rest);
1029 a->aero.setInt(aero);
1030 a->paused = frozen; // TODO
1033 // copy data from entity
1034 DullPart *p = (DullPart *)a->part(0);
1035 copyEntityData(entity, p);
1037 // TODO: bhvr
1038 // TODO: pickup handles/points
1040 if (currentsound.size() != 0) {
1041 a->playAudio(currentsound, true, true);
1045 void SFCPointerTool::copyToWorld() {
1046 // don't copy the cursor, for now at least :-)
1049 #include "Blackboard.h"
1051 void SFCBlackboard::copyToWorld() {
1052 ourAgent = new Blackboard(family, genus, species, parts[0]->zorder, parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes, textx, texty, backgroundcolour, chalkcolour, aliascolour);
1053 Blackboard *a = dynamic_cast<Blackboard *>(ourAgent);
1055 SFCCompoundObject::copyToWorld();
1057 for (unsigned int i = 0; i < strings.size(); i++) {
1058 a->addBlackboardString(i, strings[i].first, strings[i].second);
1062 #include "Vehicle.h"
1064 void SFCVehicle::copyToWorld() {
1065 if (!ourAgent) {
1066 ourAgent = new Vehicle(family, genus, species, parts[0]->zorder, parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes);
1068 Vehicle *a = dynamic_cast<Vehicle *>(ourAgent);
1069 assert(a);
1071 SFCCompoundObject::copyToWorld();
1073 // set cabin rectangle and plane
1074 a->setCabinRect(cabinleft, cabintop, cabinright, cabinbottom);
1075 a->cabinplane = 95; // TODO: arbitarily-chosen value (see also Vehicle constructor)
1077 // set bump, xvec and yvec
1078 a->bump = bump;
1079 a->xvec.setInt(xvec);
1080 a->yvec.setInt(yvec);
1083 #include "Lift.h"
1085 void SFCLift::copyToWorld() {
1086 Lift *a = new Lift(family, genus, species, parts[0]->zorder, parts[0]->sprite->filename, parts[0]->sprite->firstimg, parts[0]->sprite->noframes);
1087 ourAgent = a;
1089 SFCVehicle::copyToWorld();
1091 // set current button
1092 a->currentbutton = currentbutton;
1094 // set call button y locations
1095 for (unsigned int i = 0; i < nobuttons; i++) {
1096 a->callbuttony.push_back(callbuttony[i]);
1100 #include "CallButton.h"
1102 void SFCCallButton::copyToWorld() {
1103 CallButton *a = new CallButton(family, genus, species, entity->zorder, sprite->filename, sprite->firstimg, sprite->noframes);
1104 ourAgent = a;
1106 SFCSimpleObject::copyToWorld();
1108 // set lift
1109 sfccheck(ourLift->ourAgent);
1110 assert(dynamic_cast<Lift *>(ourLift->ourAgent));
1111 a->lift = ourLift->ourAgent;
1113 a->buttonid = liftid;
1116 void SFCScenery::copyToWorld() {
1117 SFCSimpleObject::copyToWorld();
1118 SpritePart *p = dynamic_cast<SpritePart *>(ourAgent->part(0));
1119 assert(p);
1120 p->is_transparent = true;
1123 #include <boost/format.hpp>
1124 #include <sstream>
1126 #include "caosScript.h"
1128 void SFCScript::install() {
1129 std::string scriptinfo = boost::str(boost::format("<SFC script %d, %d, %d: %d>") % (int)family % (int)genus % species % eventno);
1130 caosScript script(world.gametype, scriptinfo);
1131 std::istringstream s(data);
1132 try {
1133 script.parse(s);
1134 script.installInstallScript(family, genus, species, eventno);
1135 script.installScripts();
1136 } catch (creaturesException &e) {
1137 std::cerr << "installation of \"" << scriptinfo << "\" failed due to exception " << e.prettyPrint() << std::endl;
1138 } catch (std::exception &e) {
1139 std::cerr << "installation of \"" << scriptinfo << "\" failed due to exception " << e.what() << std::endl;
1143 /* vim: set noet: */