| | 1 | #include "system.h" |
| | 2 | #include "prototyp.h" |
| | 3 | #include "stratdef.h" |
| | 4 | #include "bh_types.h" |
| | 5 | #include "weapons.h" |
| | 6 | #include "switchdoor.h" |
| | 7 | #include "savegame.h" |
| | 8 | #include <assert.h> |
| | 9 | #include <stdlib.h> |
| | 10 | |
| | 11 | extern void UpdateMorphing(MORPHCTRL *mcptr); |
| | 12 | |
| | 13 | /*---------------------Patrick 12/3/97------------------------- |
| | 14 | Initialisation of a switch door.... |
| | 15 | NB asumes that all switch doors start in a 'closed' state |
| | 16 | -------------------------------------------------------------*/ |
| | 17 | void InitialiseSwitchDoor(void* bhdata, STRATEGYBLOCK* sbPtr) |
| | 18 | { |
| | 19 | /* create a switch door data block */ |
| | 20 | SWITCH_DOOR_BEHAV_BLOCK *switchDoorBehaviourPtr = malloc(sizeof(SWITCH_DOOR_BEHAV_BLOCK)); |
| | 21 | |
| | 22 | if (!switchDoorBehaviourPtr) |
| | 23 | { |
| | 24 | RemoveBehaviourStrategy(sbPtr); |
| | 25 | return; |
| | 26 | } |
| | 27 | |
| | 28 | switchDoorBehaviourPtr->myBehaviourType = I_BehaviourSwitchDoor; |
| | 29 | sbPtr->dataptr = (void *)switchDoorBehaviourPtr; |
| | 30 | /* cast the tools data for access */ |
| | 31 | SWITCH_DOOR_TOOLS_TEMPLATE *switchDoorToolsData = (SWITCH_DOOR_TOOLS_TEMPLATE *)bhdata; |
| | 32 | |
| | 33 | /* Set up a new Morph Control */ |
| | 34 | MORPHFRAME *morphFrame = malloc(sizeof(MORPHFRAME)); |
| | 35 | |
| | 36 | if (!morphFrame) |
| | 37 | { |
| | 38 | RemoveBehaviourStrategy(sbPtr); |
| | 39 | return; |
| | 40 | } |
| | 41 | |
| | 42 | morphFrame->mf_shape1 = switchDoorToolsData->shapeOpen; |
| | 43 | morphFrame->mf_shape2 = switchDoorToolsData->shapeClosed; |
| | 44 | MORPHHEADER *morphHeader = malloc(sizeof(MORPHHEADER)); |
| | 45 | |
| | 46 | if (!morphHeader) |
| | 47 | { |
| | 48 | free(morphFrame); |
| | 49 | RemoveBehaviourStrategy(sbPtr); |
| | 50 | return; |
| | 51 | } |
| | 52 | |
| | 53 | morphHeader->mph_numframes = 1; |
| | 54 | morphHeader->mph_maxframes = ONE_FIXED; |
| | 55 | morphHeader->mph_frames = morphFrame; |
| | 56 | |
| | 57 | MORPHCTRL *morphCtrl = malloc(sizeof(MORPHCTRL)); |
| | 58 | |
| | 59 | if (!morphCtrl) |
| | 60 | { |
| | 61 | free(morphFrame); |
| | 62 | free(morphHeader); |
| | 63 | RemoveBehaviourStrategy(sbPtr); |
| | 64 | return; |
| | 65 | } |
| | 66 | |
| | 67 | morphCtrl->ObMorphCurrFrame = 0; |
| | 68 | morphCtrl->ObMorphFlags = 0; |
| | 69 | morphCtrl->ObMorphSpeed = 0; |
| | 70 | morphCtrl->ObMorphHeader = morphHeader; |
| | 71 | switchDoorBehaviourPtr->morfControl = sbPtr->morphctrl = morphCtrl; |
| | 72 | |
| | 73 | /* set up my module, and it's morph controls */ |
| | 74 | COPY_NAME(sbPtr->SBname, switchDoorToolsData->nameID); |
| | 75 | { |
| | 76 | extern SCENEMODULE MainScene; |
| | 77 | MREF mref = switchDoorToolsData->myModule; |
| | 78 | ConvertModuleNameToPointer(&mref, MainScene.sm_marray); |
| | 79 | assert(mref.mref_ptr); |
| | 80 | assert(mref.mref_ptr->m_mapptr); |
| | 81 | mref.mref_ptr->m_sbptr = sbPtr; |
| | 82 | sbPtr->moptr = mref.mref_ptr; |
| | 83 | } |
| | 84 | |
| | 85 | sbPtr->moptr->m_flags &= ~m_flag_open; |
| | 86 | |
| | 87 | /* set up some other behaviour block stuff */ |
| | 88 | COPY_NAME(switchDoorBehaviourPtr->linkedDoorName, switchDoorToolsData->linkedDoorName); |
| | 89 | switchDoorBehaviourPtr->doorState = I_door_closed; |
| | 90 | switchDoorBehaviourPtr->linkedDoorPtr = NULL; |
| | 91 | switchDoorBehaviourPtr->requestOpen = 0; |
| | 92 | switchDoorBehaviourPtr->requestClose = 0; |
| | 93 | switchDoorBehaviourPtr->openTimer = 0; |
| | 94 | switchDoorBehaviourPtr->SoundHandle = SOUND_NOACTIVEINDEX; |
| | 95 | CloseDoor(sbPtr->morphctrl, DOOR_CLOSEFASTSPEED); |
| | 96 | |
| | 97 | { |
| | 98 | // Work out the door sound pitch |
| | 99 | |
| | 100 | int maxX = mainshapelist[morphFrame->mf_shape2]->shapemaxx; |
| | 101 | int maxY = mainshapelist[morphFrame->mf_shape2]->shapemaxy; |
| | 102 | int maxZ = mainshapelist[morphFrame->mf_shape2]->shapemaxz; |
| | 103 | |
| | 104 | int doorSize = maxX + maxY + maxZ; |
| | 105 | |
| | 106 | if (doorSize < 3000) |
| | 107 | doorSize = 3000; |
| | 108 | else if (doorSize > 8000) |
| | 109 | doorSize = 8000; |
| | 110 | |
| | 111 | doorSize = (3000 - doorSize) >> 4; |
| | 112 | |
| | 113 | switchDoorBehaviourPtr->doorType = doorSize; |
| | 114 | } |
| | 115 | } |
| | 116 | |
| | 117 | int AnythingInMyModule(MODULE* my_mod) |
| | 118 | { |
| | 119 | // simple overlap test |
| | 120 | // this used within level - find objects in module |
| | 121 | // all will have sbs |
| | 122 | int i = 0; |
| | 123 | |
| | 124 | int max_x = my_mod->m_maxx + my_mod->m_world.vx; |
| | 125 | int min_x = my_mod->m_minx + my_mod->m_world.vx; |
| | 126 | int max_y = my_mod->m_maxy + my_mod->m_world.vy; |
| | 127 | int min_y = my_mod->m_miny + my_mod->m_world.vy; |
| | 128 | int max_z = my_mod->m_maxz + my_mod->m_world.vz; |
| | 129 | int min_z = my_mod->m_minz + my_mod->m_world.vz; |
| | 130 | |
| | 131 | for(; i < NumActiveStBlocks; i++) |
| | 132 | { |
| | 133 | STRATEGYBLOCK *sbptr = ActiveStBlockList[i]; |
| | 134 | DYNAMICSBLOCK *dynptr = sbptr->DynPtr; |
| | 135 | |
| | 136 | if(dynptr) |
| | 137 | { |
| | 138 | VECTORCH obj_world = dynptr->Position; |
| | 139 | |
| | 140 | if((obj_world.vx < max_x) && (obj_world.vx > min_x) |
| | 141 | && (obj_world.vz < max_z) && (obj_world.vz > min_z) |
| | 142 | && (obj_world.vy < max_y) && (obj_world.vy > min_y)) |
| | 143 | { |
| | 144 | CauseDamageToObject(sbptr, &damage_profiles[FALLINGDAMAGE], (100 * NormalFrameTime), NULL); |
| | 145 | return sbptr->DamageBlock.Indestructable; |
| | 146 | } |
| | 147 | } |
| | 148 | } |
| | 149 | |
| | 150 | return 0; |
| | 151 | } |
| | 152 | |
| | 153 | /*---------------------Patrick 13/3/97------------------------- |
| | 154 | Switch door behaviour function. |
| | 155 | -------------------------------------------------------------*/ |
| | 156 | void SwitchDoorBehaviour(STRATEGYBLOCK* sbPtr) |
| | 157 | { |
| | 158 | int linkedDoorIsClosed = 1; |
| | 159 | |
| | 160 | assert(sbPtr); |
| | 161 | SWITCH_DOOR_BEHAV_BLOCK *doorBehaviour = (SWITCH_DOOR_BEHAV_BLOCK*)sbPtr->dataptr; |
| | 162 | assert(doorBehaviour); |
| | 163 | MORPHCTRL *mCtrl = doorBehaviour->morfControl; |
| | 164 | assert(mCtrl); |
| | 165 | MODULE *mPtr = sbPtr->moptr; |
| | 166 | assert(mPtr); |
| | 167 | |
| | 168 | /* update morphing.... */ |
| | 169 | UpdateMorphing(mCtrl); |
| | 170 | |
| | 171 | /* get state of linked door: if there isn't a linked door, 'linkeddoorisclosed' |
| | 172 | remains true so that there is no obstruction to operation of this door. |
| | 173 | |
| | 174 | NB can't use 'GetState' here, as it returns true only if the door is fully open |
| | 175 | (used by the NPC's). Here, we need to determine if the door is closed (which is |
| | 176 | not the same as !open) */ |
| | 177 | |
| | 178 | if(doorBehaviour->linkedDoorPtr) |
| | 179 | { |
| | 180 | if(((SWITCH_DOOR_BEHAV_BLOCK *)doorBehaviour->linkedDoorPtr->dataptr)->doorState != I_door_closed) |
| | 181 | linkedDoorIsClosed = 0; |
| | 182 | } |
| | 183 | |
| | 184 | switch(doorBehaviour->doorState) |
| | 185 | { |
| | 186 | case I_door_opening: |
| | 187 | { |
| | 188 | /* assert(linkedDoorIsClosed); */ |
| | 189 | /* check if we've got a close request */ |
| | 190 | |
| | 191 | if(doorBehaviour->requestClose && !AnythingInMyModule(sbPtr->moptr)) |
| | 192 | { |
| | 193 | if(sbPtr->DisplayBlock) |
| | 194 | CloseDoor(mCtrl, DOOR_CLOSESLOWSPEED); |
| | 195 | else |
| | 196 | CloseDoor(mCtrl, DOOR_CLOSEFASTSPEED); |
| | 197 | |
| | 198 | doorBehaviour->doorState = I_door_closing; |
| | 199 | } |
| | 200 | else if(mCtrl->ObMorphFlags & mph_flag_finished) |
| | 201 | { |
| | 202 | /* already opening, so just allow the door to continue... */ |
| | 203 | //door has finished opening |
| | 204 | doorBehaviour->doorState = I_door_open; |
| | 205 | doorBehaviour->openTimer = DOOR_FAROPENTIME; |
| | 206 | |
| | 207 | if (doorBehaviour->SoundHandle != SOUND_NOACTIVEINDEX) |
| | 208 | { |
| | 209 | Sound_Play(SID_DOOREND, "dp", &mPtr->m_world,doorBehaviour->doorType); |
| | 210 | Sound_Stop(doorBehaviour->SoundHandle); |
| | 211 | } |
| | 212 | } |
| | 213 | } |
| | 214 | break; |
| | 215 | case I_door_closing: |
| | 216 | { |
| | 217 | /* assert(linkedDoorIsClosed); */ |
| | 218 | /* check if we've got an open request, or anything has jumped in */ |
| | 219 | if(doorBehaviour->requestOpen || AnythingInMyModule(sbPtr->moptr)) |
| | 220 | { |
| | 221 | //have to start opening again |
| | 222 | if(sbPtr->DisplayBlock) |
| | 223 | OpenDoor(mCtrl, DOOR_OPENSLOWSPEED); |
| | 224 | else |
| | 225 | OpenDoor(mCtrl, DOOR_OPENFASTSPEED); |
| | 226 | |
| | 227 | doorBehaviour->doorState = I_door_opening; |
| | 228 | |
| | 229 | Sound_Play(SID_DOORSTART, "dp", &mPtr->m_world, doorBehaviour->doorType); |
| | 230 | Sound_Play(SID_DOORMID, "delp", &mPtr->m_world, &doorBehaviour->SoundHandle, doorBehaviour->doorType); |
| | 231 | } |
| | 232 | else if(mCtrl->ObMorphFlags & mph_flag_finished) |
| | 233 | { |
| | 234 | /* check if we've finished closing */ |
| | 235 | doorBehaviour->doorState = I_door_closed; |
| | 236 | mPtr->m_flags &= ~m_flag_open; |
| | 237 | |
| | 238 | if (doorBehaviour->SoundHandle!=SOUND_NOACTIVEINDEX) |
| | 239 | { |
| | 240 | Sound_Play(SID_DOOREND,"dp",&mPtr->m_world,doorBehaviour->doorType); |
| | 241 | Sound_Stop(doorBehaviour->SoundHandle); |
| | 242 | } |
| | 243 | } |
| | 244 | } |
| | 245 | break; |
| | 246 | case I_door_open: |
| | 247 | { |
| | 248 | /* assert(linkedDoorIsClosed); */ |
| | 249 | /*if we've got a close request , set the open timer to 0 |
| | 250 | so the door will start closing*/ |
| | 251 | if(doorBehaviour->requestClose) |
| | 252 | doorBehaviour->openTimer = 0; |
| | 253 | |
| | 254 | /* check our timer to see if it's time to close*/ |
| | 255 | if(doorBehaviour->openTimer <= 0) |
| | 256 | { |
| | 257 | /* make sure there's nothing inside the door module before closing */ |
| | 258 | if(!AnythingInMyModule(sbPtr->moptr)) |
| | 259 | { |
| | 260 | if(sbPtr->DisplayBlock) |
| | 261 | CloseDoor(mCtrl, DOOR_CLOSESLOWSPEED); |
| | 262 | else |
| | 263 | CloseDoor(mCtrl, DOOR_CLOSEFASTSPEED); |
| | 264 | |
| | 265 | doorBehaviour->doorState = I_door_closing; |
| | 266 | doorBehaviour->openTimer = 0; |
| | 267 | |
| | 268 | Sound_Play(SID_DOORSTART, "dp", &mPtr->m_world, doorBehaviour->doorType); |
| | 269 | Sound_Play(SID_DOORMID, "delp", &mPtr->m_world, &doorBehaviour->SoundHandle, doorBehaviour->doorType); |
| | 270 | } |
| | 271 | } |
| | 272 | else |
| | 273 | { |
| | 274 | doorBehaviour->openTimer -= NormalFrameTime; |
| | 275 | } |
| | 276 | } |
| | 277 | break; |
| | 278 | case I_door_closed: |
| | 279 | { |
| | 280 | if(doorBehaviour->requestOpen && linkedDoorIsClosed) |
| | 281 | { |
| | 282 | /* just open the door */ |
| | 283 | if(sbPtr->DisplayBlock) |
| | 284 | OpenDoor(mCtrl, DOOR_OPENSLOWSPEED); |
| | 285 | else |
| | 286 | OpenDoor(mCtrl, DOOR_OPENFASTSPEED); |
| | 287 | |
| | 288 | doorBehaviour->doorState = I_door_opening; |
| | 289 | mPtr->m_flags |= m_flag_open; |
| | 290 | |
| | 291 | Sound_Play(SID_DOORSTART,"dp",&mPtr->m_world,doorBehaviour->doorType); |
| | 292 | Sound_Play(SID_DOORMID,"delp",&mPtr->m_world,&doorBehaviour->SoundHandle,doorBehaviour->doorType); |
| | 293 | } |
| | 294 | } |
| | 295 | } |
| | 296 | |
| | 297 | /* must reset this every frame */ |
| | 298 | doorBehaviour->requestOpen = 0; |
| | 299 | doorBehaviour->requestClose = 0; |
| | 300 | } |
| | 301 | |
| | 302 | /*--------------------** |
| | 303 | ** Loading and Saving ** |
| | 304 | **--------------------*/ |
| | 305 | typedef struct switch_door_save_block |
| | 306 | { |
| | 307 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 308 | |
| | 309 | DOOR_STATES doorState; |
| | 310 | int openTimer; |
| | 311 | unsigned int requestOpen :1; |
| | 312 | unsigned int requestClose :1; |
| | 313 | |
| | 314 | //from the morph control |
| | 315 | int ObMorphCurrFrame; |
| | 316 | int ObMorphFlags; |
| | 317 | int ObMorphSpeed; |
| | 318 | |
| | 319 | } SWITCH_DOOR_SAVE_BLOCK; |
| | 320 | |
| | 321 | //defines for load/save macros |
| | 322 | #define SAVELOAD_BLOCK block |
| | 323 | #define SAVELOAD_BEHAV doorbhv |
| | 324 | |
| | 325 | void LoadStrategy_SwitchDoor(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 326 | { |
| | 327 | SWITCH_DOOR_SAVE_BLOCK* block = (SWITCH_DOOR_SAVE_BLOCK*) header; |
| | 328 | |
| | 329 | if(header->size != sizeof(*block)) |
| | 330 | return; |
| | 331 | |
| | 332 | //find the existing strategy block |
| | 333 | STRATEGYBLOCK* sbPtr = FindSBWithName(header->SBname); |
| | 334 | |
| | 335 | if(!sbPtr) |
| | 336 | return; |
| | 337 | |
| | 338 | //make sure the strategy found is of the right type |
| | 339 | if(sbPtr->type != I_BehaviourSwitchDoor) |
| | 340 | return; |
| | 341 | |
| | 342 | SWITCH_DOOR_BEHAV_BLOCK *doorbhv = (SWITCH_DOOR_BEHAV_BLOCK*)sbPtr->dataptr; |
| | 343 | |
| | 344 | COPYELEMENT_LOAD(doorState) |
| | 345 | COPYELEMENT_LOAD(openTimer) |
| | 346 | COPYELEMENT_LOAD(requestOpen) |
| | 347 | COPYELEMENT_LOAD(requestClose) |
| | 348 | |
| | 349 | doorbhv->morfControl->ObMorphCurrFrame = block->ObMorphCurrFrame; |
| | 350 | doorbhv->morfControl->ObMorphFlags = block->ObMorphFlags; |
| | 351 | doorbhv->morfControl->ObMorphSpeed = block->ObMorphSpeed; |
| | 352 | |
| | 353 | Load_SoundState(&doorbhv->SoundHandle); |
| | 354 | } |
| | 355 | |
| | 356 | void SaveStrategy_SwitchDoor(STRATEGYBLOCK* sbPtr) |
| | 357 | { |
| | 358 | SWITCH_DOOR_SAVE_BLOCK *block; |
| | 359 | SWITCH_DOOR_BEHAV_BLOCK *doorbhv = (SWITCH_DOOR_BEHAV_BLOCK*)sbPtr->dataptr; |
| | 360 | |
| | 361 | GET_STRATEGY_SAVE_BLOCK(block,sbPtr); |
| | 362 | |
| | 363 | COPYELEMENT_SAVE(doorState) |
| | 364 | COPYELEMENT_SAVE(openTimer) |
| | 365 | COPYELEMENT_SAVE(requestOpen) |
| | 366 | COPYELEMENT_SAVE(requestClose) |
| | 367 | |
| | 368 | block->ObMorphCurrFrame = doorbhv->morfControl->ObMorphCurrFrame; |
| | 369 | block->ObMorphFlags = doorbhv->morfControl->ObMorphFlags; |
| | 370 | block->ObMorphSpeed = doorbhv->morfControl->ObMorphSpeed; |
| | 371 | |
| | 372 | Save_SoundState(&doorbhv->SoundHandle); |
| | 373 | } |