| | 1 | #include "system.h" |
| | 2 | #include "prototyp.h" |
| | 3 | #include <assert.h> |
| | 4 | #include "stratdef.h" |
| | 5 | #include "bh_types.h" |
| | 6 | #include "weapons.h" |
| | 7 | #include "kshape.h" |
| | 8 | #include "pvisible.h" |
| | 9 | #include <stdio.h> |
| | 10 | |
| | 11 | extern int GetLoadedShapeMSL(char const * shapename); |
| | 12 | extern void DrawCable(VECTORCH *centrePtr, MATRIXCH *orientationPtr); |
| | 13 | extern void AssignNewSBName(STRATEGYBLOCK *sbPtr); |
| | 14 | extern int CloakingPhase; |
| | 15 | |
| | 16 | struct GrapplingHookData |
| | 17 | { |
| | 18 | int IsEmbedded; |
| | 19 | int IsEngaged; |
| | 20 | int Tightness; |
| | 21 | |
| | 22 | VECTORCH Position; |
| | 23 | MATRIXCH Orientation; |
| | 24 | int ShapeIndex; |
| | 25 | DISPLAYBLOCK *DispPtr; |
| | 26 | }; |
| | 27 | |
| | 28 | static struct GrapplingHookData GrapplingHook; |
| | 29 | |
| | 30 | void InitialiseGrapplingHook() |
| | 31 | { |
| | 32 | GrapplingHook.IsEngaged = 0; |
| | 33 | GrapplingHook.IsEmbedded = 0; |
| | 34 | GrapplingHook.ShapeIndex = GetLoadedShapeMSL("spear"); |
| | 35 | GrapplingHook.DispPtr = 0; |
| | 36 | } |
| | 37 | |
| | 38 | static DISPLAYBLOCK* CreateGrapplingHook() |
| | 39 | { |
| | 40 | STRATEGYBLOCK* sbPtr = CreateActiveStrategyBlock(I_BehaviourGrapplingHook); |
| | 41 | |
| | 42 | if(!sbPtr) |
| | 43 | return NULL; |
| | 44 | |
| | 45 | DISPLAYBLOCK *dPtr = sbPtr->DisplayBlock = CreateActiveObject(); |
| | 46 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_ROCKET); |
| | 47 | sbPtr->containingModule = ModuleFromPosition(&Global_VDB.VDB_World, NULL); |
| | 48 | |
| | 49 | if((NULL == dynPtr) || (NULL == dPtr) || (NULL == sbPtr->containingModule)) |
| | 50 | { |
| | 51 | RemoveBehaviourStrategy(sbPtr); |
| | 52 | return NULL; |
| | 53 | } |
| | 54 | |
| | 55 | AssignNewSBName(sbPtr); |
| | 56 | dynPtr->PrevPosition = dynPtr->Position = Global_VDB.VDB_World; |
| | 57 | |
| | 58 | GrapplingHook.Orientation = Global_VDB.VDB_Mat; |
| | 59 | TransposeMatrixCH(&GrapplingHook.Orientation); |
| | 60 | dynPtr->OrientMat = GrapplingHook.Orientation; |
| | 61 | |
| | 62 | dynPtr->LinVelocity.vx = dynPtr->OrientMat.mat31; |
| | 63 | dynPtr->LinVelocity.vy = dynPtr->OrientMat.mat32; |
| | 64 | dynPtr->LinVelocity.vz = dynPtr->OrientMat.mat33; |
| | 65 | |
| | 66 | sbPtr->shapeIndex = GetLoadedShapeMSL("spear"); |
| | 67 | |
| | 68 | dPtr->ObShape = sbPtr->shapeIndex; |
| | 69 | dPtr->ShapeData = mainshapelist[sbPtr->shapeIndex]; |
| | 70 | dPtr->ObStrategyBlock = sbPtr; |
| | 71 | dPtr->ObWorld = dynPtr->Position; |
| | 72 | dPtr->ObEuler = dynPtr->OrientEuler; |
| | 73 | dPtr->ObMat = dynPtr->OrientMat; |
| | 74 | |
| | 75 | dPtr->extent.radius = 10; |
| | 76 | |
| | 77 | dPtr->extent.max_x = 10; |
| | 78 | dPtr->extent.max_y = 10; |
| | 79 | dPtr->extent.max_z = 10; |
| | 80 | dPtr->extent.min_x = -10; |
| | 81 | dPtr->extent.min_y = -10; |
| | 82 | dPtr->extent.min_z = -10; |
| | 83 | |
| | 84 | dPtr->ObFlags3 |= ObFlag3_DynamicModuleObject; |
| | 85 | |
| | 86 | return dPtr; |
| | 87 | } |
| | 88 | |
| | 89 | static void FireGrapplingHook() |
| | 90 | { |
| | 91 | GrapplingHook.DispPtr = CreateGrapplingHook(); |
| | 92 | |
| | 93 | if (GrapplingHook.DispPtr) |
| | 94 | { |
| | 95 | GrapplingHook.IsEngaged = 1; |
| | 96 | GrapplingHook.IsEmbedded = 0; |
| | 97 | GrapplingHook.Tightness = ONE_FIXED; |
| | 98 | Sound_Play(SID_GRAPPLE_THROW,"h"); |
| | 99 | } |
| | 100 | } |
| | 101 | |
| | 102 | void DisengageGrapplingHook() |
| | 103 | { |
| | 104 | GrapplingHook.IsEngaged = 0; |
| | 105 | GrapplingHook.IsEmbedded = 0; |
| | 106 | |
| | 107 | if (GrapplingHook.DispPtr) |
| | 108 | { |
| | 109 | RemoveBehaviourStrategy(GrapplingHook.DispPtr->ObStrategyBlock); |
| | 110 | GrapplingHook.DispPtr = NULL; |
| | 111 | } |
| | 112 | } |
| | 113 | |
| | 114 | void ActivateGrapplingHook() |
| | 115 | { |
| | 116 | GrapplingHook.IsEngaged ? DisengageGrapplingHook() : FireGrapplingHook(); |
| | 117 | } |
| | 118 | |
| | 119 | void GrapplingHookBehaviour(STRATEGYBLOCK *sbPtr) |
| | 120 | { |
| | 121 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr; |
| | 122 | |
| | 123 | if (!GrapplingHook.IsEmbedded) |
| | 124 | { |
| | 125 | COLLISIONREPORT *reportPtr = dynPtr->CollisionReportPtr; |
| | 126 | |
| | 127 | if(reportPtr) |
| | 128 | { |
| | 129 | char stickWhereYouAre = 0; |
| | 130 | |
| | 131 | if (reportPtr->ObstacleSBPtr) |
| | 132 | { |
| | 133 | DISPLAYBLOCK *dispPtr = reportPtr->ObstacleSBPtr->DisplayBlock; |
| | 134 | |
| | 135 | if (dispPtr && dispPtr->Module && !dispPtr->ObMorphCtrl) |
| | 136 | stickWhereYouAre=1; |
| | 137 | } |
| | 138 | else |
| | 139 | { |
| | 140 | stickWhereYouAre = 1; |
| | 141 | } |
| | 142 | |
| | 143 | if(stickWhereYouAre) |
| | 144 | { |
| | 145 | dynPtr->IsStatic = 1; |
| | 146 | dynPtr->PrevPosition = dynPtr->Position; |
| | 147 | GrapplingHook.Position = dynPtr->Position; |
| | 148 | GrapplingHook.IsEmbedded = 1; |
| | 149 | Sound_Play(SID_GRAPPLE_HIT_WALL,"d",&dynPtr->Position); |
| | 150 | return; |
| | 151 | } |
| | 152 | else |
| | 153 | { |
| | 154 | DisengageGrapplingHook(); |
| | 155 | return; |
| | 156 | } |
| | 157 | } |
| | 158 | } |
| | 159 | else |
| | 160 | { |
| | 161 | GrapplingHook.Tightness -= NormalFrameTime*4; |
| | 162 | if (GrapplingHook.Tightness < 0) |
| | 163 | GrapplingHook.Tightness = 0; |
| | 164 | } |
| | 165 | } |
| | 166 | |
| | 167 | void HandleGrapplingHookForces() |
| | 168 | { |
| | 169 | if (GrapplingHook.IsEmbedded) |
| | 170 | { |
| | 171 | DYNAMICSBLOCK *dynPtr = PlayerStatus.sbptr->DynPtr; |
| | 172 | VECTORCH direction = GrapplingHook.Position; |
| | 173 | int distance; |
| | 174 | |
| | 175 | direction.vx -= dynPtr->Position.vx; |
| | 176 | direction.vy -= dynPtr->Position.vy-1000; |
| | 177 | direction.vz -= dynPtr->Position.vz; |
| | 178 | |
| | 179 | distance = Approximate3dMagnitude(&direction); |
| | 180 | |
| | 181 | if (distance > 4096 + 1024) |
| | 182 | { |
| | 183 | Normalise(&direction); |
| | 184 | dynPtr->LinImpulse.vx += MUL_FIXED(direction.vx,NormalFrameTime); |
| | 185 | dynPtr->LinImpulse.vy += MUL_FIXED(direction.vy,NormalFrameTime); |
| | 186 | dynPtr->LinImpulse.vz += MUL_FIXED(direction.vz,NormalFrameTime); |
| | 187 | } |
| | 188 | else if (distance > 1024) |
| | 189 | { |
| | 190 | int s = MUL_FIXED((distance-1024)*16,NormalFrameTime); |
| | 191 | Normalise(&direction); |
| | 192 | dynPtr->LinImpulse.vx += MUL_FIXED(direction.vx,s); |
| | 193 | dynPtr->LinImpulse.vy += MUL_FIXED(direction.vy,s); |
| | 194 | dynPtr->LinImpulse.vz += MUL_FIXED(direction.vz,s); |
| | 195 | |
| | 196 | dynPtr->LinImpulse.vx -= MUL_FIXED(dynPtr->LinImpulse.vx,NormalFrameTime/2); |
| | 197 | dynPtr->LinImpulse.vy -= MUL_FIXED(dynPtr->LinImpulse.vy,NormalFrameTime/2); |
| | 198 | dynPtr->LinImpulse.vz -= MUL_FIXED(dynPtr->LinImpulse.vz,NormalFrameTime/2); |
| | 199 | } |
| | 200 | |
| | 201 | if (Approximate3dMagnitude(&dynPtr->LinImpulse) > ONE_FIXED) |
| | 202 | { |
| | 203 | Normalise(&dynPtr->LinImpulse); |
| | 204 | } |
| | 205 | } |
| | 206 | } |
| | 207 | |
| | 208 | void RenderGrapplingHook() |
| | 209 | { |
| | 210 | if (GrapplingHook.IsEngaged && GrapplingHook.DispPtr) |
| | 211 | { |
| | 212 | VECTORCH cable[46]; |
| | 213 | int i=1; |
| | 214 | { |
| | 215 | MATRIXCH mat = Global_VDB.VDB_Mat; |
| | 216 | TransposeMatrixCH(&mat); |
| | 217 | |
| | 218 | cable[0].vx = Global_VDB.VDB_World.vx-mat.mat31/128; |
| | 219 | cable[0].vy = Global_VDB.VDB_World.vy-mat.mat32/128+500; |
| | 220 | cable[0].vz = Global_VDB.VDB_World.vz-mat.mat33/128; |
| | 221 | } |
| | 222 | |
| | 223 | for (; i < 46; i++) |
| | 224 | { |
| | 225 | cable[i].vx = ((45-i)*cable[0].vx + (i)*GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position.vx)/45; |
| | 226 | cable[i].vy = ((45-i)*cable[0].vy + (i)*GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position.vy)/45; |
| | 227 | cable[i].vz = ((45-i)*cable[0].vz + (i)*GrapplingHook.DispPtr->ObStrategyBlock->DynPtr->Position.vz)/45; |
| | 228 | |
| | 229 | if (GrapplingHook.Tightness != 0) |
| | 230 | { |
| | 231 | int x = GetSin((302*i+CloakingPhase)&4095) / 256; |
| | 232 | int y = GetSin((502*i+200+CloakingPhase)&4095) / 256; |
| | 233 | int z = GetCos((302*i+100+CloakingPhase)&4095) / 256; |
| | 234 | int u = GetSin( ((4096*i)/45)&4095 ); |
| | 235 | u = MUL_FIXED(MUL_FIXED(u,u),GrapplingHook.Tightness); |
| | 236 | cable[i].vx += MUL_FIXED(u,x); |
| | 237 | cable[i].vy += MUL_FIXED(u,y); |
| | 238 | cable[i].vz += MUL_FIXED(u,z); |
| | 239 | } |
| | 240 | } |
| | 241 | |
| | 242 | { |
| | 243 | MATRIXCH mat; |
| | 244 | VECTORCH dir = cable[45]; |
| | 245 | dir.vx -= cable[0].vx; |
| | 246 | dir.vy -= cable[0].vy; |
| | 247 | dir.vz -= cable[0].vz; |
| | 248 | Normalise(&dir); |
| | 249 | MakeMatrixFromDirection(&dir,&mat); |
| | 250 | DrawCable(cable, &mat); |
| | 251 | } |
| | 252 | } |
| | 253 | } |
| | 254 | |
| | 255 | /*--------------------** |
| | 256 | ** Loading and Saving ** |
| | 257 | **--------------------*/ |
| | 258 | #include "savegame.h" |
| | 259 | |
| | 260 | typedef struct grapple_save_block |
| | 261 | { |
| | 262 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 263 | |
| | 264 | int IsEmbedded; |
| | 265 | int IsEngaged; |
| | 266 | int Tightness; |
| | 267 | |
| | 268 | VECTORCH Position; |
| | 269 | MATRIXCH Orientation; |
| | 270 | //strategy block stuff |
| | 271 | DYNAMICSBLOCK dynamics; |
| | 272 | } GRAPPLE_SAVE_BLOCK; |
| | 273 | |
| | 274 | #define SAVELOAD_BLOCK block |
| | 275 | #define SAVELOAD_BEHAV (&GrapplingHook) |
| | 276 | |
| | 277 | void LoadStrategy_Grapple(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 278 | { |
| | 279 | GRAPPLE_SAVE_BLOCK* block = (GRAPPLE_SAVE_BLOCK*) header; |
| | 280 | |
| | 281 | //check the size of the save block |
| | 282 | if(header->size != sizeof(*block)) |
| | 283 | return; |
| | 284 | |
| | 285 | //create the grappling hook |
| | 286 | GrapplingHook.DispPtr = CreateGrapplingHook(); |
| | 287 | if(!GrapplingHook.DispPtr) |
| | 288 | return; |
| | 289 | |
| | 290 | //copy suff from the save block |
| | 291 | COPYELEMENT_LOAD(IsEmbedded) |
| | 292 | COPYELEMENT_LOAD(IsEngaged) |
| | 293 | COPYELEMENT_LOAD(Tightness) |
| | 294 | COPYELEMENT_LOAD(Position) |
| | 295 | COPYELEMENT_LOAD(Orientation) |
| | 296 | |
| | 297 | *GrapplingHook.DispPtr->ObStrategyBlock->DynPtr = block->dynamics; |
| | 298 | } |
| | 299 | |
| | 300 | void SaveStrategy_Grapple(STRATEGYBLOCK* sbPtr) |
| | 301 | { |
| | 302 | GRAPPLE_SAVE_BLOCK* block; |
| | 303 | |
| | 304 | GET_STRATEGY_SAVE_BLOCK(block,sbPtr); |
| | 305 | |
| | 306 | //copy stuff to the save block |
| | 307 | COPYELEMENT_SAVE(IsEmbedded) |
| | 308 | COPYELEMENT_SAVE(IsEngaged) |
| | 309 | COPYELEMENT_SAVE(Tightness) |
| | 310 | COPYELEMENT_SAVE(Position) |
| | 311 | COPYELEMENT_SAVE(Orientation) |
| | 312 | |
| | 313 | block->dynamics = *sbPtr->DynPtr; |
| | 314 | block->dynamics.CollisionReportPtr=0; |
| | 315 | } |