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.
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
37 #define TYPE_COMPOUNDOBJECT 6
38 #define TYPE_BLACKBOARD 7
39 #define TYPE_VEHICLE 8
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__));
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
++) {
58 void SFCFile::read(std::istream
*i
) {
61 mapdata
= (MapData
*)slurpMFC(TYPE_MAPDATA
);
64 // TODO: hackery to seek to the next bit
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
);
76 uint32 numscenery
= read32();
77 for (unsigned int i
= 0; i
< numscenery
; i
++) {
78 SFCScenery
*o
= (SFCScenery
*)slurpMFC(TYPE_SCENERY
);
83 uint32 numscripts
= read32();
84 for (unsigned int i
= 0; i
< numscripts
; i
++) {
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;
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();
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
);
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
;
156 throw creaturesException(std::string("SFCFile doesn't understand class name '") + classname
+ "'!");
157 } else if ((pid
& 0x8000) != 0x8000) {
158 // return an existing object
160 sfccheck(pid
< storage
.size());
161 sfccheck(validSFCType(types
[pid
], reqtype
));
162 SFCClass
*temp
= storage
[pid
];
167 // create a new object of an existing class
170 sfccheck(pid
< storage
.size());
171 sfccheck(!(storage
[pid
]));
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;
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
);
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
211 uint8
SFCFile::read8() {
213 ourStream
->read(temp
, 1);
217 uint16
SFCFile::read16() {
219 ourStream
->read(temp
, 2);
220 uint16
*i
= (uint16
*)&temp
;
221 return swapEndianShort(*i
);
224 uint32
SFCFile::read32() {
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) {
235 if (strlen
== 0xffff)
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
);
250 void SFCFile::setVersion(unsigned int v
) {
252 sfccheck(world
.gametype
== "c1");
254 sfccheck(world
.gametype
== "c2");
256 throw creaturesException(boost::str(boost::format("unknown version# %d") % 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
272 if (parent
->version() == 1) {
278 background
= (CGallery
*)slurpMFC(TYPE_CGALLERY
);
279 sfccheck(background
);
282 uint32 norooms
= read32();
283 for (unsigned int i
= 0; i
< norooms
; i
++) {
284 if (parent
->version() == 0) {
285 CRoom
*temp
= new CRoom(parent
);
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
);
295 CRoom
*temp
= (CRoom
*)slurpMFC(TYPE_CROOM
);
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
++) {
320 void CGallery::read() {
322 filename
= parent
->readBytes(4);
325 // discard unknown bytes
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();
338 otherroom
= read16();
340 // discard unknown bytes
341 sfccheck(read16() == 0);
348 sfccheck(read16() == 2);
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
);
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();
373 pressuresource
= reads32();
378 lightlevel
= read8();
379 lightsource
= reads32();
382 radiationsource
= reads32();
384 // discard unknown bytes
387 uint16 nopoints
= read16();
388 for (unsigned int i
= 0; i
< nopoints
; i
++) {
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() {
403 sprite
= (CGallery
*)slurpMFC(TYPE_CGALLERY
);
406 // read current frame and offset from base
415 // check if this agent is animated at present
416 uint8 animbyte
= read8();
418 sfccheck(animbyte
== 1);
421 // read the animation frame
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()) {
441 partzorder
= read32();
444 bhvrclick
[0] = (signed char)read8();
445 bhvrclick
[1] = (signed char)read8();
446 bhvrclick
[2] = (signed char)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)
475 sfccheck(read16() == 0);
479 if (parent
->version() == 0) {
480 // discard unknown byte
486 // discard unknown byte
491 if (parent
->version() == 0)
496 // discard unknown bytes
497 if (parent
->version() == 1)
498 sfccheck(read16() == 0);
500 // read unknown coords
506 // discard unknown bytes
513 sprite
= (CGallery
*)slurpMFC(TYPE_CGALLERY
);
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
537 // TODO: this is mysterious and unknown
540 // read physics values
547 // discard unknown bytes
554 uint8 flags
= read8();
555 frozen
= (flags
& 0x02);
559 uint32 numscripts
= read32();
560 for (unsigned int i
= 0; i
< numscripts
; i
++) {
563 scripts
.push_back(x
);
567 void SFCCompoundObject::read() {
570 uint32 numparts
= read32();
572 for (unsigned int i
= 0; i
< numparts
; i
++) {
573 SFCEntity
*e
= (SFCEntity
*)slurpMFC(TYPE_ENTITY
);
576 // if entity is null, discard unknown bytes
579 if (i
== 0) sfccheck((e
->relx
== 0) && (e
->rely
== 0));
581 // push the entity, even if it is null..
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();
622 backgroundcolour
= read32();
623 chalkcolour
= read32();
624 aliascolour
= read32();
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();
646 // discard unknown bytes
648 unsigned short x
= read16();
649 if (parent
->version() == 1)
652 sfccheck(read8() == 0);
654 // read cabin boundaries
655 cabinleft
= read32();
657 cabinright
= read32();
658 cabinbottom
= read32();
660 // discard unknown bytes
661 sfccheck(read32() == 0);
664 void SFCLift::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() {
689 entity
= (SFCEntity
*)slurpMFC(TYPE_ENTITY
);
692 void SFCPointerTool::read() {
693 SFCSimpleObject::read();
695 // discard unknown bytes
696 if (parent
->version() == 0)
702 void SFCCallButton::read() {
703 SFCSimpleObject::read();
705 ourLift
= (SFCLift
*)slurpMFC(TYPE_LIFT
);
709 void SFCScript::read(SFCFile
*f
) {
710 if (f
->version() == 0) {
711 eventno
= f
->read8();
712 species
= f
->read8();
718 eventno
= f
->read16();
719 species
= f
->read16();
721 data
= f
->readstring();
724 // ------------------------------------------------------------------
726 void SFCFile::copyToWorld() {
728 mapdata
->copyToWorld();
731 for (std::vector
<SFCScript
>::iterator i
= scripts
.begin(); i
!= scripts
.end(); i
++) {
735 // create normal objects
736 for (std::vector
<SFCObject
*>::iterator i
= objects
.begin(); i
!= objects
.end(); i
++) {
741 for (std::vector
<SFCScenery
*>::iterator i
= scenery
.begin(); i
!= scenery
.end(); i
++) {
745 // move the camera to the correct position
746 world
.camera
.moveTo(scrollx
, scrolly
, jump
);
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());
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"
789 void MapData::copyToWorld() {
790 // find the background sprite
791 shared_ptr
<creaturesImage
> spr
= world
.gallery
.getImage(background
->filename
);
794 // check for Terra Nornia's corrupt background sprite
795 if (background
->filename
== "buro") {
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());
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
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) {
825 r
->floorpoints
= src
->floorpoints
;
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
);
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
]);
858 for (std::vector
<CRoom
*>::iterator i
= rooms
.begin(); i
!= rooms
.end(); 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
++) {
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?
878 RoomDoor
*roomdoor
= r1
->doors
[r2
];
879 sfccheck(roomdoor
->perm
== door
->openness
);
888 void copyEntityData(SFCEntity
*entity
, DullPart
*p
) {
890 p
->setBase(entity
->imgoffset
);
891 p
->setPose(entity
->currframe
- entity
->imgoffset
);
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);
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)
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
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
;
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
); }
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
];
966 p
= new DullPart(a
, i
, e
->sprite
->filename
, e
->sprite
->firstimg
, e
->relx
, e
->rely
, e
->zorder
);
968 p
= new DullPart(a
, i
, e
->sprite
->filename
, e
->sprite
->firstimg
, e
->relx
, e
->rely
, e
->zorder
- parts
[0]->zorder
);
971 copyEntityData(e
, p
);
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
993 ourAgent
= new SimpleAgent(family
, genus
, species
, entity
->zorder
, sprite
->filename
, sprite
->firstimg
, sprite
->noframes
);
995 SimpleAgent
*a
= ourAgent
;
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];
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
);
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() {
1079 ourAgent
= new Vehicle(parts
[0]->sprite
->filename
, parts
[0]->sprite
->firstimg
, parts
[0]->sprite
->noframes
);
1081 Vehicle
*a
= dynamic_cast<Vehicle
*>(ourAgent
);
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
1092 a
->xvec
.setInt(xvec
);
1093 a
->yvec
.setInt(yvec
);
1098 void SFCLift::copyToWorld() {
1099 Lift
*a
= new Lift(parts
[0]->sprite
->filename
, parts
[0]->sprite
->firstimg
, parts
[0]->sprite
->noframes
);
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
);
1123 SFCSimpleObject::copyToWorld();
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));
1137 p
->is_transparent
= true;
1140 #include <boost/format.hpp>
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
);
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: */