| | 1 | #include "npc_common.h" |
| | 2 | #include "dynamics.h" |
| | 3 | #include "savegame.h" |
| | 4 | #include "game_statistics.h" |
| | 5 | #include "frustum.h" |
| | 6 | #include "usr_io.h" |
| | 7 | #include "userprofile.h" |
| | 8 | #include "sequnces.h" |
| | 9 | #include "hud.h" |
| | 10 | #include <stdlib.h> |
| | 11 | |
| | 12 | PLAYER_INPUT_CONFIGURATION *primaryInput; |
| | 13 | PLAYER_INPUT_CONFIGURATION *secondaryInput; |
| | 14 | |
| | 15 | extern void InitialiseGrapplingHook(); |
| | 16 | |
| | 17 | extern int Keyboard_input_operate(); |
| | 18 | extern void handle_user_input(); |
| | 19 | extern unsigned int mission_messages_timer; |
| | 20 | extern char * mission_messages; |
| | 21 | extern HMODELCONTROLLER PlayersWeaponHModelController; |
| | 22 | extern int predHUDSoundHandle; |
| | 23 | extern int predOVision_SoundHandle; |
| | 24 | extern int weaponHandle; |
| | 25 | extern int AVPDPNetID; |
| | 26 | extern int myNetworkKillerId; |
| | 27 | extern int MyHitBodyPartId; |
| | 28 | extern int MultiplayerObservedPlayer; |
| | 29 | extern int PlayersMaxHeightWhilstNotInContactWithGround; |
| | 30 | |
| | 31 | extern int SlotForThisWeapon(enum WEAPON_ID weaponID); |
| | 32 | extern void LoadAllWeapons(); |
| | 33 | extern void DisengageGrapplingHook(); |
| | 34 | extern int LightIntensityAtPoint(VECTORCH *pointPtr); |
| | 35 | extern void PointAlert(int level, VECTORCH *point); |
| | 36 | extern void InitMarineHUD(); |
| | 37 | |
| | 38 | PLAYER_STATUS PlayerStatus; |
| | 39 | int AlienTeethOffset = 0; |
| | 40 | int AlienTongueOffset = 0; |
| | 41 | int deathFadeLevel; |
| | 42 | int CloakingPhase; |
| | 43 | EULER HeadOrientation = {0,0,0}; |
| | 44 | |
| | 45 | extern int TURNSCALE; |
| | 46 | int ALIEN_STRAFESCALE; |
| | 47 | int PREDATOR_STRAFESCALE; |
| | 48 | int MARINE_STRAFESCALE; |
| | 49 | |
| | 50 | static void InitialisePlayersInventory() |
| | 51 | { |
| | 52 | int a; |
| | 53 | |
| | 54 | switch(AvP.PlayerType) |
| | 55 | { |
| | 56 | case I_Marine: |
| | 57 | { |
| | 58 | GrenadeLauncherData.StandardRoundsRemaining = 0; |
| | 59 | GrenadeLauncherData.StandardMagazinesRemaining = 0; |
| | 60 | GrenadeLauncherData.ProximityRoundsRemaining = 0; |
| | 61 | GrenadeLauncherData.ProximityMagazinesRemaining = 0; |
| | 62 | GrenadeLauncherData.FragmentationRoundsRemaining = 0; |
| | 63 | GrenadeLauncherData.FragmentationMagazinesRemaining = 0; |
| | 64 | GrenadeLauncherData.SelectedAmmo = AMMO_GRENADE; |
| | 65 | |
| | 66 | PlayerStatus.JetpackEnabled = PlayerStatus.StartingEquipment.marine_jetpack; |
| | 67 | |
| | 68 | a = SlotForThisWeapon(WEAPON_CUDGEL); |
| | 69 | |
| | 70 | if (a != -1) |
| | 71 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 72 | |
| | 73 | /*if in a multiplayer game , check to see if player is a specialist marine*/ |
| | 74 | if(SinglePlayer != AvP.PlayMode) |
| | 75 | { |
| | 76 | if (netGameData.specialistPistols) |
| | 77 | { |
| | 78 | /* Conditional pistol! */ |
| | 79 | a = SlotForThisWeapon(WEAPON_MARINE_PISTOL); |
| | 80 | |
| | 81 | if (a != -1) |
| | 82 | { |
| | 83 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 84 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 6; |
| | 85 | } |
| | 86 | } |
| | 87 | |
| | 88 | switch(netGameData.myCharacterSubType) |
| | 89 | { |
| | 90 | case NGSCT_Smartgun: |
| | 91 | a = SlotForThisWeapon(WEAPON_SMARTGUN); |
| | 92 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 93 | |
| | 94 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 6; |
| | 95 | break; |
| | 96 | case NGSCT_Flamer: |
| | 97 | a = SlotForThisWeapon(WEAPON_FLAMETHROWER); |
| | 98 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 99 | |
| | 100 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 8; |
| | 101 | break; |
| | 102 | case NGSCT_Sadar: |
| | 103 | a = SlotForThisWeapon(WEAPON_SADAR); |
| | 104 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 105 | |
| | 106 | PlayerStatus.WeaponSlot[a].PrimaryRoundsRemaining = 10; |
| | 107 | break; |
| | 108 | case NGSCT_GrenadeLauncher: |
| | 109 | a = SlotForThisWeapon(WEAPON_GRENADELAUNCHER); |
| | 110 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 111 | |
| | 112 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 4; |
| | 113 | GrenadeLauncherData.StandardMagazinesRemaining = 4; |
| | 114 | GrenadeLauncherData.ProximityMagazinesRemaining = 4; |
| | 115 | GrenadeLauncherData.FragmentationMagazinesRemaining = 4; |
| | 116 | break; |
| | 117 | case NGSCT_Minigun: |
| | 118 | a = SlotForThisWeapon(WEAPON_MINIGUN); |
| | 119 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 120 | |
| | 121 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 4; |
| | 122 | break; |
| | 123 | case NGSCT_PulseRifle: |
| | 124 | a = SlotForThisWeapon(WEAPON_PULSERIFLE); |
| | 125 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 126 | |
| | 127 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 10; |
| | 128 | PlayerStatus.WeaponSlot[a].SecondaryRoundsRemaining = 15; |
| | 129 | break; |
| | 130 | case NGSCT_Frisbee: |
| | 131 | a = SlotForThisWeapon(WEAPON_FRISBEE_LAUNCHER); |
| | 132 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 133 | |
| | 134 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 5; |
| | 135 | break; |
| | 136 | case NGSCT_Pistols: |
| | 137 | a = SlotForThisWeapon(WEAPON_MARINE_PISTOL); |
| | 138 | |
| | 139 | if (a != -1) |
| | 140 | { |
| | 141 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 142 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 30; |
| | 143 | } |
| | 144 | |
| | 145 | a = SlotForThisWeapon(WEAPON_TWO_PISTOLS); |
| | 146 | |
| | 147 | if (a != -1) |
| | 148 | { |
| | 149 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 150 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 30; |
| | 151 | } |
| | 152 | break; |
| | 153 | case NGSCT_General: |
| | 154 | default: |
| | 155 | |
| | 156 | a = SlotForThisWeapon(WEAPON_PULSERIFLE); |
| | 157 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 158 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 6; |
| | 159 | PlayerStatus.WeaponSlot[a].SecondaryRoundsRemaining = 5; |
| | 160 | } |
| | 161 | } |
| | 162 | else |
| | 163 | { |
| | 164 | a = SlotForThisWeapon(WEAPON_PULSERIFLE); |
| | 165 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 166 | |
| | 167 | if (CHEATMODE_GRENADE == UserProfile.active_bonus) |
| | 168 | { |
| | 169 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 0; |
| | 170 | PlayerStatus.WeaponSlot[a].SecondaryRoundsRemaining = 99; |
| | 171 | } |
| | 172 | else |
| | 173 | { |
| | 174 | PlayerStatus.WeaponSlot[a].MagazinesRemaining = 4; |
| | 175 | PlayerStatus.WeaponSlot[a].SecondaryRoundsRemaining = 4; |
| | 176 | } |
| | 177 | } |
| | 178 | } |
| | 179 | break; |
| | 180 | case I_Predator: |
| | 181 | { |
| | 182 | PlayerStatus.GrapplingHookEnabled = PlayerStatus.StartingEquipment.predator_grappling_hook; |
| | 183 | |
| | 184 | if(PlayerStatus.StartingEquipment.predator_pistol) |
| | 185 | { |
| | 186 | a = SlotForThisWeapon(WEAPON_PRED_PISTOL); |
| | 187 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 188 | } |
| | 189 | |
| | 190 | if(PlayerStatus.StartingEquipment.predator_num_spears) |
| | 191 | { |
| | 192 | a = SlotForThisWeapon(WEAPON_PRED_RIFLE); |
| | 193 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 194 | PlayerStatus.WeaponSlot[a].PrimaryRoundsRemaining = PlayerStatus.StartingEquipment.predator_num_spears; |
| | 195 | } |
| | 196 | |
| | 197 | if(PlayerStatus.StartingEquipment.predator_plasmacaster) |
| | 198 | { |
| | 199 | a = SlotForThisWeapon(WEAPON_PRED_SHOULDERCANNON); |
| | 200 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 201 | } |
| | 202 | |
| | 203 | if(PlayerStatus.StartingEquipment.predator_disc) |
| | 204 | { |
| | 205 | a = SlotForThisWeapon(WEAPON_PRED_DISC); |
| | 206 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 207 | PlayerStatus.WeaponSlot[a].PrimaryRoundsRemaining = 1; |
| | 208 | } |
| | 209 | |
| | 210 | if(PlayerStatus.StartingEquipment.predator_medicomp) |
| | 211 | { |
| | 212 | a = SlotForThisWeapon(WEAPON_PRED_MEDICOMP); |
| | 213 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 214 | } |
| | 215 | |
| | 216 | a = SlotForThisWeapon(WEAPON_PRED_WRISTBLADE); |
| | 217 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 218 | } |
| | 219 | break; |
| | 220 | case I_Alien: |
| | 221 | { |
| | 222 | a = SlotForThisWeapon(WEAPON_ALIEN_CLAW); |
| | 223 | PlayerStatus.WeaponSlot[a].Possessed = 1; |
| | 224 | PlayerStatus.SelectedWeapon = &PlayerStatus.WeaponSlot[a]; |
| | 225 | return; |
| | 226 | } |
| | 227 | } |
| | 228 | |
| | 229 | PlayerStatus.PreviouslySelectedWeaponSlot = a; |
| | 230 | PlayerStatus.SwapToWeaponSlot = a; |
| | 231 | PlayerStatus.SelectedWeapon = &PlayerStatus.WeaponSlot[a]; |
| | 232 | LoadAllWeapons(); |
| | 233 | } |
| | 234 | |
| | 235 | void create_player_hmodel() |
| | 236 | { |
| | 237 | const SECTION *root_section; |
| | 238 | |
| | 239 | switch(AvP.PlayerType) |
| | 240 | { |
| | 241 | case I_Alien: |
| | 242 | root_section = GetNamedHierarchyFromLibrary("hnpcalien", "alien"); |
| | 243 | //root_section = GetNamedHierarchyFromLibrary("hnpcpred_alien", "TEMPLATE"); |
| | 244 | //root_section = GetNamedHierarchyFromLibrary("hnpcpretorian","Template"); |
| | 245 | break; |
| | 246 | case I_Marine: |
| | 247 | switch (PlayerStatus.SelectedWeapon->WeaponIDNumber) |
| | 248 | { |
| | 249 | default: |
| | 250 | case WEAPON_PULSERIFLE: |
| | 251 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "marine with pulse rifle"); |
| | 252 | break; |
| | 253 | case WEAPON_TWO_PISTOLS: |
| | 254 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "Two Pistol"); |
| | 255 | break; |
| | 256 | case WEAPON_MARINE_PISTOL: |
| | 257 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "PISTOL"); |
| | 258 | break; |
| | 259 | case WEAPON_FLAMETHROWER: |
| | 260 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "marine with flame thrower"); |
| | 261 | break; |
| | 262 | case WEAPON_SMARTGUN: |
| | 263 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "marine with smart gun"); |
| | 264 | break; |
| | 265 | case WEAPON_MINIGUN: |
| | 266 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "Marine with Mini Gun"); |
| | 267 | break; |
| | 268 | case WEAPON_SADAR: |
| | 269 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "marine with SADAR"); |
| | 270 | break; |
| | 271 | case WEAPON_GRENADELAUNCHER: |
| | 272 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "marine + grenade launcher"); |
| | 273 | break; |
| | 274 | case WEAPON_CUDGEL: |
| | 275 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "Cudgel"); |
| | 276 | break; |
| | 277 | case WEAPON_FRISBEE_LAUNCHER: |
| | 278 | root_section = GetNamedHierarchyFromLibrary("hnpcmarine", "skeeter"); |
| | 279 | } |
| | 280 | break; |
| | 281 | case I_Predator: |
| | 282 | switch (PlayerStatus.SelectedWeapon->WeaponIDNumber) |
| | 283 | { |
| | 284 | default: |
| | 285 | case WEAPON_PRED_WRISTBLADE: |
| | 286 | root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "pred with wristblade"); |
| | 287 | break; |
| | 288 | case WEAPON_PRED_RIFLE: |
| | 289 | root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "Speargun"); |
| | 290 | break; |
| | 291 | case WEAPON_PRED_MEDICOMP: |
| | 292 | root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "medicomp"); |
| | 293 | break; |
| | 294 | case WEAPON_PRED_SHOULDERCANNON: |
| | 295 | root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "pred with Plasma Caster"); |
| | 296 | break; |
| | 297 | case WEAPON_PRED_PISTOL: |
| | 298 | root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "pred + pistol"); |
| | 299 | break; |
| | 300 | case WEAPON_PRED_DISC: |
| | 301 | root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "pred with disk"); |
| | 302 | //root_section = GetNamedHierarchyFromLibrary("hnpcpredator", "pred with staff"); |
| | 303 | } |
| | 304 | } |
| | 305 | |
| | 306 | Dispel_HModel(&PlayerStatus.HModelController); |
| | 307 | Create_HModel(&PlayerStatus.HModelController, root_section); |
| | 308 | InitHModelSequence(&PlayerStatus.HModelController, 0, 0, ONE_FIXED); |
| | 309 | //PlayerStatus.HModelController.Playing = 0; |
| | 310 | PlayerStatus.HModelController.Looped = 0; |
| | 311 | ProveHModel_Far(&PlayerStatus.HModelController, PlayerStatus.sbptr); |
| | 312 | } |
| | 313 | |
| | 314 | static void ConfigurePlayer() |
| | 315 | { |
| | 316 | PlayerStatus.DisplayBlock->ObFlags |= ObFlag_NotVis; |
| | 317 | Observer = 0; |
| | 318 | mission_messages = NULL; |
| | 319 | mission_messages_timer = 0; |
| | 320 | mission_messages_clear(); |
| | 321 | |
| | 322 | PlayerStatus.LeanScale = ONE_FIXED; |
| | 323 | |
| | 324 | if (CHEATMODE_MIRROR == UserProfile.active_bonus) |
| | 325 | { |
| | 326 | TURNSCALE = -2000; |
| | 327 | ALIEN_STRAFESCALE = -12000; |
| | 328 | PREDATOR_STRAFESCALE = -8000; |
| | 329 | MARINE_STRAFESCALE = -7000; |
| | 330 | } |
| | 331 | else |
| | 332 | { |
| | 333 | TURNSCALE = 2000; |
| | 334 | ALIEN_STRAFESCALE = 12000; |
| | 335 | PREDATOR_STRAFESCALE = 8000; |
| | 336 | MARINE_STRAFESCALE = 7000; |
| | 337 | } |
| | 338 | |
| | 339 | { |
| | 340 | extern int AllowedLookUpAngle; |
| | 341 | extern int AllowedLookDownAngle; |
| | 342 | extern float CameraZoomScale; |
| | 343 | extern int CameraZoomLevel; |
| | 344 | extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; |
| | 345 | |
| | 346 | Global_VDB.VDB_ProjX = ScreenDescriptorBlock.SDB_CentreX; |
| | 347 | Global_VDB.VDB_ProjY = ScreenDescriptorBlock.SDB_CentreY; |
| | 348 | |
| | 349 | const NPC_DATA *NpcData; |
| | 350 | AllowedLookUpAngle = 328; |
| | 351 | AllowedLookDownAngle = 1700; |
| | 352 | HeadOrientation.EulerX = HeadOrientation.EulerY = HeadOrientation.EulerZ = 0; |
| | 353 | PlayerStatus.VisionMode = VISION_MODE_NORMAL; |
| | 354 | CameraZoomScale = 1.0f; |
| | 355 | CameraZoomLevel = 0; |
| | 356 | PredatorVisionChangeCounter = 0; |
| | 357 | enum WEAPON_ID *PlayerWeaponKey; |
| | 358 | |
| | 359 | PlayerStatus.imageintensifier_battery = 0; |
| | 360 | PlayerStatus.FlaresLeft = 20; |
| | 361 | PlayerStatus.sbptr->DamageBlock.Health = 0; |
| | 362 | PlayerStatus.sbptr->DamageBlock.Armour = 0; |
| | 363 | PlayerStatus.sbptr->DamageBlock.AcidResistant = 0; |
| | 364 | PlayerStatus.sbptr->DamageBlock.FireResistant = 0; |
| | 365 | PlayerStatus.sbptr->DamageBlock.ElectricResistant = 0; |
| | 366 | PlayerStatus.sbptr->DamageBlock.PerfectArmour = 0; |
| | 367 | PlayerStatus.sbptr->DamageBlock.ElectricSensitive = 0; |
| | 368 | PlayerStatus.sbptr->DamageBlock.IsOnFire = 0; |
| | 369 | PlayerStatus.sbptr->DamageBlock.Indestructable = 0; |
| | 370 | PlayerStatus.sbptr->DamageBlock.Combustability = 1; |
| | 371 | |
| | 372 | if(!UserProfile.GameOptions.BloodParticles) |
| | 373 | AvP.Difficulty = I_Easy; |
| | 374 | |
| | 375 | switch(AvP.PlayerType) |
| | 376 | { |
| | 377 | case I_Marine: |
| | 378 | switch (AvP.Difficulty) |
| | 379 | { |
| | 380 | default: |
| | 381 | case I_Easy: |
| | 382 | PlayerStatus.sbptr->DamageBlock.AcidResistant = 1; |
| | 383 | case I_Medium: |
| | 384 | PlayerStatus.imageintensifier_battery = FIXED_MINUTE * 3; |
| | 385 | case I_Hard: |
| | 386 | NpcData = &NpcDataList[I_NPC_Marine]; |
| | 387 | } |
| | 388 | PlayerStatus.sbptr->DynPtr->ToppleForce = TOPPLE_FORCE_NONE; |
| | 389 | PlayerStatus.sbptr->DynPtr->Mass = 80; |
| | 390 | PlayerWeaponKey = MarineWeaponKey; |
| | 391 | PlayerStatus.bhvr_type = I_BehaviourMarinePlayer; |
| | 392 | PlayerStatus.sbptr->type = I_BehaviourMarinePlayer; |
| | 393 | SetFrustrumType(FRUSTRUM_TYPE_NORMAL); |
| | 394 | InitMarineHUD(); |
| | 395 | primaryInput = &UserProfile.MarineInputPrimaryConfig; |
| | 396 | secondaryInput = &UserProfile.MarineInputSecondaryConfig; |
| | 397 | PlayerStatus.Hud = marine_hud; |
| | 398 | PlayerStatus.weapon_func = maintain_marine_weapons; |
| | 399 | break; |
| | 400 | case I_Predator: |
| | 401 | switch (AvP.Difficulty) |
| | 402 | { |
| | 403 | default: |
| | 404 | case I_Easy: |
| | 405 | PlayerStatus.sbptr->DamageBlock.AcidResistant = 1; |
| | 406 | case I_Medium: |
| | 407 | case I_Hard: |
| | 408 | NpcData = &NpcDataList[I_NPC_PredatorAlien]; |
| | 409 | } |
| | 410 | PlayerStatus.sbptr->DynPtr->ToppleForce = TOPPLE_FORCE_NONE; |
| | 411 | PlayerStatus.sbptr->DynPtr->Mass = 180; |
| | 412 | PlayerWeaponKey = PredatorWeaponKey; |
| | 413 | PlayerStatus.bhvr_type = I_BehaviourPredatorPlayer; |
| | 414 | PlayerStatus.sbptr->type = I_BehaviourPredatorPlayer; |
| | 415 | SetFrustrumType(FRUSTRUM_TYPE_NORMAL); |
| | 416 | InitialiseGrapplingHook(); |
| | 417 | primaryInput = &UserProfile.PredatorInputPrimaryConfig; |
| | 418 | secondaryInput = &UserProfile.PredatorInputSecondaryConfig; |
| | 419 | predOVision_SoundHandle = SOUND_NOACTIVEINDEX; |
| | 420 | PlayerStatus.Hud = predator_hud; |
| | 421 | PlayerStatus.weapon_func = maintain_predator_weapons; |
| | 422 | break; |
| | 423 | case I_Alien: |
| | 424 | NpcData = &NpcDataList[I_NPC_Alien]; |
| | 425 | PlayerStatus.sbptr->DamageBlock.AcidResistant = 1; |
| | 426 | PlayerStatus.sbptr->DamageBlock.ElectricSensitive = 1; |
| | 427 | PlayerStatus.sbptr->DamageBlock.PerfectArmour = 1; |
| | 428 | PlayerStatus.sbptr->DamageBlock.Combustability = 0; |
| | 429 | PlayerStatus.sbptr->DynPtr->Mass = 160; |
| | 430 | PlayerWeaponKey = AlienWeaponKey; |
| | 431 | PlayerStatus.sbptr->DynPtr->ToppleForce = TOPPLE_FORCE_ALIEN; |
| | 432 | PlayerStatus.bhvr_type = I_BehaviourAlienPlayer; |
| | 433 | PlayerStatus.sbptr->type = I_BehaviourAlienPlayer; |
| | 434 | AlienTeethOffset = 0; |
| | 435 | AlienTongueOffset = 0; |
| | 436 | /* setup wide-angle lens */ |
| | 437 | Global_VDB.VDB_ProjX /= 2; |
| | 438 | Global_VDB.VDB_ProjY /= 2; |
| | 439 | SetFrustrumType(FRUSTRUM_TYPE_WIDE); |
| | 440 | PlayerStatus.LeanScale *= 3; |
| | 441 | primaryInput = &UserProfile.AlienInputPrimaryConfig; |
| | 442 | secondaryInput = &UserProfile.AlienInputSecondaryConfig; |
| | 443 | AllowedLookUpAngle = 0; |
| | 444 | PlayerStatus.Hud = alien_hud; |
| | 445 | PlayerStatus.weapon_func = maintain_alien_weapons; |
| | 446 | } |
| | 447 | |
| | 448 | PlayerStatus.StartingHealth = NpcData->StartingStats.Health; |
| | 449 | PlayerStatus.StartingArmour = NpcData->StartingStats.Armour; |
| | 450 | |
| | 451 | PlayerStatus.sbptr->DamageBlock = NpcData->StartingStats; |
| | 452 | PlayerStatus.sbptr->DamageBlock.Health = PlayerStatus.StartingHealth << ONE_FIXED_SHIFT; |
| | 453 | PlayerStatus.sbptr->DamageBlock.Armour = PlayerStatus.StartingArmour << ONE_FIXED_SHIFT; |
| | 454 | |
| | 455 | PlayerStatus.sbptr->DynPtr->UseStandardGravity = 1; |
| | 456 | |
| | 457 | { |
| | 458 | int slot = MAX_NO_OF_WEAPON_SLOTS; |
| | 459 | |
| | 460 | do |
| | 461 | { |
| | 462 | struct PLAYER_WEAPON_DATA *wdPtr = &PlayerStatus.WeaponSlot[--slot]; |
| | 463 | |
| | 464 | wdPtr->WeaponIDNumber = PlayerWeaponKey[slot]; |
| | 465 | wdPtr->PrimaryRoundsRemaining = 0; |
| | 466 | wdPtr->SecondaryRoundsRemaining = 0; |
| | 467 | wdPtr->MagazinesRemaining = 0; |
| | 468 | wdPtr->LeftOverBullets = 0; |
| | 469 | wdPtr->Possessed = 0; |
| | 470 | |
| | 471 | } while(slot); |
| | 472 | } |
| | 473 | } |
| | 474 | |
| | 475 | PlayerStatus.incidentFlag = 0; |
| | 476 | PlayerStatus.incidentTimer = 0; |
| | 477 | |
| | 478 | PlayerStatus.cloakOn = 0; |
| | 479 | PlayerStatus.muzzle_flash = 0; |
| | 480 | PlayerStatus.FirstPersonView = 1; |
| | 481 | PlayerStatus.CloakingEffectiveness = 0; |
| | 482 | PlayerStatus.FieldCharge = PLAYERCLOAK_MAXENERGY; |
| | 483 | PlayerStatus.PlasmaCasterCharge = 0; |
| | 484 | |
| | 485 | /* CDF 16/9/97 Now, those health and armour stats are those of the last cycle. */ |
| | 486 | |
| | 487 | PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health; |
| | 488 | PlayerStatus.Armour = PlayerStatus.sbptr->DamageBlock.Armour; |
| | 489 | |
| | 490 | PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon = 0; |
| | 491 | PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon = 0; |
| | 492 | PlayerStatus.InputRequests.Rqst_Forward = 0; |
| | 493 | PlayerStatus.InputRequests.Rqst_Backward = 0; |
| | 494 | PlayerStatus.InputRequests.Rqst_SideStepLeft = 0; |
| | 495 | PlayerStatus.InputRequests.Rqst_SideStepRight = 0; |
| | 496 | PlayerStatus.InputRequests.Rqst_Strafe = 0; |
| | 497 | PlayerStatus.InputRequests.Rqst_Jump = 0; |
| | 498 | PlayerStatus.InputRequests.Rqst_Walk = 0; |
| | 499 | |
| | 500 | PlayerStatus.Alive = 1; |
| | 501 | PlayerStatus.RequestsToStandUp = 0; |
| | 502 | PlayerStatus.IHaveAPlacedAutogun = 0; |
| | 503 | PlayerStatus.tauntTimer = 0; |
| | 504 | PlayerStatus.invulnerabilityTimer = 0; |
| | 505 | PlayerStatus.ForwardInertia = 0; |
| | 506 | PlayerStatus.StrafeInertia = 0; |
| | 507 | PlayerStatus.TurnInertia = 0; |
| | 508 | PlayerStatus.Crouching = 0; |
| | 509 | PlayerStatus.ViewPanX = 0; |
| | 510 | PlayerStatus.securityClearances = 0; |
| | 511 | PlayerStatus.DamagedOverlayIntensity = 0; |
| | 512 | PlayerStatus.CurrentLightAtPlayer = 0; |
| | 513 | |
| | 514 | /* Better safe than sorry. */ |
| | 515 | PlayerStatus.sound_mouth = SOUND_NOACTIVEINDEX; |
| | 516 | PlayerStatus.soundCracklingFire = SOUND_NOACTIVEINDEX; |
| | 517 | PlayerStatus.sound_watersplash = SOUND_NOACTIVEINDEX; |
| | 518 | PlayerStatus.sound_jetpack = SOUND_NOACTIVEINDEX; |
| | 519 | |
| | 520 | PlayerStatus.WeaponStateTimeOutCounter = 0; |
| | 521 | PlayerStatus.WeaponState = WEAPONSTATE_SWAPPING_IN; |
| | 522 | PlayerStatus.WeaponPositionOffset.vx = 0; |
| | 523 | PlayerStatus.WeaponPositionOffset.vy = 0; |
| | 524 | PlayerStatus.WeaponPositionOffset.vz = 0; |
| | 525 | |
| | 526 | switch(AvP.Difficulty) |
| | 527 | { |
| | 528 | case I_Easy: |
| | 529 | PlayerStatus.saves_left = 4; |
| | 530 | break; |
| | 531 | case I_Medium: |
| | 532 | PlayerStatus.saves_left = 2; |
| | 533 | break; |
| | 534 | case I_Hard: |
| | 535 | default: |
| | 536 | PlayerStatus.saves_left = 1; |
| | 537 | } |
| | 538 | |
| | 539 | InitialisePlayersInventory(); |
| | 540 | GrabWeaponShape(); |
| | 541 | |
| | 542 | if(SinglePlayer == AvP.PlayMode) |
| | 543 | SoundSys_FadeIn(); |
| | 544 | else |
| | 545 | SoundSys_ResetFadeLevel(); |
| | 546 | } |
| | 547 | |
| | 548 | int InitPlayer() |
| | 549 | { |
| | 550 | PlayerStatus.DisplayBlock = CreateActiveObject(); |
| | 551 | PlayerStatus.sbptr = CreateActiveStrategyBlock(I_BehaviourMarinePlayer); |
| | 552 | PlayerStatus.HModelController.Deltas = NULL; |
| | 553 | PlayerStatus.HModelController.Root_Section = NULL; |
| | 554 | PlayerStatus.HModelController.section_data= NULL; |
| | 555 | |
| | 556 | if((NULL != PlayerStatus.sbptr) && (NULL != PlayerStatus.DisplayBlock)) |
| | 557 | { |
| | 558 | PlayerStatus.DisplayBlock->ObStrategyBlock = PlayerStatus.sbptr; |
| | 559 | PlayerStatus.sbptr->DisplayBlock = PlayerStatus.DisplayBlock; |
| | 560 | PlayerStatus.DisplayBlock->HModelControlBlock = &PlayerStatus.HModelController; |
| | 561 | PlayerStatus.DisplayBlock->ObFlags |= ObFlag_NotVis; |
| | 562 | PlayerStatus.sbptr->maintainVisibility = 0; // player is always near; skip DoObjectVisibility. |
| | 563 | |
| | 564 | PlayerStatus.sbptr->dataptr = (void*)&PlayerStatus; |
| | 565 | AssignNewSBName(PlayerStatus.sbptr); |
| | 566 | PlayerStatus.sbptr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 567 | |
| | 568 | if(NULL != PlayerStatus.sbptr->DynPtr) |
| | 569 | { |
| | 570 | extern const DISPLAYBLOCK Zero_Displayblock; |
| | 571 | DYNAMICSBLOCK *dynPtr = PlayerStatus.sbptr->DynPtr; |
| | 572 | |
| | 573 | dynPtr->PrevPosition = dynPtr->Position = PlayerStatus.DisplayBlock->ObWorld = PlayerStatus.StartLocation; |
| | 574 | dynPtr->PrevOrientMat = dynPtr->OrientMat = PlayerStatus.StartMat; |
| | 575 | MatrixToEuler(&dynPtr->OrientMat, &dynPtr->OrientEuler); |
| | 576 | |
| | 577 | dynPtr->PrevOrientEuler = dynPtr->OrientEuler; |
| | 578 | |
| | 579 | PlayersMaxHeightWhilstNotInContactWithGround = dynPtr->Position.vy; |
| | 580 | |
| | 581 | PlayerStatus.weapon = Zero_Displayblock; |
| | 582 | PlayerStatus.weapon.HModelControlBlock = &PlayersWeaponHModelController; |
| | 583 | |
| | 584 | ConfigurePlayer(); |
| | 585 | return 1; |
| | 586 | } |
| | 587 | } |
| | 588 | |
| | 589 | |
| | 590 | return 0; |
| | 591 | } |
| | 592 | |
| | 593 | static void MakePlayersWeaponPickupVisible() |
| | 594 | { |
| | 595 | int i = NumActiveStBlocks - 1; |
| | 596 | |
| | 597 | /* |
| | 598 | Search through the strategy block list for weapons. |
| | 599 | Any weapons that have a lifespan timer should be made visible. |
| | 600 | There should only be one such object , so we can stop looking once we find it |
| | 601 | */ |
| | 602 | |
| | 603 | for(; i >= 0; i--) |
| | 604 | { |
| | 605 | STRATEGYBLOCK* sbPtr = ActiveStBlockList[i]; |
| | 606 | |
| | 607 | if(sbPtr->type == I_BehaviourInanimateObject && !sbPtr->maintainVisibility) |
| | 608 | { |
| | 609 | INANIMATEOBJECT_STATUSBLOCK* objectstatusptr = (INANIMATEOBJECT_STATUSBLOCK*)sbPtr->dataptr; |
| | 610 | |
| | 611 | if(objectstatusptr->typeId == IOT_Weapon) |
| | 612 | { |
| | 613 | if(objectstatusptr->lifespanTimer > 0) |
| | 614 | { |
| | 615 | //okay we've found the object , so allow it to be visible |
| | 616 | sbPtr->DynPtr->IsPickupObject = 1; |
| | 617 | sbPtr->maintainVisibility = 1; |
| | 618 | return; |
| | 619 | } |
| | 620 | } |
| | 621 | } |
| | 622 | } |
| | 623 | } |
| | 624 | |
| | 625 | static int ObjectIsPlayersDisc(STRATEGYBLOCK *sbPtr) |
| | 626 | { |
| | 627 | switch(sbPtr->type) |
| | 628 | { |
| | 629 | case I_BehaviourInanimateObject: |
| | 630 | { |
| | 631 | INANIMATEOBJECT_STATUSBLOCK* objStatPtr = sbPtr->dataptr; |
| | 632 | |
| | 633 | /* Make sure the object hasn't already been picked up this frame */ |
| | 634 | if(!sbPtr->please_destroy_me && !objStatPtr->respawnTimer) |
| | 635 | { |
| | 636 | if (objStatPtr->typeId == IOT_Ammo) |
| | 637 | { |
| | 638 | if (objStatPtr->subType == AMMO_PRED_DISC) |
| | 639 | return 1; |
| | 640 | } |
| | 641 | } |
| | 642 | } |
| | 643 | break; |
| | 644 | case I_BehaviourPredatorDisc_SeekTrack: |
| | 645 | { |
| | 646 | /* Erm... just return? */ |
| | 647 | return 1; |
| | 648 | } |
| | 649 | default: |
| | 650 | return 0; |
| | 651 | } |
| | 652 | |
| | 653 | return 0; |
| | 654 | } |
| | 655 | |
| | 656 | static void RemoveAllThisPlayersDiscs() |
| | 657 | { |
| | 658 | int a; |
| | 659 | |
| | 660 | /* All discs that are NOT ghosted must 'belong' to this player. */ |
| | 661 | |
| | 662 | for (a=0; a < NumActiveStBlocks; a++) |
| | 663 | { |
| | 664 | STRATEGYBLOCK *candidate = ActiveStBlockList[a]; |
| | 665 | |
| | 666 | if (candidate->DynPtr && ObjectIsPlayersDisc(candidate)) |
| | 667 | { |
| | 668 | /* Are we the right type? */ |
| | 669 | AddNetMsg_LocalObjectDestroyed(candidate); |
| | 670 | candidate->please_destroy_me = 1; |
| | 671 | } |
| | 672 | } |
| | 673 | } |
| | 674 | |
| | 675 | static void NetPlayerRespawn() |
| | 676 | { |
| | 677 | /* When you're going to respawn... you might change */ |
| | 678 | /* character class, after all. */ |
| | 679 | |
| | 680 | if (PlayerStatus.sound_mouth != SOUND_NOACTIVEINDEX) |
| | 681 | Sound_Stop(PlayerStatus.sound_mouth); |
| | 682 | |
| | 683 | if (PlayerStatus.soundCracklingFire != SOUND_NOACTIVEINDEX) |
| | 684 | Sound_Stop(PlayerStatus.soundCracklingFire); |
| | 685 | |
| | 686 | if (weaponHandle != SOUND_NOACTIVEINDEX) |
| | 687 | Sound_Stop(weaponHandle); |
| | 688 | |
| | 689 | if (predHUDSoundHandle != SOUND_NOACTIVEINDEX) |
| | 690 | Sound_Stop(predHUDSoundHandle); |
| | 691 | |
| | 692 | if (predOVision_SoundHandle != SOUND_NOACTIVEINDEX) |
| | 693 | Sound_Stop(predOVision_SoundHandle); |
| | 694 | |
| | 695 | ConfigurePlayer(); |
| | 696 | //reset the player's elasticity (which gets altered upon death) |
| | 697 | PlayerStatus.sbptr->DynPtr->Elasticity = 0; |
| | 698 | |
| | 699 | TurnOffMultiplayerObserveMode(); |
| | 700 | |
| | 701 | //The player's dropped weapon (if there was one) can now be drawn |
| | 702 | MakePlayersWeaponPickupVisible(); |
| | 703 | RemoveAllThisPlayersDiscs(); |
| | 704 | ChooseLightingModel(); |
| | 705 | } |
| | 706 | |
| | 707 | void ChangeToMarine() |
| | 708 | { |
| | 709 | if (I_Marine != AvP.PlayerType) |
| | 710 | { |
| | 711 | AvP.PlayerType = I_Marine; |
| | 712 | NetPlayerRespawn(); |
| | 713 | netGameData.myCharacterType = netGameData.myNextCharacterType = NGCT_Marine; |
| | 714 | |
| | 715 | //reorient the player |
| | 716 | { |
| | 717 | EULER e; |
| | 718 | MatrixToEuler(&PlayerStatus.sbptr->DynPtr->OrientMat, &e); |
| | 719 | e.EulerX = e.EulerZ = 0; |
| | 720 | |
| | 721 | CreateEulerMatrix(&e, &PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 722 | TransposeMatrixCH(&PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 723 | } |
| | 724 | } |
| | 725 | } |
| | 726 | |
| | 727 | void ChangeToAlien() |
| | 728 | { |
| | 729 | if (I_Alien != AvP.PlayerType) |
| | 730 | { |
| | 731 | AvP.PlayerType = I_Alien; |
| | 732 | NetPlayerRespawn(); |
| | 733 | netGameData.myCharacterType = netGameData.myNextCharacterType = NGCT_Alien; |
| | 734 | } |
| | 735 | } |
| | 736 | |
| | 737 | void ChangeToPredator() |
| | 738 | { |
| | 739 | if (I_Predator != AvP.PlayerType) |
| | 740 | { |
| | 741 | AvP.PlayerType = I_Predator; |
| | 742 | NetPlayerRespawn(); |
| | 743 | netGameData.myCharacterType = netGameData.myNextCharacterType = NGCT_Predator; |
| | 744 | |
| | 745 | { |
| | 746 | EULER e; |
| | 747 | MatrixToEuler(&PlayerStatus.sbptr->DynPtr->OrientMat,&e); |
| | 748 | e.EulerX = e.EulerZ = 0; |
| | 749 | |
| | 750 | CreateEulerMatrix(&e, &PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 751 | TransposeMatrixCH(&PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 752 | } |
| | 753 | } |
| | 754 | } |
| | 755 | |
| | 756 | void ShowAdjacencies() |
| | 757 | { |
| | 758 | /* Utility function... */ |
| | 759 | printf("Adjacencies FROM Player's Module (%s):\n", (*(PlayerStatus.sbptr->containingModule->m_aimodule->m_module_ptrs))->name); |
| | 760 | |
| | 761 | AIMODULE *thisModule = PlayerStatus.sbptr->containingModule->m_aimodule; |
| | 762 | AIMODULE **AdjModuleRefPtr = thisModule->m_link_ptrs; |
| | 763 | |
| | 764 | if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ |
| | 765 | { |
| | 766 | while(*AdjModuleRefPtr != 0) |
| | 767 | { |
| | 768 | /* Probably want some validity test for the link. */ |
| | 769 | if (AIModuleIsPhysical(*AdjModuleRefPtr)) |
| | 770 | { |
| | 771 | /* Probably a valid link... */ |
| | 772 | if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) |
| | 773 | { |
| | 774 | printf("--AI Module of %s, general.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); |
| | 775 | } |
| | 776 | else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) |
| | 777 | { |
| | 778 | printf("--AI Module of %s, alien only.\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); |
| | 779 | } |
| | 780 | else |
| | 781 | { |
| | 782 | printf("--AI Module of %s, fails validity test!\n",(*((*AdjModuleRefPtr)->m_module_ptrs))->name); |
| | 783 | } |
| | 784 | } |
| | 785 | |
| | 786 | /* next adjacent module reference pointer */ |
| | 787 | AdjModuleRefPtr++; |
| | 788 | } |
| | 789 | } |
| | 790 | |
| | 791 | printf("Adjacencies TO Player's Module:\n"); |
| | 792 | |
| | 793 | AIMODULE *ModuleListPointer = AIModuleArray; |
| | 794 | |
| | 795 | /* go through each aimodule in the environment */ |
| | 796 | int moduleCounter = 0; |
| | 797 | for(; moduleCounter < AIModuleArraySize; moduleCounter++) |
| | 798 | { |
| | 799 | /* get a pointer to the next current module */ |
| | 800 | thisModule = &(ModuleListPointer[moduleCounter]); |
| | 801 | assert(thisModule); |
| | 802 | |
| | 803 | AdjModuleRefPtr = thisModule->m_link_ptrs; |
| | 804 | |
| | 805 | if(AdjModuleRefPtr) /* check that there is a list of adjacent modules */ |
| | 806 | { |
| | 807 | while(*AdjModuleRefPtr != 0) |
| | 808 | { |
| | 809 | /* Probably want some validity test for the link. */ |
| | 810 | if (AIModuleIsPhysical(*AdjModuleRefPtr)) |
| | 811 | { |
| | 812 | /* Is this the target? */ |
| | 813 | if ((*AdjModuleRefPtr) == (PlayerStatus.sbptr->containingModule->m_aimodule)) |
| | 814 | { |
| | 815 | /* Probably a valid link... */ |
| | 816 | if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,0)) |
| | 817 | { |
| | 818 | printf("--AI Module of %s, general.\n",(*(thisModule->m_module_ptrs))->name); |
| | 819 | } |
| | 820 | else if (CheckAdjacencyValidity((*AdjModuleRefPtr),thisModule,1)) |
| | 821 | { |
| | 822 | printf("--AI Module of %s, alien only.\n",(*(thisModule->m_module_ptrs))->name); |
| | 823 | } |
| | 824 | else |
| | 825 | { |
| | 826 | printf("--AI Module of %s, fails validity test!\n",(*(thisModule->m_module_ptrs))->name); |
| | 827 | } |
| | 828 | |
| | 829 | } |
| | 830 | } |
| | 831 | |
| | 832 | /* next adjacent module reference pointer */ |
| | 833 | AdjModuleRefPtr++; |
| | 834 | } |
| | 835 | } |
| | 836 | } |
| | 837 | } |
| | 838 | |
| | 839 | void StartPlayerTaunt() |
| | 840 | { |
| | 841 | if (PlayerStatus.tauntTimer) |
| | 842 | return; |
| | 843 | |
| | 844 | PlayerStatus.tauntTimer = -1; /* Cue to start. */ |
| | 845 | |
| | 846 | if(SinglePlayer == AvP.PlayMode) |
| | 847 | PlayerStatus.tauntTimer = TAUNT_LENGTH; |
| | 848 | |
| | 849 | /* An actual noise, too, would probably be good. */ |
| | 850 | |
| | 851 | /* That should make sure we don't get more than one. */ |
| | 852 | if (PlayerStatus.sound_mouth == SOUND_NOACTIVEINDEX) |
| | 853 | { |
| | 854 | switch(AvP.PlayerType) |
| | 855 | { |
| | 856 | case I_Alien: |
| | 857 | { |
| | 858 | SpeciesSound(0, ASC_Taunt, 0, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, ALIEN_SOUND); |
| | 859 | |
| | 860 | if(SinglePlayer != AvP.PlayMode) |
| | 861 | netGameData.myLastScream = ASC_Taunt; |
| | 862 | } |
| | 863 | break; |
| | 864 | case I_Marine: |
| | 865 | { |
| | 866 | SpeciesSound(0, MSC_Taunt, 0, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, HUMAN_SOUND); |
| | 867 | |
| | 868 | if(SinglePlayer != AvP.PlayMode) |
| | 869 | netGameData.myLastScream = MSC_Taunt; |
| | 870 | } |
| | 871 | break; |
| | 872 | case I_Predator: |
| | 873 | { |
| | 874 | SpeciesSound(0, PSC_Taunt, 0, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND); |
| | 875 | |
| | 876 | if(SinglePlayer != AvP.PlayMode) |
| | 877 | netGameData.myLastScream = PSC_Taunt; |
| | 878 | } |
| | 879 | } |
| | 880 | } |
| | 881 | } |
| | 882 | |
| | 883 | static STRATEGYBLOCK *MakePlayerCorpse(const DEATH_DATA * its_death) |
| | 884 | { |
| | 885 | STRATEGYBLOCK *sbPtr = CreateActiveStrategyBlock(I_BehaviourCorpse); |
| | 886 | |
| | 887 | if(NULL != sbPtr) |
| | 888 | { |
| | 889 | AssignNewSBName(sbPtr); |
| | 890 | |
| | 891 | DYNAMICSBLOCK *dynPtr = sbPtr->DynPtr = AllocateDynamicsBlock(DYNAMICS_TEMPLATE_DEFAULT); |
| | 892 | CORPSEDATABLOCK *corpseData = sbPtr->dataptr = make_new_corpse(I_BehaviourCorpse); |
| | 893 | |
| | 894 | if(!dynPtr || !corpseData) |
| | 895 | { |
| | 896 | RemoveBehaviourStrategy(sbPtr); |
| | 897 | return NULL; |
| | 898 | } |
| | 899 | |
| | 900 | dynPtr->CanClimbStairs = 0; |
| | 901 | dynPtr->IgnoreThePlayer = 1; |
| | 902 | dynPtr->Mass = 100; |
| | 903 | |
| | 904 | dynPtr->Position = dynPtr->PrevPosition = PlayerStatus.sbptr->DynPtr->Position; |
| | 905 | dynPtr->OrientEuler = PlayerStatus.sbptr->DynPtr->OrientEuler; |
| | 906 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 907 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 908 | |
| | 909 | sbPtr->maintainVisibility = 1; |
| | 910 | sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL); |
| | 911 | Splice_HModels(&corpseData->HModelController, PlayerStatus.HModelController.section_data); |
| | 912 | |
| | 913 | corpseData->This_Death = its_death; |
| | 914 | |
| | 915 | switch(AvP.PlayerType) |
| | 916 | { |
| | 917 | case I_Marine: |
| | 918 | { |
| | 919 | corpseData->Type = I_BehaviourMarinePlayer; |
| | 920 | corpseData->hltable = GetThisHitLocationTable("marine with pulse rifle"); |
| | 921 | /* Select hierarchy from character's selected weapon. */ |
| | 922 | //while we're at it , also deal with creating the pickupable weapon |
| | 923 | { |
| | 924 | STRATEGYBLOCK* weaponSbPtr = CreateMultiplayerWeaponPickup(&PlayerStatus.sbptr->DynPtr->Position,
PlayerStatus.SelectedWeapon->WeaponIDNumber, 0); |
| | 925 | |
| | 926 | //hide the newly created weapon from this player , until the player respawns |
| | 927 | |
| | 928 | if(weaponSbPtr) |
| | 929 | { |
| | 930 | weaponSbPtr->maintainVisibility = 0; |
| | 931 | weaponSbPtr->DynPtr->IsPickupObject = 0; |
| | 932 | } |
| | 933 | } |
| | 934 | { |
| | 935 | const SECTION* template_root = GetNamedHierarchyFromLibrary("hnpcmarine", "Template"); |
| | 936 | assert(template_root); |
| | 937 | /* Convert to template. */ |
| | 938 | |
| | 939 | if (its_death->Template) |
| | 940 | Transmogrify_HModels(sbPtr, &corpseData->HModelController, template_root, 0, 0, 0); |
| | 941 | else |
| | 942 | TrimToTemplate(sbPtr, &corpseData->HModelController, template_root, 0); |
| | 943 | } |
| | 944 | } |
| | 945 | break; |
| | 946 | case I_Alien: |
| | 947 | { |
| | 948 | corpseData->Type = I_BehaviourAlienPlayer; |
| | 949 | corpseData->hltable = GetThisHitLocationTable("alien"); |
| | 950 | } |
| | 951 | break; |
| | 952 | case I_Predator: |
| | 953 | { |
| | 954 | corpseData->Type = I_BehaviourPredatorPlayer; |
| | 955 | corpseData->hltable = GetThisHitLocationTable("predator"); |
| | 956 | |
| | 957 | if (its_death->Template) |
| | 958 | { |
| | 959 | const SECTION* template_root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template"); |
| | 960 | assert(template_root); |
| | 961 | /* Convert to template. */ |
| | 962 | Transmogrify_HModels(sbPtr, &corpseData->HModelController, template_root, 1, 0, 0); |
| | 963 | } |
| | 964 | } |
| | 965 | } |
| | 966 | |
| | 967 | /* Now fix timer. */ |
| | 968 | corpseData->timer = CORPSE_EXPIRY_TIME; /* Arbitrarily */ |
| | 969 | corpseData->validityTimer = CORPSE_VALIDITY_TIME; |
| | 970 | corpseData->HModelController.Looped = 0; |
| | 971 | //ProveHModel_Far(&corpseData->HModelController, sbPtr); |
| | 972 | MakeCorpseNear(sbPtr); |
| | 973 | //sbPtr->DisplayBlock->ObFlags |= ObFlag_NotVis; |
| | 974 | |
| | 975 | if (PlayerStatus.sbptr->DamageBlock.IsOnFire) |
| | 976 | { |
| | 977 | sbPtr->DamageBlock.IsOnFire = 1; |
| | 978 | corpseData->SoundHandle3 = PlayerStatus.soundCracklingFire; |
| | 979 | PlayerStatus.soundCracklingFire = SOUND_NOACTIVEINDEX; |
| | 980 | } |
| | 981 | |
| | 982 | if (its_death->Electrical) |
| | 983 | Sound_Play(SID_ELEC_DEATH, "de", &sbPtr->DynPtr->Position, &corpseData->SoundHandle4); |
| | 984 | |
| | 985 | if(its_death->TweeningTime <= 0) |
| | 986 | InitHModelSequence(&corpseData->HModelController, its_death->Sequence_Type, its_death->Sub_Sequence, its_death->Sequence_Length); |
| | 987 | else |
| | 988 | InitHModelTweening(&corpseData->HModelController, its_death->TweeningTime, its_death->Sequence_Type, its_death->Sub_Sequence,
its_death->Sequence_Length, 0); |
| | 989 | |
| | 990 | } |
| | 991 | |
| | 992 | return sbPtr; |
| | 993 | } |
| | 994 | |
| | 995 | static const DEATH_DATA* PlayerMarineDeathSequence(const HMODELCONTROLLER *controller, const DAMAGE_PROFILE* damage, int multiple, VECTORCH* incoming) |
| | 996 | { |
| | 997 | int deathtype = 0,gibbFactor = 0; |
| | 998 | |
| | 999 | /* Set GibbFactor and death type*/ |
| | 1000 | { |
| | 1001 | int tkd = TotalKineticDamage(damage); |
| | 1002 | |
| | 1003 | if (damage->ExplosivePower == 1) |
| | 1004 | { |
| | 1005 | if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1)))>20) |
| | 1006 | { |
| | 1007 | /* Okay, you can gibb now. */ |
| | 1008 | gibbFactor = ONE_FIXED >> 1; |
| | 1009 | deathtype = 2; |
| | 1010 | } |
| | 1011 | } |
| | 1012 | else if ((tkd > 60) && ((multiple>>16) > 1)) |
| | 1013 | { |
| | 1014 | int newmult = DIV_FIXED(multiple,NormalFrameTime); |
| | 1015 | |
| | 1016 | if (MUL_FIXED(tkd,newmult) > 500) |
| | 1017 | { |
| | 1018 | /* Loadsabullets! */ |
| | 1019 | gibbFactor = -(ONE_FIXED >> 2); |
| | 1020 | deathtype = 2; |
| | 1021 | } |
| | 1022 | } |
| | 1023 | |
| | 1024 | if ((damage->ExplosivePower == 2) || (damage->ExplosivePower == 6)) |
| | 1025 | { |
| | 1026 | /* Basically SADARS only. */ |
| | 1027 | gibbFactor = ONE_FIXED; |
| | 1028 | deathtype = 3; |
| | 1029 | } |
| | 1030 | } |
| | 1031 | |
| | 1032 | if (damage->ForceBoom) |
| | 1033 | deathtype += damage->ForceBoom; |
| | 1034 | |
| | 1035 | { |
| | 1036 | SECTION_DATA *chest = GetThisSectionData(controller->section_data,"chest"); |
| | 1037 | |
| | 1038 | if (chest == NULL) |
| | 1039 | { |
| | 1040 | /* I'm impressed. */ |
| | 1041 | deathtype += 2; |
| | 1042 | } |
| | 1043 | else if ((chest->flags & section_data_notreal) && (chest->flags & section_data_terminate_here)) |
| | 1044 | { |
| | 1045 | /* That's gotta hurt. */ |
| | 1046 | deathtype++; |
| | 1047 | } |
| | 1048 | } |
| | 1049 | |
| | 1050 | /* Now final stage. */ |
| | 1051 | { |
| | 1052 | HIT_FACING facing = { 0,0,0,0 }; |
| | 1053 | int burning = 0,electrical = 0; |
| | 1054 | |
| | 1055 | const SECTION *root = GetNamedHierarchyFromLibrary("hnpcmarine","Template"); |
| | 1056 | |
| | 1057 | if (incoming) |
| | 1058 | { |
| | 1059 | if (incoming->vz > 0) |
| | 1060 | facing.Back = 1; |
| | 1061 | else |
| | 1062 | facing.Front = 1; |
| | 1063 | |
| | 1064 | if (incoming->vx > 0) |
| | 1065 | facing.Right = 1; |
| | 1066 | else |
| | 1067 | facing.Left = 1; |
| | 1068 | } |
| | 1069 | |
| | 1070 | if ( !damage->Impact && !damage->Cutting && !damage->Penetrative && !damage->Acid) |
| | 1071 | { |
| | 1072 | if(damage->Electrical) |
| | 1073 | { |
| | 1074 | if (!damage->Fire) |
| | 1075 | electrical = 1; |
| | 1076 | } |
| | 1077 | else if (damage->Fire && PlayerStatus.sbptr->DamageBlock.IsOnFire) |
| | 1078 | { |
| | 1079 | burning = 1; |
| | 1080 | } |
| | 1081 | } |
| | 1082 | |
| | 1083 | return GetDeathSequence(controller, root, 0, 0, deathtype, &facing, burning, PlayerStatus.Crouching, electrical, 1); |
| | 1084 | } |
| | 1085 | } |
| | 1086 | |
| | 1087 | static const DEATH_DATA* PlayerPredatorDeathSequence(const HMODELCONTROLLER *controller, const DAMAGE_PROFILE* damage, int multiple, VECTORCH* incoming) |
| | 1088 | { |
| | 1089 | int deathtype = 0; |
| | 1090 | int tkd = TotalKineticDamage(damage); |
| | 1091 | |
| | 1092 | if (damage->ExplosivePower == 1) |
| | 1093 | { |
| | 1094 | if (MUL_FIXED(tkd,(multiple&((ONE_FIXED<<1)-1))) > 20) |
| | 1095 | { |
| | 1096 | /* Okay, you can... splat now. */ |
| | 1097 | deathtype = 2; |
| | 1098 | } |
| | 1099 | } |
| | 1100 | else if ((tkd < 40) && ((multiple >> 16) > 1)) |
| | 1101 | { |
| | 1102 | int newmult = DIV_FIXED(multiple,NormalFrameTime); |
| | 1103 | |
| | 1104 | if (MUL_FIXED(tkd, newmult) > 500) |
| | 1105 | deathtype = 2; |
| | 1106 | } |
| | 1107 | |
| | 1108 | if ((damage->ExplosivePower == 2) || (damage->ExplosivePower == 6)) |
| | 1109 | { |
| | 1110 | /* Basically SADARS only. */ |
| | 1111 | deathtype = 3; |
| | 1112 | } |
| | 1113 | |
| | 1114 | if (damage->ForceBoom) |
| | 1115 | deathtype += damage->ForceBoom; |
| | 1116 | |
| | 1117 | { |
| | 1118 | SECTION_DATA *chest = GetThisSectionData(controller->section_data, "chest"); |
| | 1119 | |
| | 1120 | if (chest == NULL) |
| | 1121 | { |
| | 1122 | /* I'm impressed. */ |
| | 1123 | deathtype += 2; |
| | 1124 | } |
| | 1125 | else if ((chest->flags & section_data_notreal) && (chest->flags & section_data_terminate_here)) |
| | 1126 | { |
| | 1127 | /* That's gotta hurt. */ |
| | 1128 | deathtype++; |
| | 1129 | } |
| | 1130 | } |
| | 1131 | |
| | 1132 | { |
| | 1133 | HIT_FACING facing = { 0,0,0,0 }; |
| | 1134 | int burning = 0; |
| | 1135 | const SECTION *root = GetNamedHierarchyFromLibrary("hnpcpredator", "Template"); |
| | 1136 | |
| | 1137 | if (incoming) |
| | 1138 | { |
| | 1139 | if (incoming->vz > 0) |
| | 1140 | facing.Back = 1; |
| | 1141 | else |
| | 1142 | facing.Front = 1; |
| | 1143 | |
| | 1144 | if (incoming->vx > 0) |
| | 1145 | facing.Right = 1; |
| | 1146 | else |
| | 1147 | facing.Left = 1; |
| | 1148 | } |
| | 1149 | |
| | 1150 | if (!damage->Impact |
| | 1151 | && !damage->Cutting |
| | 1152 | && !damage->Penetrative |
| | 1153 | && damage->Fire |
| | 1154 | && !damage->Electrical |
| | 1155 | && !damage->Acid) |
| | 1156 | { |
| | 1157 | burning = 1; |
| | 1158 | } |
| | 1159 | |
| | 1160 | return GetDeathSequence(controller, root, 0, 0, deathtype, &facing, burning, PlayerStatus.Crouching, 0, 3); |
| | 1161 | } |
| | 1162 | } |
| | 1163 | |
| | 1164 | static const DEATH_DATA* PlayerAlienDeathSequence(const HMODELCONTROLLER *controller, const DAMAGE_PROFILE* damage, int multiple, VECTORCH* incoming) |
| | 1165 | { |
| | 1166 | /* Get death type. */ |
| | 1167 | int tkd = TotalKineticDamage(damage); |
| | 1168 | int deathtype = 0; |
| | 1169 | |
| | 1170 | if (damage->ExplosivePower == 1) |
| | 1171 | { |
| | 1172 | /* Explosion case. */ |
| | 1173 | if (MUL_FIXED(tkd, (multiple&((ONE_FIXED<<1)-1))) > 20) |
| | 1174 | { |
| | 1175 | /* Okay, you can gibb now. */ |
| | 1176 | deathtype = 2; |
| | 1177 | } |
| | 1178 | } |
| | 1179 | else if ((tkd < 40) && ((multiple >> 16) > 1)) |
| | 1180 | { |
| | 1181 | int temp = MUL_FIXED(tkd, DIV_FIXED(multiple,NormalFrameTime)); |
| | 1182 | |
| | 1183 | if (temp > 700) |
| | 1184 | { |
| | 1185 | /* Excessive bullets case 1. */ |
| | 1186 | deathtype = 2; |
| | 1187 | } |
| | 1188 | else if (temp > 250) |
| | 1189 | { |
| | 1190 | /* Excessive bullets case 2. */ |
| | 1191 | deathtype = 1; |
| | 1192 | } |
| | 1193 | } |
| | 1194 | |
| | 1195 | if ((damage->ExplosivePower == 2) || (damage->ExplosivePower == 6)) |
| | 1196 | deathtype = 3; // Basically SADARS only. |
| | 1197 | |
| | 1198 | if (damage->ForceBoom) |
| | 1199 | deathtype += damage->ForceBoom; |
| | 1200 | |
| | 1201 | { |
| | 1202 | SECTION_DATA *chest=GetThisSectionData(controller->section_data, "chest"); |
| | 1203 | |
| | 1204 | if (chest == NULL) |
| | 1205 | { |
| | 1206 | /* I'm impressed. */ |
| | 1207 | deathtype += 2; |
| | 1208 | } |
| | 1209 | else if ((chest->flags & section_data_notreal) && (chest->flags & section_data_terminate_here)) |
| | 1210 | { |
| | 1211 | /* That's gotta hurt. */ |
| | 1212 | deathtype++; |
| | 1213 | } |
| | 1214 | } |
| | 1215 | |
| | 1216 | { |
| | 1217 | HIT_FACING facing = { 0,0,0,0 }; |
| | 1218 | |
| | 1219 | if (incoming) |
| | 1220 | { |
| | 1221 | if (incoming->vz > 0) |
| | 1222 | facing.Back = 1; |
| | 1223 | else |
| | 1224 | facing.Front = 1; |
| | 1225 | |
| | 1226 | if (incoming->vx > 0) |
| | 1227 | facing.Right = 1; |
| | 1228 | else |
| | 1229 | facing.Left = 1; |
| | 1230 | } |
| | 1231 | |
| | 1232 | return GetDeathSequence(controller, NULL, 0, 0, deathtype, &facing, 0, PlayerStatus.Crouching, 0, 2); |
| | 1233 | } |
| | 1234 | } |
| | 1235 | |
| | 1236 | static void PlayerIsDead(const DAMAGE_PROFILE* damage, int multiplier, VECTORCH* incoming) |
| | 1237 | { |
| | 1238 | PlayerStatus.Alive = 0; |
| | 1239 | PlayerStatus.DisplayBlock->ObFlags &= ~ObFlag_NotVis; |
| | 1240 | PlayerStatus.FirstPersonView = 0; |
| | 1241 | |
| | 1242 | if(weaponHandle != SOUND_NOACTIVEINDEX) |
| | 1243 | Sound_Stop(weaponHandle); |
| | 1244 | |
| | 1245 | if (PlayerStatus.sound_mouth != SOUND_NOACTIVEINDEX) |
| | 1246 | Sound_Stop(PlayerStatus.sound_mouth); |
| | 1247 | |
| | 1248 | switch (AvP.PlayerType) |
| | 1249 | { |
| | 1250 | case I_Alien: |
| | 1251 | PlayerStatus.sbptr->DynPtr->UseStandardGravity = 1; |
| | 1252 | SpeciesSound(0, ASC_Scream_Dying, 0, NULL, &PlayerStatus.sbptr->DynPtr->Position, ALIEN_SOUND); |
| | 1253 | break; |
| | 1254 | case I_Marine: |
| | 1255 | { |
| | 1256 | if (damage->Id == AMMO_FACEHUGGER) |
| | 1257 | SpeciesSound(0, MSC_Facehugged, 0, NULL, &PlayerStatus.sbptr->DynPtr->Position, HUMAN_SOUND); |
| | 1258 | else |
| | 1259 | SpeciesSound(0, MSC_Death, 0, NULL, &PlayerStatus.sbptr->DynPtr->Position, HUMAN_SOUND); |
| | 1260 | } |
| | 1261 | break; |
| | 1262 | case I_Predator: |
| | 1263 | { |
| | 1264 | DisengageGrapplingHook(); |
| | 1265 | |
| | 1266 | if(predHUDSoundHandle != SOUND_NOACTIVEINDEX) |
| | 1267 | Sound_Stop(predHUDSoundHandle); |
| | 1268 | |
| | 1269 | if(predOVision_SoundHandle != SOUND_NOACTIVEINDEX) |
| | 1270 | Sound_Stop(predOVision_SoundHandle); |
| | 1271 | |
| | 1272 | if (damage->Id == AMMO_FACEHUGGER) |
| | 1273 | SpeciesSound(0, PSC_Facehugged, 0, NULL, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND); |
| | 1274 | else |
| | 1275 | SpeciesSound(0, PSC_Scream_Dying, 0, NULL, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND); |
| | 1276 | } |
| | 1277 | } |
| | 1278 | |
| | 1279 | mission_messages = NULL; |
| | 1280 | mission_messages_timer = 0; |
| | 1281 | |
| | 1282 | /* give player a little bounce */ |
| | 1283 | PlayerStatus.sbptr->DynPtr->Elasticity = 16384; |
| | 1284 | /* but a lot of friction */ |
| | 1285 | // PlayerStatus.sbptr->DynPtr->Mass = 1 << 20; |
| | 1286 | |
| | 1287 | deathFadeLevel = ONE_FIXED; |
| | 1288 | |
| | 1289 | const DEATH_DATA * its_death = NULL; |
| | 1290 | |
| | 1291 | switch(AvP.PlayerType) |
| | 1292 | { |
| | 1293 | case I_Marine: |
| | 1294 | its_death = PlayerMarineDeathSequence(&PlayerStatus.HModelController, damage, multiplier, incoming); |
| | 1295 | break; |
| | 1296 | case I_Alien: |
| | 1297 | its_death = PlayerAlienDeathSequence(&PlayerStatus.HModelController, damage, multiplier, incoming); |
| | 1298 | break; |
| | 1299 | case I_Predator: |
| | 1300 | its_death = PlayerPredatorDeathSequence(&PlayerStatus.HModelController, damage, multiplier, incoming); |
| | 1301 | } |
| | 1302 | |
| | 1303 | if(NULL == its_death) |
| | 1304 | { |
| | 1305 | printf("Invalid Null Death\n"); |
| | 1306 | return; |
| | 1307 | } |
| | 1308 | |
| | 1309 | if(SinglePlayer != AvP.PlayMode) |
| | 1310 | { |
| | 1311 | STRATEGYBLOCK *MyCorpse = MakePlayerCorpse(its_death); |
| | 1312 | |
| | 1313 | if(NULL == MyCorpse) |
| | 1314 | return; |
| | 1315 | |
| | 1316 | AddNetMsg_PlayerKilled((*((int *)(&(MyCorpse->SBname[4])))), damage); |
| | 1317 | |
| | 1318 | if (damage->Id == AMMO_ALIEN_BITE_KILLSECTION) |
| | 1319 | Sound_Play(SID_ALIEN_JAW_ATTACK, "d", &PlayerStatus.sbptr->DynPtr->Position); |
| | 1320 | |
| | 1321 | //tell everyone else about the chosen death |
| | 1322 | AddNetMsg_PlayerDeathAnim(its_death->Multiplayer_Code, *(int*)&MyCorpse->SBname[4]); |
| | 1323 | |
| | 1324 | //does this death require a change in character type? |
| | 1325 | if(netGameData.gameType == NGT_LastManStanding) |
| | 1326 | { |
| | 1327 | //Am I a marine or predator? |
| | 1328 | if(AvP.PlayerType != I_Alien) |
| | 1329 | { |
| | 1330 | //was I killed by an alien? |
| | 1331 | if(myNetworkKillerId && myNetworkKillerId != AVPDPNetID) |
| | 1332 | { |
| | 1333 | int killer_index = PlayerIdInPlayerList(myNetworkKillerId); |
| | 1334 | |
| | 1335 | assert(killer_index != NET_IDNOTINPLAYERLIST); |
| | 1336 | |
| | 1337 | if(netGameData.playerData[killer_index].characterType == NGCT_Alien) |
| | 1338 | { |
| | 1339 | //set the next character to be an alien then |
| | 1340 | netGameData.myNextCharacterType = NGCT_Alien; |
| | 1341 | } |
| | 1342 | } |
| | 1343 | else |
| | 1344 | { |
| | 1345 | //suicide , so become an alien anyway |
| | 1346 | netGameData.myNextCharacterType = NGCT_Alien; |
| | 1347 | } |
| | 1348 | } |
| | 1349 | } |
| | 1350 | else if(netGameData.gameType == NGT_PredatorTag || netGameData.gameType == NGT_AlienTag) |
| | 1351 | { |
| | 1352 | //we may need to change character |
| | 1353 | extern void SpeciesTag_DetermineMyNextCharacterType(); |
| | 1354 | SpeciesTag_DetermineMyNextCharacterType(); |
| | 1355 | } |
| | 1356 | } |
| | 1357 | else |
| | 1358 | { |
| | 1359 | if(its_death->TweeningTime <= 0) |
| | 1360 | InitHModelSequence(&PlayerStatus.HModelController, its_death->Sequence_Type, its_death->Sub_Sequence, its_death->Sequence_Length); |
| | 1361 | else |
| | 1362 | InitHModelTweening(&PlayerStatus.HModelController, its_death->TweeningTime, its_death->Sequence_Type, its_death->Sub_Sequence,
its_death->Sequence_Length, 0); |
| | 1363 | |
| | 1364 | switch(damage->Id) |
| | 1365 | { |
| | 1366 | case EXPLOSIONFIRE_BLAST: |
| | 1367 | case AMMO_FRAGMENTATION_GRENADE: |
| | 1368 | { |
| | 1369 | int GibbFactor = (I_Marine == AvP.PlayerType) ? ONE_FIXED >> 1 : ONE_FIXED >> 3; |
| | 1370 | Extreme_Gibbing(PlayerStatus.sbptr, PlayerStatus.HModelController.section_data, GibbFactor, incoming); |
| | 1371 | } |
| | 1372 | break; |
| | 1373 | case AMMO_FLECHETTE: |
| | 1374 | { |
| | 1375 | int GibbFactor = ONE_FIXED >> 4; |
| | 1376 | Extreme_Gibbing(PlayerStatus.sbptr, PlayerStatus.HModelController.section_data, GibbFactor, incoming); |
| | 1377 | } |
| | 1378 | default: |
| | 1379 | break; |
| | 1380 | } |
| | 1381 | |
| | 1382 | SoundSys_FadeOut(); |
| | 1383 | } |
| | 1384 | |
| | 1385 | if (PlayerStatus.soundCracklingFire != SOUND_NOACTIVEINDEX) |
| | 1386 | Sound_Stop(PlayerStatus.soundCracklingFire); |
| | 1387 | } |
| | 1388 | |
| | 1389 | static void ModifyHeadOrientation() |
| | 1390 | { |
| | 1391 | #define TILT_THRESHOLD 128 |
| | 1392 | |
| | 1393 | if (!PlayerStatus.Alive && !MultiplayerObservedPlayer) |
| | 1394 | { |
| | 1395 | int decay = NormalFrameTime >> 6; |
| | 1396 | |
| | 1397 | HeadOrientation.EulerX &= 4095; |
| | 1398 | HeadOrientation.EulerX -= decay; |
| | 1399 | |
| | 1400 | if(HeadOrientation.EulerX < 3072) |
| | 1401 | HeadOrientation.EulerX = 3072; |
| | 1402 | } |
| | 1403 | else |
| | 1404 | { |
| | 1405 | int decay = NormalFrameTime >> 8; |
| | 1406 | |
| | 1407 | if(HeadOrientation.EulerX > 2048) |
| | 1408 | { |
| | 1409 | if (HeadOrientation.EulerX < 4096 - TILT_THRESHOLD) |
| | 1410 | HeadOrientation.EulerX = 4096 - TILT_THRESHOLD; |
| | 1411 | |
| | 1412 | HeadOrientation.EulerX += decay; |
| | 1413 | |
| | 1414 | if(HeadOrientation.EulerX > 4095) |
| | 1415 | HeadOrientation.EulerX = 0; |
| | 1416 | } |
| | 1417 | else |
| | 1418 | { |
| | 1419 | if (HeadOrientation.EulerX > TILT_THRESHOLD) |
| | 1420 | HeadOrientation.EulerX = TILT_THRESHOLD; |
| | 1421 | |
| | 1422 | HeadOrientation.EulerX -= decay; |
| | 1423 | |
| | 1424 | if(HeadOrientation.EulerX < 0) |
| | 1425 | HeadOrientation.EulerX = 0; |
| | 1426 | } |
| | 1427 | |
| | 1428 | if(HeadOrientation.EulerY > 2048) |
| | 1429 | { |
| | 1430 | if (HeadOrientation.EulerY < 4096 - TILT_THRESHOLD) |
| | 1431 | HeadOrientation.EulerY = 4096 - TILT_THRESHOLD; |
| | 1432 | |
| | 1433 | HeadOrientation.EulerY += decay; |
| | 1434 | |
| | 1435 | if(HeadOrientation.EulerY > 4095) |
| | 1436 | HeadOrientation.EulerY = 0; |
| | 1437 | } |
| | 1438 | else |
| | 1439 | { |
| | 1440 | if (HeadOrientation.EulerY > TILT_THRESHOLD) |
| | 1441 | HeadOrientation.EulerY = TILT_THRESHOLD; |
| | 1442 | |
| | 1443 | HeadOrientation.EulerY -= decay; |
| | 1444 | |
| | 1445 | if(HeadOrientation.EulerY < 0) |
| | 1446 | HeadOrientation.EulerY = 0; |
| | 1447 | } |
| | 1448 | |
| | 1449 | if(HeadOrientation.EulerZ > 2048) |
| | 1450 | { |
| | 1451 | if (HeadOrientation.EulerZ < 4096 - TILT_THRESHOLD) |
| | 1452 | HeadOrientation.EulerZ = 4096 - TILT_THRESHOLD; |
| | 1453 | |
| | 1454 | HeadOrientation.EulerZ += decay; |
| | 1455 | |
| | 1456 | if(HeadOrientation.EulerZ > 4095) |
| | 1457 | HeadOrientation.EulerZ = 0; |
| | 1458 | } |
| | 1459 | else |
| | 1460 | { |
| | 1461 | if (HeadOrientation.EulerZ > TILT_THRESHOLD) |
| | 1462 | HeadOrientation.EulerZ = TILT_THRESHOLD; |
| | 1463 | |
| | 1464 | HeadOrientation.EulerZ -= decay; |
| | 1465 | |
| | 1466 | if(HeadOrientation.EulerZ < 0) |
| | 1467 | HeadOrientation.EulerZ = 0; |
| | 1468 | } |
| | 1469 | } |
| | 1470 | } |
| | 1471 | |
| | 1472 | static void InteriorType_Body() |
| | 1473 | { |
| | 1474 | static int verticalSpeed = 0; |
| | 1475 | static int zAxisTilt = 0; |
| | 1476 | |
| | 1477 | { |
| | 1478 | VECTORCH offset = { 0, 0, 0 }; |
| | 1479 | |
| | 1480 | switch(AvP.PlayerType) |
| | 1481 | { |
| | 1482 | case I_Alien: |
| | 1483 | //offset.vy = CollisionExtents[(PlayerStatus.Crouching ? CE_ALIEN_CROUCH : CE_ALIEN)].StandingTop; |
| | 1484 | offset.vy = (PlayerStatus.Crouching ? CollisionExtents[CE_ALIEN].CrouchingTop : CollisionExtents[CE_ALIEN].StandingTop); |
| | 1485 | //offset.vy = CollisionExtents[CE_ALIEN].StandingTop; |
| | 1486 | break; |
| | 1487 | case I_Marine: |
| | 1488 | offset.vy = (PlayerStatus.Crouching ? CollisionExtents[CE_MARINE].CrouchingTop : CollisionExtents[CE_MARINE].StandingTop); |
| | 1489 | break; |
| | 1490 | case I_Predator: |
| | 1491 | offset.vy = (PlayerStatus.Crouching ? CollisionExtents[CE_PREDATOR].CrouchingTop : CollisionExtents[CE_PREDATOR].StandingTop); |
| | 1492 | } |
| | 1493 | |
| | 1494 | if(PlayerStatus.FirstPersonView) |
| | 1495 | { |
| | 1496 | ModifyHeadOrientation(); |
| | 1497 | //if (CHEATMODE_LANDOFTHEGIANTS == UserProfile.active_bonus) offset.vy /= 4; |
| | 1498 | } |
| | 1499 | else |
| | 1500 | { |
| | 1501 | if(1) |
| | 1502 | { |
| | 1503 | offset.vz = -CollisionExtents[AvP.PlayerType].CollisionRadius * 3; |
| | 1504 | offset.vy = PlayerStatus.Crouching ? CollisionExtents[AvP.PlayerType].CrouchingTop : CollisionExtents[AvP.PlayerType].StandingTop; |
| | 1505 | offset.vy -= 1500; |
| | 1506 | } |
| | 1507 | else if(1) |
| | 1508 | { |
| | 1509 | offset.vz = -CollisionExtents[AvP.PlayerType].CollisionRadius; |
| | 1510 | offset.vy = PlayerStatus.Crouching ? CollisionExtents[AvP.PlayerType].CrouchingTop : CollisionExtents[AvP.PlayerType].StandingTop; |
| | 1511 | offset.vy -= 50; |
| | 1512 | } |
| | 1513 | else // first person view with model |
| | 1514 | { |
| | 1515 | offset.vz = CollisionExtents[AvP.PlayerType].CollisionRadius; |
| | 1516 | offset.vy = PlayerStatus.Crouching ? CollisionExtents[AvP.PlayerType].CrouchingTop : CollisionExtents[AvP.PlayerType].StandingTop; |
| | 1517 | offset.vy += 100; |
| | 1518 | } |
| | 1519 | } |
| | 1520 | |
| | 1521 | if (!PlayerStatus.Alive && !MultiplayerObservedPlayer) |
| | 1522 | { |
| | 1523 | offset.vy = MUL_FIXED(deathFadeLevel * 4 - 3 * ONE_FIXED, offset.vy); |
| | 1524 | |
| | 1525 | if (offset.vy > -100) |
| | 1526 | offset.vy = -100; |
| | 1527 | } |
| | 1528 | |
| | 1529 | //offset.vy += verticalSpeed / 16+200; |
| | 1530 | |
| | 1531 | RotateVector(&offset, &PlayerStatus.DisplayBlock->ObMat); |
| | 1532 | Global_VDB.VDB_World.vx += offset.vx; |
| | 1533 | Global_VDB.VDB_World.vy += offset.vy; |
| | 1534 | Global_VDB.VDB_World.vz += offset.vz; |
| | 1535 | } |
| | 1536 | |
| | 1537 | { |
| | 1538 | EULER orientation = HeadOrientation; |
| | 1539 | |
| | 1540 | orientation.EulerZ += zAxisTilt >> 8; |
| | 1541 | orientation.EulerZ &= 4095; |
| | 1542 | |
| | 1543 | if (CHEATMODE_NAUSEA == UserProfile.active_bonus) |
| | 1544 | { |
| | 1545 | orientation.EulerZ = (orientation.EulerZ + GetSin((CloakingPhase/2) & 4095) / 256) & 4095; |
| | 1546 | orientation.EulerX = (orientation.EulerX + GetSin((CloakingPhase/2+500) & 4095) / 512) & 4095; |
| | 1547 | orientation.EulerY = (orientation.EulerY + GetSin((CloakingPhase/3+800) & 4095) / 512) & 4095; |
| | 1548 | } |
| | 1549 | // The next test drops the matrix multiply if the orientation is close to zero |
| | 1550 | // There is an inaccuracy problem with the Z angle at this point |
| | 1551 | |
| | 1552 | if (orientation.EulerX || orientation.EulerY || (orientation.EulerZ > 1 && orientation.EulerZ < 4095)) |
| | 1553 | { |
| | 1554 | MATRIXCH matrix; |
| | 1555 | CreateEulerMatrix(&orientation, &matrix); |
| | 1556 | MatrixMultiply(&Global_VDB.VDB_Mat, &matrix, &Global_VDB.VDB_Mat); |
| | 1557 | } |
| | 1558 | } |
| | 1559 | |
| | 1560 | { |
| | 1561 | VECTORCH relativeVelocity; |
| | 1562 | |
| | 1563 | /* get subject's total velocity */ |
| | 1564 | { |
| | 1565 | DYNAMICSBLOCK *dynPtr = PlayerStatus.sbptr->DynPtr; |
| | 1566 | /* make world to local matrix */ |
| | 1567 | MATRIXCH worldToLocalMatrix = PlayerStatus.DisplayBlock->ObMat; |
| | 1568 | |
| | 1569 | TransposeMatrixCH(&worldToLocalMatrix); |
| | 1570 | |
| | 1571 | relativeVelocity.vx = dynPtr->Position.vx - dynPtr->PrevPosition.vx; |
| | 1572 | relativeVelocity.vy = dynPtr->Position.vy - dynPtr->PrevPosition.vy; |
| | 1573 | relativeVelocity.vz = dynPtr->Position.vz - dynPtr->PrevPosition.vz; |
| | 1574 | /* rotate into object space */ |
| | 1575 | |
| | 1576 | RotateVector(&relativeVelocity, &worldToLocalMatrix); |
| | 1577 | } |
| | 1578 | |
| | 1579 | { |
| | 1580 | int targetingSpeed = 10 * NormalFrameTime; |
| | 1581 | |
| | 1582 | /* KJL 14:08:50 09/20/96 - the targeting is FRI, but care has to be taken |
| | 1583 | at very low frame rates to ensure that you can't overshoot */ |
| | 1584 | if (targetingSpeed > 65536) |
| | 1585 | targetingSpeed = 65536; |
| | 1586 | |
| | 1587 | zAxisTilt += MUL_FIXED ( DIV_FIXED ( MUL_FIXED(relativeVelocity.vx, PlayerStatus.LeanScale), NormalFrameTime )-zAxisTilt, targetingSpeed ); |
| | 1588 | |
| | 1589 | { |
| | 1590 | static int previousVerticalSpeed = 0; |
| | 1591 | int difference = 0; |
| | 1592 | |
| | 1593 | if (relativeVelocity.vy >= 0) |
| | 1594 | difference = DIV_FIXED ( previousVerticalSpeed - relativeVelocity.vy, NormalFrameTime ); |
| | 1595 | |
| | 1596 | if (verticalSpeed < difference) |
| | 1597 | verticalSpeed = difference; |
| | 1598 | |
| | 1599 | if(verticalSpeed > 150*16) |
| | 1600 | verticalSpeed = 150*16; |
| | 1601 | |
| | 1602 | verticalSpeed -= NormalFrameTime>>2; |
| | 1603 | |
| | 1604 | if (verticalSpeed < 0) |
| | 1605 | verticalSpeed = 0; |
| | 1606 | |
| | 1607 | previousVerticalSpeed = relativeVelocity.vy; |
| | 1608 | } |
| | 1609 | } |
| | 1610 | } |
| | 1611 | } |
| | 1612 | |
| | 1613 | void PlayerIsDamaged(const DAMAGE_PROFILE *damage, int multiplier, VECTORCH* incoming) |
| | 1614 | { |
| | 1615 | if (PlayerStatus.Alive) |
| | 1616 | { |
| | 1617 | if (PlayerStatus.sbptr->DamageBlock.Health <= 0) |
| | 1618 | { |
| | 1619 | PlayerIsDead(damage, multiplier, incoming); |
| | 1620 | return; |
| | 1621 | } |
| | 1622 | |
| | 1623 | int deltaHealth = PlayerStatus.Health - PlayerStatus.sbptr->DamageBlock.Health; |
| | 1624 | int deltaArmour = PlayerStatus.Armour - PlayerStatus.sbptr->DamageBlock.Armour; |
| | 1625 | |
| | 1626 | CurrentGameStats_DamageTaken(deltaHealth, deltaArmour); |
| | 1627 | |
| | 1628 | { |
| | 1629 | int maxTilt = deltaHealth >> 12; |
| | 1630 | int halfTilt = maxTilt / 2; |
| | 1631 | |
| | 1632 | if (maxTilt) |
| | 1633 | { |
| | 1634 | HeadOrientation.EulerX = (FastRandom()%maxTilt)-halfTilt; |
| | 1635 | HeadOrientation.EulerY = (FastRandom()%maxTilt)-halfTilt; |
| | 1636 | HeadOrientation.EulerZ = (FastRandom()%maxTilt)-halfTilt; |
| | 1637 | |
| | 1638 | if (HeadOrientation.EulerX < 0) HeadOrientation.EulerX += 4096; |
| | 1639 | if (HeadOrientation.EulerY < 0) HeadOrientation.EulerY += 4096; |
| | 1640 | if (HeadOrientation.EulerZ < 0) HeadOrientation.EulerZ += 4096; |
| | 1641 | } |
| | 1642 | } |
| | 1643 | |
| | 1644 | if ((PlayerStatus.sound_mouth == SOUND_NOACTIVEINDEX) && (deltaHealth || deltaArmour)) |
| | 1645 | { |
| | 1646 | int pitch = (FastRandom() & 255) - 128; |
| | 1647 | |
| | 1648 | switch (AvP.PlayerType) |
| | 1649 | { |
| | 1650 | case I_Alien: |
| | 1651 | { |
| | 1652 | if (!damage->Impact && !damage->Cutting && !damage->Penetrative && damage->Fire &&
!damage->Electrical && !damage->Acid) |
| | 1653 | { |
| | 1654 | SpeciesSound(0, ASC_PC_OnFire, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, ALIEN_SOUND); |
| | 1655 | |
| | 1656 | if(SinglePlayer != AvP.PlayMode) |
| | 1657 | netGameData.myLastScream = ASC_PC_OnFire; |
| | 1658 | } |
| | 1659 | else |
| | 1660 | { |
| | 1661 | SpeciesSound(0, ASC_Scream_Hurt, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, ALIEN_SOUND); |
| | 1662 | |
| | 1663 | if(SinglePlayer != AvP.PlayMode) |
| | 1664 | netGameData.myLastScream = ASC_Scream_Hurt; |
| | 1665 | } |
| | 1666 | } |
| | 1667 | break; |
| | 1668 | case I_Marine: |
| | 1669 | { |
| | 1670 | /* Alert marines, pretty much whoever you are. */ |
| | 1671 | PointAlert(3, &PlayerStatus.sbptr->DynPtr->Position); |
| | 1672 | |
| | 1673 | switch(damage->Id) |
| | 1674 | { |
| | 1675 | case AMMO_FACEHUGGER: |
| | 1676 | SpeciesSound(0, MSC_Facehugged, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, HUMAN_SOUND); |
| | 1677 | break; |
| | 1678 | case AMMO_FALLINGDAMAGE: |
| | 1679 | SpeciesSound(0, MSC_Falling, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, HUMAN_SOUND); |
| | 1680 | break; |
| | 1681 | default: |
| | 1682 | { |
| | 1683 | if( !damage->Impact && !damage->Cutting && !damage->Penetrative && !damage->Electrical) |
| | 1684 | { |
| | 1685 | if (damage->Acid) |
| | 1686 | { |
| | 1687 | if (!damage->Fire) |
| | 1688 | { |
| | 1689 | SpeciesSound(0, MSC_Acid, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position,
HUMAN_SOUND); |
| | 1690 | |
| | 1691 | if(SinglePlayer != AvP.PlayMode) |
| | 1692 | netGameData.myLastScream = MSC_Acid; |
| | 1693 | break; |
| | 1694 | } |
| | 1695 | } |
| | 1696 | else if (damage->Fire) |
| | 1697 | { |
| | 1698 | SpeciesSound(0, MSC_PC_OnFire, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position,
HUMAN_SOUND); |
| | 1699 | |
| | 1700 | if(SinglePlayer != AvP.PlayMode) |
| | 1701 | netGameData.myLastScream = MSC_PC_OnFire; |
| | 1702 | break; |
| | 1703 | } |
| | 1704 | |
| | 1705 | } |
| | 1706 | |
| | 1707 | SpeciesSound(0, MSC_Pain, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, HUMAN_SOUND); |
| | 1708 | |
| | 1709 | if(SinglePlayer != AvP.PlayMode) |
| | 1710 | netGameData.myLastScream = MSC_Pain; |
| | 1711 | } |
| | 1712 | } |
| | 1713 | } |
| | 1714 | break; |
| | 1715 | case I_Predator: |
| | 1716 | { |
| | 1717 | if (damage->Id == AMMO_FACEHUGGER) |
| | 1718 | { |
| | 1719 | SpeciesSound(0, PSC_Facehugged, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND); |
| | 1720 | } |
| | 1721 | else |
| | 1722 | { |
| | 1723 | if (!damage->Impact && !damage->Cutting && !damage->Penetrative && !damage->Electrical) |
| | 1724 | { |
| | 1725 | if (!damage->Fire) |
| | 1726 | { |
| | 1727 | if (damage->Acid) |
| | 1728 | { |
| | 1729 | SpeciesSound(0, PSC_Acid, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position,
PREDATOR_SOUND); |
| | 1730 | |
| | 1731 | if(SinglePlayer != AvP.PlayMode) |
| | 1732 | netGameData.myLastScream = PSC_Acid; |
| | 1733 | break; |
| | 1734 | } |
| | 1735 | } |
| | 1736 | else if (!damage->Acid) |
| | 1737 | { |
| | 1738 | SpeciesSound(0, PSC_PC_OnFire, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position,
PREDATOR_SOUND); |
| | 1739 | |
| | 1740 | if(SinglePlayer != AvP.PlayMode) |
| | 1741 | netGameData.myLastScream = PSC_PC_OnFire; |
| | 1742 | break; |
| | 1743 | } |
| | 1744 | } |
| | 1745 | |
| | 1746 | SpeciesSound(0, PSC_Scream_Hurt, pitch, &PlayerStatus.sound_mouth, &PlayerStatus.sbptr->DynPtr->Position, PREDATOR_SOUND); |
| | 1747 | |
| | 1748 | if(SinglePlayer != AvP.PlayMode) |
| | 1749 | netGameData.myLastScream = PSC_Scream_Hurt; |
| | 1750 | } |
| | 1751 | } |
| | 1752 | default: |
| | 1753 | break; |
| | 1754 | } |
| | 1755 | } |
| | 1756 | |
| | 1757 | { |
| | 1758 | /* Compute scaled deltaHealth... */ |
| | 1759 | int scaled_DeltaHealth = MUL_FIXED(deltaHealth, 100); |
| | 1760 | scaled_DeltaHealth = DIV_FIXED(scaled_DeltaHealth, PlayerStatus.StartingHealth); |
| | 1761 | |
| | 1762 | if (scaled_DeltaHealth > PlayerStatus.DamagedOverlayIntensity) |
| | 1763 | PlayerStatus.DamagedOverlayIntensity = scaled_DeltaHealth; |
| | 1764 | } |
| | 1765 | |
| | 1766 | PlayerStatus.Health = PlayerStatus.sbptr->DamageBlock.Health; |
| | 1767 | PlayerStatus.Armour = PlayerStatus.sbptr->DamageBlock.Armour; |
| | 1768 | } |
| | 1769 | } |
| | 1770 | |
| | 1771 | static void NetPlayerDeadProcessing() |
| | 1772 | { |
| | 1773 | /* call the read input function so that we can still respawn/quit, etc */ |
| | 1774 | |
| | 1775 | /* check for re-spawn */ |
| | 1776 | if(Keyboard_input_operate()) |
| | 1777 | { |
| | 1778 | if(AreThereAnyLivesLeft()) |
| | 1779 | { |
| | 1780 | PlayerStatus.DisplayBlock->ObFlags |= ObFlag_NotVis; |
| | 1781 | |
| | 1782 | //check for change of character |
| | 1783 | if(netGameData.myCharacterType != netGameData.myNextCharacterType) |
| | 1784 | { |
| | 1785 | switch(netGameData.myNextCharacterType) |
| | 1786 | { |
| | 1787 | case NGCT_Marine: |
| | 1788 | ChangeToMarine(); |
| | 1789 | break; |
| | 1790 | case NGCT_Alien: |
| | 1791 | ChangeToAlien(); |
| | 1792 | break; |
| | 1793 | case NGCT_Predator: |
| | 1794 | ChangeToPredator(); |
| | 1795 | break; |
| | 1796 | default: |
| | 1797 | assert("dodgy character type"==0); |
| | 1798 | break; |
| | 1799 | } |
| | 1800 | |
| | 1801 | netGameData.myCharacterType = netGameData.myNextCharacterType; |
| | 1802 | } |
| | 1803 | else |
| | 1804 | { |
| | 1805 | NetPlayerRespawn(); |
| | 1806 | } |
| | 1807 | |
| | 1808 | /* dynamics block stuff... */ |
| | 1809 | { |
| | 1810 | EULER zeroEuler = {0,0,0}; |
| | 1811 | VECTORCH zeroVec = {0,0,0}; |
| | 1812 | DYNAMICSBLOCK *dynPtr = PlayerStatus.sbptr->DynPtr; |
| | 1813 | |
| | 1814 | dynPtr->Position = zeroVec; |
| | 1815 | dynPtr->OrientEuler = zeroEuler; |
| | 1816 | dynPtr->LinVelocity = zeroVec; |
| | 1817 | dynPtr->LinImpulse = zeroVec; |
| | 1818 | |
| | 1819 | CreateEulerMatrix(&dynPtr->OrientEuler, &dynPtr->OrientMat); |
| | 1820 | TransposeMatrixCH(&dynPtr->OrientMat); |
| | 1821 | |
| | 1822 | //Need to get rid of collisions for this frame , so player doesn't pick up |
| | 1823 | //his dropped weapon when he respawns. |
| | 1824 | dynPtr->CollisionReportPtr = 0; |
| | 1825 | } |
| | 1826 | |
| | 1827 | TeleportNetPlayerToAStartingPosition(0); |
| | 1828 | } |
| | 1829 | else |
| | 1830 | { |
| | 1831 | //no lives left , so have to act as an observer |
| | 1832 | GetNextMultiplayerObservedPlayer(); |
| | 1833 | |
| | 1834 | //The player's dropped weapon (if there was one) can now be drawn |
| | 1835 | MakePlayersWeaponPickupVisible(); |
| | 1836 | } |
| | 1837 | } |
| | 1838 | } |
| | 1839 | |
| | 1840 | void PlayerBehaviour() |
| | 1841 | { |
| | 1842 | PlayerStatus.sbptr->containingModule = ModuleFromPosition(&PlayerStatus.DisplayBlock->ObWorld, PlayerStatus.sbptr->containingModule); |
| | 1843 | |
| | 1844 | Global_VDB.VDB_World = PlayerStatus.DisplayBlock->ObWorld; |
| | 1845 | { |
| | 1846 | int cos = GetCos(PlayerStatus.ViewPanX); |
| | 1847 | int sin = GetSin(PlayerStatus.ViewPanX); |
| | 1848 | MATRIXCH mat; |
| | 1849 | |
| | 1850 | mat.mat11 = ONE_FIXED; |
| | 1851 | mat.mat12 = 0; |
| | 1852 | mat.mat13 = 0; |
| | 1853 | mat.mat21 = 0; |
| | 1854 | mat.mat22 = cos; |
| | 1855 | mat.mat23 = -sin; |
| | 1856 | mat.mat31 = 0; |
| | 1857 | mat.mat32 = sin; |
| | 1858 | mat.mat33 = cos; |
| | 1859 | |
| | 1860 | MatrixMultiply(&PlayerStatus.DisplayBlock->ObMat, &mat, &Global_VDB.VDB_Mat); |
| | 1861 | TransposeMatrixCH(&Global_VDB.VDB_Mat); |
| | 1862 | } |
| | 1863 | InteriorType_Body(); |
| | 1864 | MNormalise(&PlayerStatus.sbptr->DynPtr->OrientMat); |
| | 1865 | |
| | 1866 | /* |
| | 1867 | { |
| | 1868 | extern int GlobalFrameCounter; |
| | 1869 | DYNAMICSBLOCK *dynPtr = PlayerStatus.sbptr->DynPtr; |
| | 1870 | printf("player Impulse at %d,%d,%d\n", dynPtr->LinImpulse.vx, dynPtr->LinImpulse.vy, dynPtr->LinImpulse.vz); |
| | 1871 | |
| | 1872 | printf ( |
| | 1873 | "Dynamics Logging: frame %d\nDL: player's Position %d,%d,%d\nDL: player's Displacement %d,%d,%d\nDL: NormalFrameTime %d\n", |
| | 1874 | GlobalFrameCounter, |
| | 1875 | dynPtr->Position.vx, dynPtr->Position.vy, dynPtr->Position.vz, |
| | 1876 | dynPtr->Displacement.vx, dynPtr->Displacement.vy, dynPtr->Displacement.vz, |
| | 1877 | NormalFrameTime); |
| | 1878 | |
| | 1879 | } |
| | 1880 | */ |
| | 1881 | if (PlayerStatus.Alive) |
| | 1882 | { |
| | 1883 | if (PlayerStatus.tauntTimer) |
| | 1884 | { |
| | 1885 | PlayerStatus.tauntTimer -= NormalFrameTime; |
| | 1886 | |
| | 1887 | if (PlayerStatus.tauntTimer < 0) |
| | 1888 | PlayerStatus.tauntTimer = 0; |
| | 1889 | |
| | 1890 | switch(AvP.PlayerType) |
| | 1891 | { |
| | 1892 | case I_Alien: |
| | 1893 | { |
| | 1894 | extern EULER HeadOrientation; |
| | 1895 | int ex = MUL_FIXED( 64, GetSin(((PlayerStatus.tauntTimer >> 6) & wrap360))); |
| | 1896 | int ey = MUL_FIXED(128, GetSin(((PlayerStatus.tauntTimer >> 5) & wrap360))); |
| | 1897 | int ez = MUL_FIXED(-64, GetSin(((PlayerStatus.tauntTimer >> 5) & wrap360))); |
| | 1898 | |
| | 1899 | ex &= wrap360; |
| | 1900 | ey &= wrap360; |
| | 1901 | ez &= wrap360; |
| | 1902 | |
| | 1903 | HeadOrientation.EulerX = ex; |
| | 1904 | HeadOrientation.EulerY = ey; |
| | 1905 | HeadOrientation.EulerZ = ez; |
| | 1906 | } |
| | 1907 | default: |
| | 1908 | break; |
| | 1909 | } |
| | 1910 | } |
| | 1911 | |
| | 1912 | handle_user_input(); |
| | 1913 | PlayerStatus.weapon_func(); |
| | 1914 | |
| | 1915 | if(SinglePlayer != AvP.PlayMode) |
| | 1916 | { |
| | 1917 | if(PlayerStatus.invulnerabilityTimer) |
| | 1918 | { |
| | 1919 | PlayerStatus.sbptr->DamageBlock.IsOnFire = 0; |
| | 1920 | PlayerStatus.invulnerabilityTimer -= NormalFrameTime; |
| | 1921 | |
| | 1922 | if(PlayerStatus.invulnerabilityTimer < 0) |
| | 1923 | PlayerStatus.invulnerabilityTimer = 0; |
| | 1924 | |
| | 1925 | //lose invulnerability if player is firing |
| | 1926 | |
| | 1927 | if(PlayerStatus.InputRequests.Rqst_FirePrimaryWeapon) |
| | 1928 | { |
| | 1929 | if(WEAPON_PRED_MEDICOMP != PlayerStatus.SelectedWeapon->WeaponIDNumber) |
| | 1930 | PlayerStatus.invulnerabilityTimer = 0; |
| | 1931 | } |
| | 1932 | |
| | 1933 | if(PlayerStatus.InputRequests.Rqst_FireSecondaryWeapon) |
| | 1934 | { |
| | 1935 | //not many weapons have an offensive secondary fire |
| | 1936 | |
| | 1937 | switch(PlayerStatus.SelectedWeapon->WeaponIDNumber) |
| | 1938 | { |
| | 1939 | case WEAPON_PULSERIFLE: |
| | 1940 | case WEAPON_CUDGEL: |
| | 1941 | case WEAPON_MARINE_PISTOL: |
| | 1942 | case WEAPON_TWO_PISTOLS: |
| | 1943 | case WEAPON_PRED_WRISTBLADE: |
| | 1944 | case WEAPON_ALIEN_CLAW: |
| | 1945 | PlayerStatus.invulnerabilityTimer = 0; |
| | 1946 | default: |
| | 1947 | break; |
| | 1948 | } |
| | 1949 | } |
| | 1950 | |
| | 1951 | PlayerStatus.sbptr->DamageBlock.Indestructable = PlayerStatus.invulnerabilityTimer; |
| | 1952 | } |
| | 1953 | } |
| | 1954 | else |
| | 1955 | { |
| | 1956 | CurrentGameStats_VisionMode(PlayerStatus.VisionMode); |
| | 1957 | CurrentGameStats_UsingWeapon(PlayerStatus.SelectedWeaponSlot); |
| | 1958 | CurrentGameStats_SpeedSample(Approximate3dMagnitude(&PlayerStatus.sbptr->DynPtr->LinVelocity), NormalFrameTime); |
| | 1959 | } |
| | 1960 | |
| | 1961 | //printf("PlayerLight %d\n", PlayerStatus.CurrentLightAtPlayer); |
| | 1962 | } |
| | 1963 | else |
| | 1964 | { |
| | 1965 | extern int RealFrameTime; |
| | 1966 | |
| | 1967 | if(SinglePlayer == AvP.PlayMode) |
| | 1968 | { |
| | 1969 | if(deathFadeLevel > ONE_FIXED/2) |
| | 1970 | { |
| | 1971 | deathFadeLevel -= RealFrameTime / 4; |
| | 1972 | //FadeDownScreen(deathFadeLevel, 0); |
| | 1973 | } |
| | 1974 | else |
| | 1975 | { |
| | 1976 | extern SCREENDESCRIPTORBLOCK ScreenDescriptorBlock; |
| | 1977 | //deathFadeLevel = 0; |
| | 1978 | RenderStringCentred("Press operate to restart game", ScreenDescriptorBlock.SDB_CentreX, ScreenDescriptorBlock.SDB_Height-20,
0xffffffff); |
| | 1979 | AvP.MainLoopRunning = !(AvP.RestartLevel = Keyboard_input_operate()); |
| | 1980 | } |
| | 1981 | } |
| | 1982 | else |
| | 1983 | { |
| | 1984 | if(deathFadeLevel > 0) |
| | 1985 | { |
| | 1986 | deathFadeLevel -= RealFrameTime / 2; |
| | 1987 | } |
| | 1988 | else |
| | 1989 | { |
| | 1990 | deathFadeLevel = 0; |
| | 1991 | NetPlayerDeadProcessing(); |
| | 1992 | } |
| | 1993 | } |
| | 1994 | } |
| | 1995 | } |
| | 1996 | |
| | 1997 | /*---------------------------** |
| | 1998 | ** Loading and saving player ** |
| | 1999 | **---------------------------*/ |
| | 2000 | |
| | 2001 | typedef struct player_save_block |
| | 2002 | { |
| | 2003 | SAVE_BLOCK_STRATEGY_HEADER header; |
| | 2004 | |
| | 2005 | //behaviour block things |
| | 2006 | struct PLAYER_WEAPON_DATA WeaponSlot[MAX_NO_OF_WEAPON_SLOTS]; |
| | 2007 | struct PLAYER_WEAPON_DATA *SelectedWeapon; |
| | 2008 | |
| | 2009 | enum WEAPON_SLOT SelectedWeaponSlot; |
| | 2010 | enum WEAPON_SLOT SwapToWeaponSlot; |
| | 2011 | enum WEAPON_SLOT PreviouslySelectedWeaponSlot; |
| | 2012 | enum WEAPON_STATE WeaponState; |
| | 2013 | enum VISION_MODE_ID VisionMode; |
| | 2014 | |
| | 2015 | VECTORCH WeaponPositionOffset; |
| | 2016 | int WeaponStateTimeOutCounter; |
| | 2017 | |
| | 2018 | int Health; /* in 16.16 */ |
| | 2019 | int Armour; /* in 16.16 */ |
| | 2020 | |
| | 2021 | unsigned int Crouching; |
| | 2022 | |
| | 2023 | signed int ForwardInertia; |
| | 2024 | signed int StrafeInertia; |
| | 2025 | signed int TurnInertia; |
| | 2026 | |
| | 2027 | int ViewPanX; /* the looking up/down value that used to be in displayblock */ |
| | 2028 | |
| | 2029 | unsigned int securityClearances; |
| | 2030 | unsigned int IHaveAPlacedAutogun :1; |
| | 2031 | unsigned int JetpackEnabled :1; |
| | 2032 | unsigned int GrapplingHookEnabled :1; |
| | 2033 | unsigned int cloakOn :1; |
| | 2034 | unsigned int muzzle_flash:1; |
| | 2035 | unsigned int FirstPersonView:1; |
| | 2036 | |
| | 2037 | int FieldCharge; |
| | 2038 | int PlasmaCasterCharge; |
| | 2039 | int imageintensifier_battery; |
| | 2040 | int FlaresLeft; |
| | 2041 | int CloakingEffectiveness; |
| | 2042 | int SmartGunMode; |
| | 2043 | int tauntTimer; |
| | 2044 | int incidentFlag; |
| | 2045 | int incidentTimer; |
| | 2046 | |
| | 2047 | //some stuff for the weapon displayblock |
| | 2048 | VECTORCH Weapon_World; |
| | 2049 | EULER Weapon_Euler; |
| | 2050 | MATRIXCH Weapon_Matrix; |
| | 2051 | |
| | 2052 | //and globals |
| | 2053 | GRENADE_LAUNCHER_DATA GrenadeLauncherData; |
| | 2054 | |
| | 2055 | //strategy block stuff |
| | 2056 | DYNAMICSBLOCK dynamics; |
| | 2057 | DAMAGEBLOCK DamageBlock; |
| | 2058 | |
| | 2059 | } PLAYER_SAVE_BLOCK; |
| | 2060 | |
| | 2061 | //defines for load/save macros |
| | 2062 | #define SAVELOAD_BLOCK block |
| | 2063 | #define SAVELOAD_BEHAV playerStatusPtr |
| | 2064 | |
| | 2065 | void SaveStrategy_Player(STRATEGYBLOCK* sbPtr) |
| | 2066 | { |
| | 2067 | PLAYER_SAVE_BLOCK* block; |
| | 2068 | int i; |
| | 2069 | PLAYER_STATUS *playerStatusPtr = &PlayerStatus; |
| | 2070 | |
| | 2071 | GET_STRATEGY_SAVE_BLOCK(block, sbPtr); |
| | 2072 | |
| | 2073 | COPYELEMENT_SAVE(SelectedWeaponSlot) |
| | 2074 | COPYELEMENT_SAVE(SwapToWeaponSlot) |
| | 2075 | COPYELEMENT_SAVE(PreviouslySelectedWeaponSlot) |
| | 2076 | COPYELEMENT_SAVE(WeaponState) |
| | 2077 | COPYELEMENT_SAVE(VisionMode) |
| | 2078 | COPYELEMENT_SAVE(WeaponPositionOffset) |
| | 2079 | COPYELEMENT_SAVE(WeaponStateTimeOutCounter) |
| | 2080 | COPYELEMENT_SAVE(Health) /* in 16.16 */ |
| | 2081 | COPYELEMENT_SAVE(Armour) /* in 16.16 */ |
| | 2082 | COPYELEMENT_SAVE(Crouching) |
| | 2083 | COPYELEMENT_SAVE(ForwardInertia) |
| | 2084 | COPYELEMENT_SAVE(StrafeInertia) |
| | 2085 | COPYELEMENT_SAVE(TurnInertia) |
| | 2086 | COPYELEMENT_SAVE(ViewPanX) /* the looking up/down value that used to be in displayblock */ |
| | 2087 | COPYELEMENT_SAVE(securityClearances) |
| | 2088 | COPYELEMENT_SAVE(IHaveAPlacedAutogun) |
| | 2089 | COPYELEMENT_SAVE(JetpackEnabled) |
| | 2090 | COPYELEMENT_SAVE(GrapplingHookEnabled ) |
| | 2091 | COPYELEMENT_SAVE(cloakOn) |
| | 2092 | COPYELEMENT_SAVE(muzzle_flash) |
| | 2093 | COPYELEMENT_SAVE(FirstPersonView) |
| | 2094 | COPYELEMENT_SAVE(FieldCharge) |
| | 2095 | COPYELEMENT_SAVE(PlasmaCasterCharge) |
| | 2096 | COPYELEMENT_SAVE(imageintensifier_battery) |
| | 2097 | COPYELEMENT_SAVE(FlaresLeft) |
| | 2098 | COPYELEMENT_SAVE(CloakingEffectiveness) |
| | 2099 | COPYELEMENT_SAVE(SmartGunMode) |
| | 2100 | COPYELEMENT_SAVE(tauntTimer) |
| | 2101 | COPYELEMENT_SAVE(incidentFlag) |
| | 2102 | COPYELEMENT_SAVE(incidentTimer) |
| | 2103 | |
| | 2104 | for(i=0; i < MAX_NO_OF_WEAPON_SLOTS; i++) |
| | 2105 | { |
| | 2106 | block->WeaponSlot[i].WeaponIDNumber = PlayerStatus.WeaponSlot[i].WeaponIDNumber; |
| | 2107 | block->WeaponSlot[i].PrimaryRoundsRemaining = PlayerStatus.WeaponSlot[i].PrimaryRoundsRemaining; |
| | 2108 | block->WeaponSlot[i].SecondaryRoundsRemaining = PlayerStatus.WeaponSlot[i].SecondaryRoundsRemaining; |
| | 2109 | block->WeaponSlot[i].MagazinesRemaining = PlayerStatus.WeaponSlot[i].MagazinesRemaining; |
| | 2110 | block->WeaponSlot[i].Possessed = PlayerStatus.WeaponSlot[i].Possessed; |
| | 2111 | } |
| | 2112 | |
| | 2113 | //some stuff for the weapon displayblock |
| | 2114 | block->Weapon_World = PlayerStatus.weapon.ObWorld; |
| | 2115 | block->Weapon_Euler = PlayerStatus.weapon.ObEuler; |
| | 2116 | block->Weapon_Matrix = PlayerStatus.weapon.ObMat; |
| | 2117 | |
| | 2118 | //global |
| | 2119 | block->GrenadeLauncherData = GrenadeLauncherData; |
| | 2120 | |
| | 2121 | //strategy block stuff |
| | 2122 | block->DamageBlock = sbPtr->DamageBlock; |
| | 2123 | block->dynamics = *sbPtr->DynPtr; |
| | 2124 | block->dynamics.CollisionReportPtr = NULL; |
| | 2125 | |
| | 2126 | //save the weapon hierarchy |
| | 2127 | SaveHierarchy(&PlayersWeaponHModelController); |
| | 2128 | |
| | 2129 | Save_SoundState(&PlayerStatus.sound_mouth); |
| | 2130 | Save_SoundState(&PlayerStatus.soundCracklingFire); |
| | 2131 | Save_SoundState(&PlayerStatus.sound_jetpack); |
| | 2132 | } |
| | 2133 | |
| | 2134 | void LoadStrategy_Player(SAVE_BLOCK_STRATEGY_HEADER* header) |
| | 2135 | { |
| | 2136 | PLAYER_SAVE_BLOCK* block = (PLAYER_SAVE_BLOCK*) header; |
| | 2137 | STRATEGYBLOCK* sbPtr = PlayerStatus.sbptr; |
| | 2138 | int i; |
| | 2139 | |
| | 2140 | if(block->header.size != sizeof(*block)) |
| | 2141 | return; |
| | 2142 | |
| | 2143 | COPY_NAME(sbPtr->SBname, header->SBname); |
| | 2144 | |
| | 2145 | PlayerStatus.SelectedWeaponSlot = block->SelectedWeaponSlot; |
| | 2146 | PlayerStatus.SwapToWeaponSlot = block->SwapToWeaponSlot; |
| | 2147 | PlayerStatus.PreviouslySelectedWeaponSlot = block->PreviouslySelectedWeaponSlot; |
| | 2148 | PlayerStatus.WeaponState = block->WeaponState; |
| | 2149 | PlayerStatus.VisionMode = block->VisionMode; |
| | 2150 | PlayerStatus.WeaponPositionOffset = block->WeaponPositionOffset; |
| | 2151 | PlayerStatus.WeaponStateTimeOutCounter = block->WeaponStateTimeOutCounter; |
| | 2152 | PlayerStatus.Health = block->Health; |
| | 2153 | PlayerStatus.Armour = block->Armour; |
| | 2154 | PlayerStatus.Crouching = block->Crouching; |
| | 2155 | PlayerStatus.ForwardInertia = block->ForwardInertia; |
| | 2156 | PlayerStatus.StrafeInertia = block->StrafeInertia; |
| | 2157 | PlayerStatus.TurnInertia = block->TurnInertia; |
| | 2158 | PlayerStatus.ViewPanX = block->ViewPanX; |
| | 2159 | PlayerStatus.securityClearances = block->securityClearances; |
| | 2160 | PlayerStatus.IHaveAPlacedAutogun = block->IHaveAPlacedAutogun; |
| | 2161 | PlayerStatus.JetpackEnabled = block->JetpackEnabled; |
| | 2162 | PlayerStatus.GrapplingHookEnabled = block->GrapplingHookEnabled; |
| | 2163 | PlayerStatus.cloakOn = block->cloakOn; |
| | 2164 | PlayerStatus.muzzle_flash = block->muzzle_flash; |
| | 2165 | PlayerStatus.FirstPersonView = block->FirstPersonView; |
| | 2166 | PlayerStatus.FieldCharge = block->FieldCharge; |
| | 2167 | PlayerStatus.PlasmaCasterCharge = block->PlasmaCasterCharge; |
| | 2168 | PlayerStatus.imageintensifier_battery = block->imageintensifier_battery; |
| | 2169 | PlayerStatus.FlaresLeft = block->FlaresLeft; |
| | 2170 | PlayerStatus.CloakingEffectiveness = block->CloakingEffectiveness; |
| | 2171 | PlayerStatus.SmartGunMode = block->SmartGunMode; |
| | 2172 | PlayerStatus.tauntTimer = block->tauntTimer; |
| | 2173 | PlayerStatus.incidentFlag = block->incidentFlag; |
| | 2174 | PlayerStatus.incidentTimer = block->incidentTimer; |
| | 2175 | |
| | 2176 | for(i=0; i < MAX_NO_OF_WEAPON_SLOTS; i++) |
| | 2177 | { |
| | 2178 | PlayerStatus.WeaponSlot[i].WeaponIDNumber = block->WeaponSlot[i].WeaponIDNumber; |
| | 2179 | PlayerStatus.WeaponSlot[i].PrimaryRoundsRemaining = block->WeaponSlot[i].PrimaryRoundsRemaining; |
| | 2180 | PlayerStatus.WeaponSlot[i].SecondaryRoundsRemaining = block->WeaponSlot[i].SecondaryRoundsRemaining; |
| | 2181 | PlayerStatus.WeaponSlot[i].MagazinesRemaining = block->WeaponSlot[i].MagazinesRemaining; |
| | 2182 | PlayerStatus.WeaponSlot[i].Possessed = block->WeaponSlot[i].Possessed; |
| | 2183 | } |
| | 2184 | |
| | 2185 | PlayerStatus.SelectedWeapon = &PlayerStatus.WeaponSlot[PlayerStatus.SelectedWeaponSlot]; |
| | 2186 | |
| | 2187 | //some stuff for the weapon displayblock |
| | 2188 | PlayerStatus.weapon.ObWorld = block->Weapon_World; |
| | 2189 | PlayerStatus.weapon.ObEuler = block->Weapon_Euler; |
| | 2190 | PlayerStatus.weapon.ObMat = block->Weapon_Matrix; |
| | 2191 | |
| | 2192 | //global |
| | 2193 | GrenadeLauncherData = block->GrenadeLauncherData; |
| | 2194 | |
| | 2195 | //strategy block stuff |
| | 2196 | *sbPtr->DynPtr = block->dynamics; |
| | 2197 | sbPtr->DamageBlock = block->DamageBlock; |
| | 2198 | sbPtr->containingModule = ModuleFromPosition(&sbPtr->DynPtr->Position, NULL); |
| | 2199 | Global_VDB.VDB_World = sbPtr->DynPtr->Position; |
| | 2200 | |
| | 2201 | //load the weapon hierarchy |
| | 2202 | { |
| | 2203 | SAVE_BLOCK_HEADER* hier_header = GetNextBlockIfOfType(SaveBlock_Hierarchy); |
| | 2204 | |
| | 2205 | if(hier_header) |
| | 2206 | LoadHierarchy(hier_header, &PlayersWeaponHModelController); |
| | 2207 | else |
| | 2208 | Dispel_HModel(&PlayersWeaponHModelController); |
| | 2209 | } |
| | 2210 | |
| | 2211 | GrabWeaponShape(); // alien needs this |
| | 2212 | |
| | 2213 | Load_SoundState(&PlayerStatus.sound_mouth); |
| | 2214 | Load_SoundState(&PlayerStatus.soundCracklingFire); |
| | 2215 | Load_SoundState(&PlayerStatus.sound_jetpack); |
| | 2216 | } |