| | 1 | #include "system.h" |
| | 2 | #include "stratdef.h" |
| | 3 | #include "bh_types.h" |
| | 4 | #include "weapons.h" |
| | 5 | #include "dynamics.h" |
| | 6 | #include "pvisible.h" |
| | 7 | #include "lift.h" |
| | 8 | #include <assert.h> |
| | 9 | #include <stdlib.h> |
| | 10 | |
| | 11 | extern SCENEMODULE MainScene; |
| | 12 | |
| | 13 | LIFT_CONTROL_BLOCK EC_Lift_Ctrl; |
| | 14 | MODULE Old_Pos_Module; |
| | 15 | |
| | 16 | void LiftBehaveInit(void* bhdata, STRATEGYBLOCK* sbptr) |
| | 17 | { |
| | 18 | MODULE * my_mod; |
| | 19 | |
| | 20 | LIFT_BEHAV_BLOCK *lift_bhv = malloc(sizeof(LIFT_BEHAV_BLOCK)); |
| | 21 | |
| | 22 | if(!lift_bhv) |
| | 23 | { |
| | 24 | RemoveBehaviourStrategy(sbptr); |
| | 25 | return; |
| | 26 | } |
| | 27 | |
| | 28 | sbptr->dataptr = lift_bhv; |
| | 29 | |
| | 30 | lift_bhv->bhvr_type = I_BehaviourLift; |
| | 31 | LIFT_STATION* lift_stn = &lift_bhv->lift_station; |
| | 32 | LIFT_TOOLS_TEMPLATE* lift_tt = (LIFT_TOOLS_TEMPLATE*)bhdata; |
| | 33 | |
| | 34 | // Copy the name over |
| | 35 | COPY_NAME (sbptr->SBname, lift_tt->nameID); |
| | 36 | |
| | 37 | { |
| | 38 | MREF mref = lift_tt->my_module; |
| | 39 | ConvertModuleNameToPointer (&mref, MainScene.sm_marray); |
| | 40 | |
| | 41 | my_mod = mref.mref_ptr; |
| | 42 | } |
| | 43 | |
| | 44 | assert (my_mod); |
| | 45 | |
| | 46 | my_mod->m_sbptr = sbptr; |
| | 47 | sbptr->moptr = my_mod; |
| | 48 | |
| | 49 | // loaded data - first the station |
| | 50 | |
| | 51 | COPY_NAME(lift_stn->lift_call_switch_name, lift_tt->call_switch_name); |
| | 52 | COPY_NAME(lift_stn->lift_door_name, lift_tt->lift_door_name); |
| | 53 | COPY_NAME(lift_stn->lift_floor_switch_name, lift_tt->lift_floor_switch_name); |
| | 54 | COPY_NAME(lift_stn->my_sb_name, lift_tt->my_module_name); |
| | 55 | |
| | 56 | lift_stn->num_floor = lift_tt->num_floor; |
| | 57 | lift_stn->orient = lift_tt->orient; |
| | 58 | |
| | 59 | // fill in the rest of the stn data; |
| | 60 | |
| | 61 | lift_stn->lift_call_switch = NULL; |
| | 62 | lift_stn->lift_door = NULL; |
| | 63 | lift_stn->lift_floor_switch = NULL; |
| | 64 | lift_stn->lift_module = sbptr->moptr; |
| | 65 | lift_stn->starting_station = (lift_tt->lift_flags & LiftFlag_Here); |
| | 66 | lift_stn->called = 0; |
| | 67 | |
| | 68 | // fill in the behaviour block |
| | 69 | |
| | 70 | lift_bhv->control_sb = NULL; |
| | 71 | lift_bhv->controller = lift_tt->controller; |
| | 72 | COPY_NAME(lift_bhv->control_sb_name, lift_tt->control_sb_name); |
| | 73 | |
| | 74 | if(lift_bhv->controller) |
| | 75 | { |
| | 76 | LIFT_CONTROL_BLOCK* lcont = malloc(sizeof(LIFT_CONTROL_BLOCK)); |
| | 77 | |
| | 78 | if(!lcont) |
| | 79 | { |
| | 80 | RemoveBehaviourStrategy(sbptr); |
| | 81 | return; |
| | 82 | } |
| | 83 | |
| | 84 | lift_bhv->lift_control = lcont; |
| | 85 | |
| | 86 | // fill in the number of floors |
| | 87 | |
| | 88 | lcont->num_stations = lift_tt->num_stations; |
| | 89 | lcont->lift_stations = malloc(sizeof(LIFT_STATION*)*lcont->num_stations); |
| | 90 | |
| | 91 | if(!lcont->lift_stations) |
| | 92 | { |
| | 93 | RemoveBehaviourStrategy(sbptr); |
| | 94 | return; |
| | 95 | } |
| | 96 | |
| | 97 | //and init that array |
| | 98 | { |
| | 99 | int i=0; |
| | 100 | while(i < lcont->num_stations) |
| | 101 | { |
| | 102 | *(lcont->lift_stations + i) = NULL; |
| | 103 | i++; |
| | 104 | } |
| | 105 | } |
| | 106 | // fill in the rest of the data |
| | 107 | |
| | 108 | *(lcont->lift_stations + lift_stn->num_floor) = lift_stn; |
| | 109 | lcont->dest_station = -1; |
| | 110 | lcont->delay_at_floor = 0; |
| | 111 | lcont->delay_between_floors = 0; |
| | 112 | lcont->motion = I_going_down; |
| | 113 | lcont->state = I_ls_waiting; |
| | 114 | lcont->curr_station = -1; |
| | 115 | lcont->prev_station = -1; |
| | 116 | lcont->SoundHandle = SOUND_NOACTIVEINDEX; |
| | 117 | lcont->floor_switches_fixed = (lift_tt->lift_flags & LiftFlag_NoTel); |
| | 118 | } |
| | 119 | else |
| | 120 | { |
| | 121 | lift_bhv->lift_control = NULL; |
| | 122 | } |
| | 123 | } |
| | 124 | |
| | 125 | void TeleportContents(MODULE* new_pos, MODULE* old_pos, int floor_switches_fixed) |
| | 126 | { |
| | 127 | //this used within level - find objects in module |
| | 128 | // all will have sbs |
| | 129 | |
| | 130 | int i; |
| | 131 | VECTORCH mod_offset; |
| | 132 | |
| | 133 | mod_offset.vx = new_pos->m_world.vx - old_pos->m_world.vx; |
| | 134 | mod_offset.vy = new_pos->m_world.vy - old_pos->m_world.vy; |
| | 135 | mod_offset.vz = new_pos->m_world.vz - old_pos->m_world.vz; |
| | 136 | |
| | 137 | int max_x = old_pos->m_maxx + old_pos->m_world.vx; |
| | 138 | int min_x = old_pos->m_minx + old_pos->m_world.vx; |
| | 139 | int max_y = old_pos->m_maxy + old_pos->m_world.vy; |
| | 140 | int min_y = old_pos->m_miny + old_pos->m_world.vy; |
| | 141 | int max_z = old_pos->m_maxz + old_pos->m_world.vz; |
| | 142 | int min_z = old_pos->m_minz + old_pos->m_world.vz; |
| | 143 | |
| | 144 | int dest_max_x = new_pos->m_maxx + new_pos->m_world.vx -200; |
| | 145 | int dest_min_x = new_pos->m_minx + new_pos->m_world.vx +200; |
| | 146 | int dest_max_y = new_pos->m_maxy + new_pos->m_world.vy -200; |
| | 147 | int dest_min_y = new_pos->m_miny + new_pos->m_world.vy +200; |
| | 148 | int dest_max_z = new_pos->m_maxz + new_pos->m_world.vz -200; |
| | 149 | int dest_min_z = new_pos->m_minz + new_pos->m_world.vz +200; |
| | 150 | |
| | 151 | for(i = 0; i < NumActiveStBlocks; i++) |
| | 152 | { |
| | 153 | DYNAMICSBLOCK *dynptr; |
| | 154 | STRATEGYBLOCK *sbptr = ActiveStBlockList[i]; |
| | 155 | |
| | 156 | if(!(dynptr = sbptr->DynPtr)) |
| | 157 | continue; |
| | 158 | |
| | 159 | if(floor_switches_fixed) |
| | 160 | { |
| | 161 | switch(sbptr->type) |
| | 162 | { |
| | 163 | case I_BehaviourInanimateObject: |
| | 164 | if (((INANIMATEOBJECT_STATUSBLOCK*)sbptr->dataptr)->typeId) |
| | 165 | break; |
| | 166 | case I_BehaviourBinarySwitch: |
| | 167 | case I_BehaviourLinkSwitch: |
| | 168 | continue; |
| | 169 | default: |
| | 170 | break; |
| | 171 | } |
| | 172 | } |
| | 173 | |
| | 174 | VECTORCH obj_world = dynptr->Position; |
| | 175 | |
| | 176 | if(obj_world.vx < max_x) |
| | 177 | if(obj_world.vx > min_x) |
| | 178 | if(obj_world.vz < max_z) |
| | 179 | if(obj_world.vz > min_z) |
| | 180 | if(obj_world.vy < max_y) |
| | 181 | if(obj_world.vy > min_y) |
| | 182 | { |
| | 183 | dynptr->Position.vx += mod_offset.vx; |
| | 184 | dynptr->Position.vy += mod_offset.vy; |
| | 185 | dynptr->Position.vz += mod_offset.vz; |
| | 186 | |
| | 187 | dynptr->PrevPosition.vx += mod_offset.vx; |
| | 188 | dynptr->PrevPosition.vy += mod_offset.vy; |
| | 189 | dynptr->PrevPosition.vz += mod_offset.vz; |
| | 190 | |
| | 191 | //make sure new location is inside destination module |
| | 192 | if(!dynptr->IsStatic) |
| | 193 | { |
| | 194 | if(dynptr->Position.vx < dest_min_x) dynptr->Position.vx = dest_min_x; |
| | 195 | if(dynptr->Position.vy < dest_min_y) dynptr->Position.vy = dest_min_y; |
| | 196 | if(dynptr->Position.vz < dest_min_z) dynptr->Position.vz = dest_min_z; |
| | 197 | if(dynptr->Position.vx > dest_max_x) dynptr->Position.vx = dest_max_x; |
| | 198 | if(dynptr->Position.vy > dest_max_y) dynptr->Position.vy = dest_max_y; |
| | 199 | if(dynptr->Position.vz > dest_max_z) dynptr->Position.vz = dest_max_z; |
| | 200 | |
| | 201 | if(dynptr->PrevPosition.vx < dest_min_x) dynptr->PrevPosition.vx = dest_min_x; |
| | 202 | if(dynptr->PrevPosition.vy < dest_min_y) dynptr->PrevPosition.vy = dest_min_y; |
| | 203 | if(dynptr->PrevPosition.vz < dest_min_z) dynptr->PrevPosition.vz = dest_min_z; |
| | 204 | if(dynptr->PrevPosition.vx > dest_max_x) dynptr->PrevPosition.vx = dest_max_x; |
| | 205 | if(dynptr->PrevPosition.vy > dest_max_y) dynptr->PrevPosition.vy = dest_max_y; |
| | 206 | if(dynptr->PrevPosition.vz > dest_max_z) dynptr->PrevPosition.vz = dest_max_z; |
| | 207 | } |
| | 208 | |
| | 209 | if(sbptr->maintainVisibility) |
| | 210 | sbptr->containingModule = new_pos; |
| | 211 | } |
| | 212 | } |
| | 213 | } |
| | 214 | |
| | 215 | void LiftBehaveFun(STRATEGYBLOCK* sbptr) |
| | 216 | { |
| | 217 | assert(sbptr); |
| | 218 | LIFT_BEHAV_BLOCK *lift_bhv = (LIFT_BEHAV_BLOCK*)sbptr->dataptr; |
| | 219 | assert((lift_bhv->bhvr_type == I_BehaviourLift)); |
| | 220 | |
| | 221 | LIFT_CONTROL_BLOCK *lift_ctrl = lift_bhv->lift_control; |
| | 222 | |
| | 223 | /* ALL the lift modules have a Strategy block that contains inforamtion |
| | 224 | about that particular location. Only one points to the LIFT CONTROL |
| | 225 | BLOCK |
| | 226 | */ |
| | 227 | |
| | 228 | /* the lifts will work between envs as well as on the same env |
| | 229 | so the control of the doors in the other envs sin't actually set, |
| | 230 | but a record of the postion is maintained |
| | 231 | */ |
| | 232 | |
| | 233 | if(lift_bhv->controller) |
| | 234 | { |
| | 235 | // HACK - RWH - if this is true the data is broken and this fix won't always work |
| | 236 | |
| | 237 | if(lift_ctrl->curr_station == -1) |
| | 238 | lift_ctrl->curr_station = 0; |
| | 239 | |
| | 240 | switch(lift_ctrl->state) |
| | 241 | { |
| | 242 | case I_ls_waiting: |
| | 243 | { |
| | 244 | /*** find dest and set movement direction this is always the |
| | 245 | same even if the lift is on a different floor ***/ |
| | 246 | int lower_station = -1; |
| | 247 | int upper_station = -1; |
| | 248 | int i; |
| | 249 | LIFT_STATION *lift_stn; |
| | 250 | |
| | 251 | /**** find the nearest floors selected ****/ |
| | 252 | |
| | 253 | // search up and down |
| | 254 | for(i = lift_ctrl->curr_station; (i >= 0) && (lower_station == -1); i --) |
| | 255 | { |
| | 256 | lift_stn = lift_ctrl->lift_stations[i]; |
| | 257 | |
| | 258 | if(lift_stn->called) |
| | 259 | upper_station = i; // higher floors have lower nums |
| | 260 | } |
| | 261 | |
| | 262 | for(i = lift_ctrl->curr_station; (i < lift_ctrl->num_stations) && (upper_station == -1); i ++) |
| | 263 | { |
| | 264 | lift_stn = lift_ctrl->lift_stations[i]; |
| | 265 | |
| | 266 | if(lift_stn->called) |
| | 267 | lower_station = i; // lower floors have higher nums |
| | 268 | } |
| | 269 | |
| | 270 | /****** set the destination and the motion direction ****/ |
| | 271 | |
| | 272 | if(lift_ctrl->motion == I_going_down)// higher nums |
| | 273 | { |
| | 274 | if(lower_station != -1) |
| | 275 | { |
| | 276 | lift_ctrl->dest_station = lower_station; |
| | 277 | } |
| | 278 | else |
| | 279 | { |
| | 280 | lift_ctrl->dest_station = upper_station; |
| | 281 | lift_ctrl->motion = I_going_up; |
| | 282 | } |
| | 283 | } |
| | 284 | else if(lift_ctrl->motion == I_going_up) // lower nums |
| | 285 | { |
| | 286 | if(upper_station != -1) |
| | 287 | { |
| | 288 | lift_ctrl->dest_station = upper_station; |
| | 289 | } |
| | 290 | else |
| | 291 | { |
| | 292 | lift_ctrl->dest_station = lower_station; |
| | 293 | lift_ctrl->motion = I_going_down; |
| | 294 | } |
| | 295 | } |
| | 296 | |
| | 297 | // now we have a station to go to, we start the lift in motion |
| | 298 | // unless we have just pressed the current floor switch again |
| | 299 | |
| | 300 | if(lift_ctrl->dest_station == lift_ctrl->curr_station) |
| | 301 | { |
| | 302 | // we have just called the lift to the same place |
| | 303 | lift_ctrl->dest_station = -1; |
| | 304 | lift_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 305 | lift_stn->called = 0; |
| | 306 | } |
| | 307 | else if(lift_ctrl->dest_station != -1) |
| | 308 | { |
| | 309 | // if there is a dest, set the lift to go |
| | 310 | // close current stations |
| | 311 | |
| | 312 | lift_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 313 | |
| | 314 | { |
| | 315 | lift_ctrl->prev_station = lift_ctrl->curr_station; |
| | 316 | |
| | 317 | if(lift_stn->lift_door) |
| | 318 | { |
| | 319 | // no door - must be on another env |
| | 320 | RequestState(lift_stn->lift_door, 0, 0); |
| | 321 | } |
| | 322 | lift_ctrl->state = I_ls_closing_door; |
| | 323 | } |
| | 324 | } |
| | 325 | } |
| | 326 | break; |
| | 327 | case I_ls_closing_door: |
| | 328 | { |
| | 329 | // lift station for the current lift position has to |
| | 330 | // have a closed door |
| | 331 | |
| | 332 | LIFT_STATION *pos_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 333 | //MODULE* mptr = pos_stn->lift_module; |
| | 334 | |
| | 335 | // deal with the fact that the lift is in a different env |
| | 336 | |
| | 337 | // close the door before we change state to moving |
| | 338 | |
| | 339 | if(!GetState(pos_stn->lift_door)) |
| | 340 | { |
| | 341 | lift_ctrl->state = I_ls_moving; |
| | 342 | lift_ctrl->delay_between_floors = LIFT_MOVE_DELAY; |
| | 343 | |
| | 344 | RequestState(pos_stn->lift_call_switch, 0, 0); |
| | 345 | |
| | 346 | if(pos_stn->lift_floor_switch) |
| | 347 | RequestState(pos_stn->lift_floor_switch, 0, 0); |
| | 348 | |
| | 349 | //what if there is a bad guy in the lift - if there is open the door |
| | 350 | //and reset all the switches and stations |
| | 351 | } |
| | 352 | } |
| | 353 | break; |
| | 354 | case I_ls_moving: |
| | 355 | { |
| | 356 | //int curr_station_num = lift_ctrl->curr_station; |
| | 357 | //LIFT_STATION *pos_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 358 | //MODULE* mptr = pos_stn->lift_module; |
| | 359 | |
| | 360 | lift_ctrl->delay_between_floors -= NormalFrameTime; |
| | 361 | |
| | 362 | // TRAP CHANGE OF ENVIRONMENT |
| | 363 | // we need to trap it here so we don't have the delay |
| | 364 | // between floors. However. The trap should make sure it is the nex array pos |
| | 365 | |
| | 366 | if(lift_ctrl->delay_between_floors < 0) |
| | 367 | { |
| | 368 | if(lift_ctrl->motion == I_going_up) |
| | 369 | lift_ctrl->curr_station--; |
| | 370 | else |
| | 371 | lift_ctrl->curr_station++; |
| | 372 | |
| | 373 | assert(lift_ctrl->curr_station >= 0); |
| | 374 | |
| | 375 | if(lift_ctrl->curr_station == lift_ctrl->dest_station) |
| | 376 | { |
| | 377 | // at destination |
| | 378 | LIFT_STATION *lift_stn_new = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 379 | LIFT_STATION *lift_stn_old = lift_ctrl->lift_stations[lift_ctrl->prev_station]; |
| | 380 | MODULE * new_pos = lift_stn_new->lift_module; |
| | 381 | MODULE * old_pos = lift_stn_old->lift_module; |
| | 382 | |
| | 383 | lift_ctrl->dest_station = -1; |
| | 384 | lift_ctrl->state = I_ls_opening_door; |
| | 385 | |
| | 386 | /* roxby: i have taken this out - patrick */ |
| | 387 | /* assert(mptr); */ |
| | 388 | Sound_Stop(lift_ctrl->SoundHandle); |
| | 389 | |
| | 390 | // door open |
| | 391 | |
| | 392 | RequestState(lift_stn_new->lift_door, 1, 0); |
| | 393 | |
| | 394 | lift_stn_new->called = 0; |
| | 395 | |
| | 396 | if(old_pos) |
| | 397 | { |
| | 398 | // if we don't have an old pos, we must |
| | 399 | // be coming from another env |
| | 400 | TeleportContents(new_pos, old_pos,lift_ctrl->floor_switches_fixed); |
| | 401 | } |
| | 402 | } |
| | 403 | else |
| | 404 | { |
| | 405 | // futher to go - move along now |
| | 406 | lift_ctrl->delay_between_floors += LIFT_MOVE_DELAY; |
| | 407 | } |
| | 408 | } |
| | 409 | } |
| | 410 | break; |
| | 411 | case I_ls_opening_door: |
| | 412 | { |
| | 413 | LIFT_STATION *lift_stn_new = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 414 | |
| | 415 | if(GetState(lift_stn_new->lift_door)) |
| | 416 | { |
| | 417 | lift_ctrl->state = I_ls_delay_at_floor; |
| | 418 | lift_ctrl->delay_at_floor = LIFT_FLOOR_DELAY; |
| | 419 | } |
| | 420 | } |
| | 421 | break; |
| | 422 | case I_ls_delay_at_floor: |
| | 423 | { |
| | 424 | lift_ctrl->delay_at_floor -= NormalFrameTime; |
| | 425 | |
| | 426 | if(lift_ctrl->delay_at_floor < 0) |
| | 427 | { |
| | 428 | // turn on the floor lights |
| | 429 | LIFT_STATION *lift_stn = lift_ctrl->lift_stations[lift_ctrl->curr_station]; |
| | 430 | |
| | 431 | RequestState(lift_stn->lift_call_switch, 1, 0); |
| | 432 | |
| | 433 | if(lift_stn->lift_floor_switch_name[0] || lift_stn->lift_floor_switch_name[4]) |
| | 434 | RequestState(lift_stn->lift_floor_switch, 1, 0); |
| | 435 | |
| | 436 | lift_ctrl->state = I_ls_waiting; |
| | 437 | lift_ctrl->dest_station = -1; |
| | 438 | } |
| | 439 | } |
| | 440 | break; |
| | 441 | default: |
| | 442 | assert(2<1); |
| | 443 | } |
| | 444 | } |
| | 445 | } |