├── README.md ├── base ├── CBaseActor.inc └── CBaseActorZombie.inc ├── gamedata └── tf2.pets.txt ├── npc_bird.sp ├── npc_bogeyman.sp ├── npc_clot.sp ├── npc_congaline.sp ├── npc_delorean.sp ├── npc_gorefast.sp ├── npc_heavyweapons.sp ├── npc_infected.sp ├── npc_playerclone.sp ├── npc_sentrybuster.sp ├── npc_soccer.sp ├── npc_weeper.sp └── tfpets.sp /README.md: -------------------------------------------------------------------------------- 1 | # TF2_NextBot 2 | TF2 NextBot stuff using base_boss 3 | 4 | https://forums.alliedmods.net/showthread.php?t=297113 5 | 6 | ## Requires 7 | https://github.com/Pelipoika/PathFollower 8 | -------------------------------------------------------------------------------- /gamedata/tf2.pets.txt: -------------------------------------------------------------------------------- 1 | "Games" 2 | { 3 | /* Team Fortress 2 */ 4 | "tf" 5 | { 6 | "Addresses" 7 | { 8 | "GetAnimationEvent" 9 | { 10 | "windows" 11 | { 12 | "signature" "GetAnimationEvent_" 13 | } 14 | } 15 | 16 | "MannVsMachineUpgrades" 17 | { 18 | "windows" 19 | { 20 | "signature" "CTFGameRules::SetCustomUpgradesFile" 21 | "read" "42" 22 | } 23 | } 24 | 25 | //Used for getting TheNavAreas AND navarea_count 26 | "navarea_count" 27 | { 28 | "windows" 29 | { 30 | "signature" "nav_update_lighting" 31 | "read" "78" 32 | } 33 | "linux" 34 | { 35 | "signature" "nav_update_lighting" 36 | "read" "49" //Not sure 37 | } 38 | } 39 | } 40 | "Signatures" 41 | { 42 | "nav_update_lighting" //nav_update_lighting(CCommand const&) | STR "Computed lighting for %d/%d areas\n" 43 | { 44 | "windows" "\x55\x8B\xEC\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\x8B\x45\x08\x57" 45 | "linux" "@_ZL19nav_update_lightingRK8CCommand" 46 | } 47 | 48 | "GetAnimationEvent_" 49 | { 50 | "library" "server" 51 | "windows" "\x55\x8B\xEC\x53\x56\x8B\x75\x08\x85\xF6\x0F\x84\x2A\x2A\x2A\x2A" 52 | } 53 | 54 | "CBasePlayer::SnapEyeAngles" 55 | { 56 | "windows" "\x55\x8B\xEC\x8B\x45\x08\xD9\x00\xD9\x99\x58\x0A\x00\x00" 57 | "linux" "@_ZN11CBasePlayer13SnapEyeAnglesERK6QAngle" 58 | } 59 | 60 | "CBaseAnimating::ResetSequence" //(int nSequence) "ResetSequence : %s: %s -> %s\n" 61 | { 62 | "windows" "\x55\x8B\xEC\xA1\x2A\x2A\x2A\x2A\x53\x56\x57\x83\x78\x30\x00\x8B\xD9\x8B\x7D\x08" 63 | "linux" "@_ZN14CBaseAnimating13ResetSequenceEi" 64 | } 65 | "CBaseAnimating::ResetSequenceInfo" //( ) 66 | { 67 | "windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\x83\xBE\xAC\x03\x00\x00\xFF" 68 | "linux" "@_ZN14CBaseAnimating17ResetSequenceInfoEv" 69 | } 70 | "CBaseAnimating::SetPoseParameter" //( CStudioHdr *pStudioHdr, int iParameter, float flValue ) 71 | { 72 | "windows" "\x55\x8B\xEC\x8B\x45\x08\xD9\x45\x10" 73 | "linux" "@_ZN14CBaseAnimating16SetPoseParameterEP10CStudioHdrif" 74 | } 75 | "CBaseAnimating::LookupPoseParameter" //( CStudioHdr *pStudioHdr, const char *szName ) 76 | { 77 | "windows" "\x55\x8B\xEC\x57\x8B\x7D\x08\x85\xFF\x75\x2A\x33\xC0\x5F\x5D\xC2\x08\x00" 78 | "linux" "@_ZN14CBaseAnimating19LookupPoseParameterEP10CStudioHdrPKc" 79 | } 80 | "CBaseAnimating::GetPoseParameter" //( int iParameter ) "aim_pitch" 2nd in xrefs 81 | { 82 | "windows" "\x55\x8B\xEC\x56\x8B\xF1\x57\x80\xBE\x41\x03\x00\x00\x00\x75\x2A\x83\xBE\x6C\x04\x00\x00\x00\x75\x2A\xE8\x2A\x2A\x2A\x2A\x85\xC0\x74\x2A\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x8B\xBE\x6C\x04\x00\x00" 83 | "linux" "@_ZN14CBaseAnimating16GetPoseParameterEi" 84 | } 85 | "CBaseAnimating::GetIntervalMovement" //( float flIntervalUsed, bool &bMoveSeqFinished, Vector &newPosition, QAngle &newAngles ) 86 | { 87 | "windows" "\x55\x8B\xEC\x83\xEC\x18\x56\x8B\xF1\x57\x80\xBE\x41\x03\x00\x00\x00" 88 | "linux" "@_ZN14CBaseAnimating19GetIntervalMovementEfRbR6VectorR6QAngle" 89 | } 90 | "CBaseAnimating::GetSequenceActivity" 91 | { 92 | "windows" "\x55\x8B\xEC\x83\x7D\x08\xFF\x56\x8B\xF1\x74\x2A" 93 | "linux" "@_ZN14CBaseAnimating19GetSequenceActivityEi" 94 | } 95 | "LookupSequence" //int ( CStudioHdr *pstudiohdr, const char *label ) "spew_bars_context" NOTE: NOT CBaseAnimating::LookupSequence 96 | { 97 | "windows" "\x55\x8B\xEC\x56\x8B\x75\x08\x85\xF6\x75\x2A\x33\xC0\x5E\x5D\xC3\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\x53" 98 | "linux" "@_Z14LookupSequenceP10CStudioHdrPKc" 99 | } 100 | "LookupActivity" //int ( CStudioHdr *pstudiohdr, const char *label ) "spew_bars_context" NOTE: NOT CBaseAnimating::LookupActivity 101 | { 102 | "windows" "\x55\x8B\xEC\x57\x8B\x7D\x08\x85\xFF\x75\x2A\x33\xC0\x5F\x5D\xC3\x53" 103 | "linux" "@_Z14LookupActivityP10CStudioHdrPKc" 104 | } 105 | "CTFPlayer::GetMaxAmmo" //int (int AmmoType, int idk) "mult_maxammo_primary" 106 | { 107 | "windows" "\x55\x8B\xEC\x8B\x45\x0C\x56\x57\x8B\xF9\x83\xF8\xFF" 108 | "linux" "@_ZN9CTFPlayer10GetMaxAmmoEii" 109 | } 110 | "Studio_FindAttachment" //int ( const CStudioHdr *pStudioHdr, const char *pAttachmentName ) <- "alt-origin" 111 | { 112 | "windows" "\x55\x8B\xEC\x53\x56\x57\x8B\x7D\x08\x85\xFF" 113 | "linux" "@_Z21Studio_FindAttachmentPK10CStudioHdrPKc" 114 | } 115 | "CBaseAnimating::GetAttachment" //bool ( int iAttachment, Vector &absOrigin, QAngle &absAngles ) <- "alt-origin" 116 | { 117 | "windows" "\x55\x8B\xEC\x8B\x01\x8D\x55\xD0\x83\xEC\x30\x8B\x80\x44\x03\x00\x00\x53\x52\xFF\x75\x08\xFF\xD0\xFF\x75\x10" 118 | "linux" "@_ZN14CBaseAnimating13GetAttachmentEPKcR6VectorR6QAngle" 119 | } 120 | "CBaseAnimating::FindBodygroupByName" //CBaseAnimating::FindBodygroupByName(this, "mini_sentry_light"); 121 | { 122 | "windows" "\x55\x8B\xEC\x56\x8B\xF1\x80\xBE\x41\x03\x00\x00\x00\x74\x2A\x83\xC8\xFF" 123 | "linux" "@_ZN14CBaseAnimating19FindBodygroupByNameEPKc" 124 | } 125 | "CBaseAnimating::SetBodygroup" //Right below ^ 126 | { 127 | "windows" "\x55\x8B\xEC\x51\x56\x8B\xF1\x57\x80\xBE\x41\x03\x00\x00\x00\x8B\x86\x74\x03\x00\x00" 128 | "linux" "@_ZN14CBaseAnimating12SetBodygroupEii" 129 | } 130 | "CBaseAnimatingOverlay::AddGestureSequence" //( int sequence, bool autokill ) 131 | { 132 | "windows" "\x55\x8B\xEC\x56\x6A\x00\xFF\x75\x08\x8B\xF1\xE8\x2A\x2A\x2A\x2A\x85\xC0\x78\x2A" 133 | "linux" "@_ZN21CBaseAnimatingOverlay18AddGestureSequenceEib" 134 | } 135 | 136 | "CBaseAnimatingOverlay::AddGesture" //int AddGesture( Activity activity, bool autokill = true ); | STR: "CBaseAnimatingOverlay::AddGesture: model %s missing activ" 137 | { 138 | "windows" "\x55\x8B\xEC\x53\x8B\x5D\x08\x57\x53\x8B\xF9\xE8\x2A\x2A\x2A\x2A\x8B\xCF" 139 | "linux" "@_ZN21CBaseAnimatingOverlay10AddGestureE8Activityb" 140 | } 141 | "CBaseAnimatingOverlay::IsPlayingGesture" //bool IsPlayingGesture( Activity activity ); | Found above "spell_skeleton_goop_green" 142 | { 143 | "windows" "\x55\x8B\xEC\xFF\x75\x08\xE8\x2A\x2A\x2A\x2A\x83\xF8\xFF" 144 | "linux" "@_ZN21CBaseAnimatingOverlay16IsPlayingGestureE8Activity" 145 | } 146 | 147 | "CBaseEntity::GetNextThink" //( const char *szContext ) <- "group_respawn_context" 148 | { 149 | "windows" "\x55\x8B\xEC\x8B\x45\x08\x56\x8B\xF1\x85\xC0\x75\x2A\x8B\x86\xD0\x00\x00\x00\x89\x45\x08" 150 | "linux" "@_ZN11CBaseEntity12GetNextThinkEPKc" 151 | } 152 | 153 | "SelectWeightedSequence" 154 | { 155 | "windows" "\x55\x8B\xEC\x56\x8B\x75\x08\x85\xF6\x75\x2A\x33\xC0\x5E\x5D\xC3\x8B\xCE\xE8\x2A\x2A\x2A\x2A\x84\xC0\x74\x2A\x8B\xCE" 156 | "linux" "@_Z22SelectWeightedSequenceP10CStudioHdrii" 157 | } 158 | "GetItemSchema" //() 159 | { 160 | "windows" "\xE8\x2A\x2A\x2A\x2A\x83\xC0\x04\xC3" 161 | "linux" "@_Z15GEconItemSchemav" 162 | } 163 | "CEconItemSchema::GetAttributeDefinitionByName" //const char*, returns CEconItemAttributeDefinition 164 | { 165 | "windows" "\x55\x8B\xEC\x83\xEC\x14\x53\x8B\x5D\x08\x56\x57\x8B\xF9\x85\xDB\x75\x2A\x33\xC0" 166 | "linux" "@_ZN15CEconItemSchema28GetAttributeDefinitionByNameEPKc" 167 | } 168 | 169 | //CTFGameRules 170 | "CTFGameRules::CanUpgradeWithAttrib" //CTFPlayer *, int, ushort, CMannVsMachineUpgrades * 171 | { 172 | "windows" "\x55\x8B\xEC\x83\xEC\x14\x53\x8B\x5D\x08\x85\xDB\x75\x2A" 173 | "linux" "@_ZN12CTFGameRules20CanUpgradeWithAttribEP9CTFPlayeritP22CMannVsMachineUpgrades" 174 | } 175 | "CTFGameRules::GetCostForUpgrade" //(CMannVsMachineUpgrades *upgrade, int slot, int pclass, CTFPlayer *player) 176 | { 177 | "windows" "\x55\x8B\xEC\x57\x8B\x7D\x08\x85\xFF\x75\x2A\x33\xC0\x5F\x5D\xC2\x10\x00" 178 | "linux" "@_ZN12CTFGameRules17GetCostForUpgradeEP22CMannVsMachineUpgradesiiP9CTFPlayer" 179 | } 180 | "CTFGameRules::GetUpgradeTier" //int 181 | { 182 | "windows" "\x55\x8B\xEC\x80\xB9\x66\x09\x00\x00\x00\x74\x2A\x8B\x45\x08" 183 | "linux" "@_ZN12CTFGameRules14GetUpgradeTierEi" 184 | } 185 | "CTFGameRules::IsUpgradeTierEnabled" //CTFPlayer *, int, int) 186 | { 187 | "windows" "\x55\x8B\xEC\x81\xEC\xB4\x01\x00\x00\x83\x7D\x08\x00" 188 | "linux" "@_ZN12CTFGameRules20IsUpgradeTierEnabledEP9CTFPlayerii" 189 | } 190 | 191 | //Get g_MannVsMachineUpgrades pointer 192 | "CTFGameRules::SetCustomUpgradesFile" //<- "upgrades_file_changed" 193 | { 194 | "library" "server" 195 | "windows" "\x55\x8B\xEC\x56\x57\x8B\xF9\x8B\x4D\x08\x83\xC1\x08\x83\x79\x10\x02\x75\x2A\x8B\x01\xBE\x2A\x2A\x2A\x2A\x85\xC0\x0F\x45\xF0\xEB\x2A\xE8\x2A\x2A\x2A\x2A\x8B\xF0\x56" 196 | } 197 | "g_MannVsMachineUpgrades" // g_MannVsMachineUpgrades 198 | { 199 | "library" "server" 200 | "linux" "@g_MannVsMachineUpgrades" 201 | } 202 | 203 | //Inside "CTFBaseBoss::Event_Killed" found with string "item_currencypack_custom" 204 | "NextBotCombatCharacter::Event_Killed" //(NextBotCombatCharacter *this, const CTakeDamageInfo *a2) 205 | { 206 | "windows" "\x55\x8B\xEC\x53\x8B\x5D\x08\x56\x8B\xF1\x8B\x4B\x28" 207 | "linux" "@_ZN22NextBotCombatCharacter12Event_KilledERK15CTakeDamageInfo" 208 | } 209 | 210 | // STR: "BaseCombatCharacter.StopWeaponSounds", "KilledNPC", "item_healthvial" 211 | "CBaseCombatCharacter::Event_Killed" //(CBaseCombatCharacter *this, const CTakeDamageInfo *a2) 212 | { 213 | "windows" "\x55\x8B\xEC\x83\xEC\x20\x53\x56\x8B\xF1\xC6\x45\xFF\x01" 214 | } 215 | 216 | } 217 | "Offsets" 218 | { 219 | "m_bResolveCollisions" //2492 220 | { 221 | "windows" "28" 222 | "linux" "24" 223 | } 224 | 225 | "CTFPlayer::GetAmmoCount" //(int) 226 | { 227 | "windows" "259" 228 | "linux" "260" 229 | } 230 | 231 | "CTFWeaponBaseGun::GetWeaponID" //(int) 232 | { 233 | "windows" "373" 234 | "linux" "379" 235 | } 236 | "CTFWeaponBaseGun::HasAmmo" //() 237 | { 238 | "windows" "233" 239 | "linux" "239" 240 | } 241 | 242 | "CTFWeaponBaseGun::GetProjectileSpeed" //(float) 243 | { 244 | "windows" "474" 245 | "linux" "481" 246 | } 247 | "CTFWeaponBaseGun::GetProjectileGravity" //(float) 248 | { 249 | "windows" "475" 250 | "linux" "482" 251 | } 252 | 253 | "CTFBaseBoss::GetCurrencyValue" 254 | { 255 | "windows" "329" //Windows always +1 off 256 | "linux" "335" 257 | } 258 | 259 | "CBaseEntity::WorldSpaceCenter" 260 | { 261 | "windows" "149" 262 | "linux" "150" 263 | } 264 | "CBaseEntity::GetSmoothedVelocity" 265 | { 266 | "windows" "139" 267 | "linux" "140" 268 | } 269 | "CBaseEntity::MyNextBotPointer" 270 | { 271 | "windows" "72" 272 | "linux" "73" 273 | } 274 | "CBaseEntity::GetVectors" 275 | { 276 | "windows" "136" 277 | "linux" "137" 278 | } 279 | 280 | "CBaseAnimating::StudioFrameAdvance" 281 | { 282 | "windows" "194" 283 | "linux" "195" 284 | } 285 | "CBaseAnimating::DispatchAnimEvents" 286 | { 287 | "windows" "206" 288 | "linux" "207" 289 | } 290 | "CBaseAnimating::HandleAnimEvent" //(animevent_t*) 291 | { 292 | "windows" "207" 293 | "linux" "208" 294 | } 295 | "INextBotEventResponder::OnContact" //(CBaseEntity*, CGameTrace*) 296 | { 297 | "windows" "5" 298 | "linux" "6" 299 | } 300 | "INextBot::GetLocomotionInterface" 301 | { 302 | "windows" "48" 303 | "linux" "49" 304 | } 305 | "INextBot::GetBodyInterface" 306 | { 307 | "windows" "49" 308 | "linux" "50" 309 | } 310 | "INextBot::GetIntentionInterface" 311 | { 312 | "windows" "50" 313 | "linux" "51" 314 | } 315 | "INextBot::GetVisionInterface" 316 | { 317 | "windows" "51" 318 | "linux" "52" 319 | } 320 | "INextBot::Upkeep" 321 | { 322 | "windows" "44" 323 | "linux" "45" 324 | } 325 | 326 | "INextBotComponent::GetBot" 327 | { 328 | "windows" "45" 329 | "linux" "46" 330 | } 331 | "INextBotComponent::GetEntity" 332 | { 333 | "windows" "46" 334 | "linux" "47" 335 | } 336 | 337 | "ILocomotion::Approach" 338 | { 339 | "windows" "46" 340 | "linux" "47" 341 | } 342 | "ILocomotion::DriveTo" 343 | { 344 | "windows" "47" 345 | "linux" "48" 346 | } 347 | "ILocomotion::Run" 348 | { 349 | "windows" "55" 350 | "linux" "56" 351 | } 352 | "ILocomotion::IsRunning" 353 | { 354 | "windows" "58" 355 | "linux" "59" 356 | } 357 | "ILocomotion::GetDesiredSpeed" 358 | { 359 | "windows" "60" 360 | "linux" "61" 361 | } 362 | "ILocomotion::FaceTowards" 363 | { 364 | "windows" "73" 365 | "linux" "74" 366 | } 367 | "ILocomotion::IsAttemptingToMove" 368 | { 369 | "windows" "98" 370 | "linux" "99" 371 | } 372 | "ILocomotion::StuckMonitor" 373 | { 374 | "windows" "101" 375 | "linux" "102" 376 | } 377 | "ILocomotion::ShouldCollideWith" 378 | { 379 | "windows" "99" 380 | "linux" "100" 381 | } 382 | "ILocomotion::GetVelocity" 383 | { 384 | "windows" "86" 385 | "linux" "87" 386 | } 387 | "ILocomotion::GetMotionVector" 388 | { 389 | "windows" "88" 390 | "linux" "89" 391 | } 392 | "ILocomotion::GetGravity" 393 | { 394 | "windows" "105" 395 | "linux" "106" 396 | } 397 | "ILocomotion::GetGroundNormal" 398 | { 399 | "windows" "65" 400 | "linux" "66" 401 | } 402 | "ILocomotion::Jump" 403 | { 404 | "windows" "50" 405 | "linux" "51" 406 | } 407 | "ILocomotion::IsClimbingUpToLedge" 408 | { 409 | "windows" "52" 410 | "linux" "53" 411 | } 412 | "ILocomotion::GetMaxYawRate" 413 | { 414 | "windows" "108" 415 | "linux" "109" 416 | } 417 | "ILocomotion::GetFrictionForward" 418 | { 419 | "windows" "106" 420 | "linux" "107" 421 | } 422 | "ILocomotion::GetFrictionSideways" 423 | { 424 | "windows" "107" 425 | "linux" "108" 426 | } 427 | "ILocomotion::IsOnGround" 428 | { 429 | "windows" "63" 430 | "linux" "64" 431 | } 432 | "ILocomotion::IsStuck" 433 | { 434 | "windows" "95" 435 | "linux" "96" 436 | } 437 | "ILocomotion::StuckMonitor" 438 | { 439 | "windows" "101" 440 | "linux" "102" 441 | } 442 | "ILocomotion::ClearStuckStatus" 443 | { 444 | "windows" "97" 445 | "linux" "98" 446 | } 447 | "ILocomotion::SetVelocity" 448 | { 449 | "windows" "104" 450 | "linux" "105" 451 | } 452 | "ILocomotion::GetMaxDeceleration" 453 | { 454 | "windows" "85" 455 | "linux" "86" 456 | } 457 | "ILocomotion::ClimbUpToLedge" //(Vector const&, Vector const&, CBaseEntity const*) 458 | { 459 | "windows" "48" 460 | "linux" "49" 461 | } 462 | "ILocomotion::JumpAcrossGap" //(Vector const&, Vector const&) 463 | { 464 | "windows" "49" 465 | "linux" "50" 466 | } 467 | "ILocomotion::IsGap" //(Vector const&, Vector const&) 468 | { 469 | "windows" "93" 470 | "linux" "94" 471 | } 472 | "ILocomotion::GetRunSpeed" 473 | { 474 | "windows" "82" 475 | "linux" "83" 476 | } 477 | "ILocomotion::GetStepHeight" 478 | { 479 | "windows" "79" 480 | "linux" "80" 481 | } 482 | "ILocomotion::GetGroundSpeed" 483 | { 484 | "windows" "66" 485 | "linux" "67" 486 | } 487 | "ILocomotion::GetGroundMotionVector" 488 | { 489 | "windows" "67" 490 | "linux" "68" 491 | } 492 | "ILocomotion::GetMaxAcceleration" 493 | { 494 | "windows" "84" 495 | "linux" "85" 496 | } 497 | 498 | "INextBotEventResponder::OnAnimationActivityComplete" 499 | { 500 | "windows" "11" 501 | "linux" "12" 502 | } 503 | 504 | "IVision::GetPrimaryKnownThreat" 505 | { 506 | "windows" "48" 507 | "linux" "49" 508 | } 509 | "IVision::AddKnownEntity"//(CBaseEntity*) 510 | { 511 | "windows" "54" 512 | "linux" "55" 513 | } 514 | "IVision::GetKnown"//(CBaseEntity const*) 515 | { 516 | "windows" "53" 517 | "linux" "54" 518 | } 519 | 520 | "CKnownEntity::GetEntity" 521 | { 522 | "windows" "3" 523 | "linux" "4" 524 | } 525 | "CKnownEntity::UpdatePosition" 526 | { 527 | "windows" "2" 528 | "linux" "3" 529 | } 530 | "CKnownEntity::UpdateVisibilityStatus" 531 | { 532 | "windows" "10" 533 | "linux" "11" 534 | } 535 | 536 | "IBody::GetSolidMask" 537 | { 538 | "windows" "80" 539 | "linux" "81" 540 | } 541 | "IBody::StartActivity" 542 | { 543 | "windows" "58" 544 | "linux" "59" 545 | } 546 | "IBody::GetHullWidth" 547 | { 548 | "windows" "74" 549 | "linux" "75" 550 | } 551 | "IBody::GetHullHeight" 552 | { 553 | "windows" "75" 554 | "linux" "76" 555 | } 556 | "IBody::GetStandHullHeight" 557 | { 558 | "windows" "76" 559 | "linux" "77" 560 | } 561 | "IBody::GetCrouchHullHeight" 562 | { 563 | "windows" "77" 564 | "linux" "78" 565 | } 566 | "IBody::GetHullMins" 567 | { 568 | "windows" "78" 569 | "linux" "79" 570 | } 571 | "IBody::GetHullMaxs" 572 | { 573 | "windows" "79" 574 | "linux" "80" 575 | } 576 | "IBody::GetActivity" 577 | { 578 | "windows" "60" 579 | "linux" "61" 580 | } 581 | "IBody::IsActivity" 582 | { 583 | "windows" "61" 584 | "linux" "62" 585 | } 586 | "IBody::HasActivityType" 587 | { 588 | "windows" "62" 589 | "linux" "63" 590 | } 591 | "IBody::SetDesiredPosture" //(IBody::PostureType) 592 | { 593 | "windows" "63" 594 | "linux" "64" 595 | } 596 | "IBody::GetDesiredPosture" 597 | { 598 | "windows" "64" 599 | "linux" "65" 600 | } 601 | "IBody::IsDesiredPosture" //(IBody::PostureType) 602 | { 603 | "windows" "65" 604 | "linux" "66" 605 | } 606 | "IBody::IsInDesiredPosture" 607 | { 608 | "windows" "66" 609 | "linux" "67" 610 | } 611 | "IBody::GetActualPosture" 612 | { 613 | "windows" "67" 614 | "linux" "68" 615 | } 616 | "IBody::IsActualPosture" //(IBody::PostureType) 617 | { 618 | "windows" "68" 619 | "linux" "69" 620 | } 621 | "IBody::IsPostureMobile" 622 | { 623 | "windows" "69" 624 | "linux" "70" 625 | } 626 | 627 | "CBaseCombatCharacter::ShouldGib" 628 | { 629 | "windows" "290" 630 | "linux" "291" 631 | } 632 | "CBaseCombatCharacter::GetTimeSinceLastInjury" //(int team) 633 | { 634 | "windows" "283" 635 | "linux" "284" 636 | } 637 | "CTFBaseBoss::Event_Killed" //(CTakeDamageInfo const&) 638 | { 639 | "windows" "66" 640 | "linux" "67" 641 | } 642 | } 643 | } 644 | } -------------------------------------------------------------------------------- /npc_bird.sp: -------------------------------------------------------------------------------- 1 | #define GAME_TF2 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #pragma newdecls required 11 | 12 | #define MODEL_CROW "models/crow.mdl" 13 | #define MODEL_PIGEON "models/pigeon.mdl" 14 | 15 | #define int(%1) view_as(%1) 16 | 17 | //SDKCalls 18 | Handle g_hGetSmoothedVelocity; 19 | Handle g_hStudioFrameAdvance; 20 | Handle g_hDispatchAnimEvents; 21 | Handle g_hMyNextBotPointer; 22 | Handle g_hGetLocomotionInterface; 23 | Handle g_hRun; 24 | Handle g_hApproach; 25 | Handle g_hFaceTowards; 26 | Handle g_hResetSequence; 27 | Handle g_hLookupSequence; 28 | Handle g_hStuckMonitor; 29 | Handle g_hSetVelocity; 30 | Handle g_hIsOnGround; 31 | 32 | //DHooks 33 | Handle g_hGetStepHeight; 34 | Handle g_hGetGravity; 35 | Handle g_hGetGroundNormal; 36 | Handle g_hShouldCollideWith; 37 | 38 | public Plugin myinfo = 39 | { 40 | name = "[TF2] NPC Testing", 41 | author = "Pelipoika", 42 | description = "", 43 | version = "1.0", 44 | url = "http://www.sourcemod.net/plugins.php?author=Pelipoika&search=1" 45 | }; 46 | 47 | public void OnPluginStart() 48 | { 49 | RegAdminCmd("sm_bird", Command_FastZombie, ADMFLAG_ROOT); 50 | 51 | Handle hConf = LoadGameConfigFile("tf2.siryouarehunted"); 52 | 53 | StartPrepSDKCall(SDKCall_Entity); 54 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::StudioFrameAdvance"); 55 | if ((g_hStudioFrameAdvance = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::StudioFrameAdvance offset!"); 56 | 57 | StartPrepSDKCall(SDKCall_Entity); 58 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::DispatchAnimEvents"); 59 | PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); 60 | if ((g_hDispatchAnimEvents = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::DispatchAnimEvents offset!"); 61 | 62 | StartPrepSDKCall(SDKCall_Entity); 63 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::ResetSequence"); 64 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 65 | if ((g_hResetSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::ResetSequence signature!"); 66 | 67 | StartPrepSDKCall(SDKCall_Entity); 68 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::LookupSequence"); 69 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); 70 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 71 | if ((g_hLookupSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::LookupSequence signature!"); 72 | 73 | StartPrepSDKCall(SDKCall_Entity); 74 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::GetSmoothedVelocity"); 75 | PrepSDKCall_SetReturnInfo(SDKType_Vector, SDKPass_ByValue); 76 | if((g_hGetSmoothedVelocity = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for CBaseEntity::GetSmoothedVelocity!"); 77 | 78 | StartPrepSDKCall(SDKCall_Entity); 79 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::MyNextBotPointer"); 80 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 81 | if ((g_hMyNextBotPointer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseEntity::MyNextBotPointer offset!"); 82 | 83 | StartPrepSDKCall(SDKCall_Raw); 84 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetLocomotionInterface"); 85 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 86 | if((g_hGetLocomotionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetLocomotionInterface!"); 87 | 88 | StartPrepSDKCall(SDKCall_Raw); 89 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Run"); 90 | if((g_hRun = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Run!"); 91 | 92 | StartPrepSDKCall(SDKCall_Raw); 93 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::StuckMonitor"); 94 | if((g_hStuckMonitor = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::StuckMonitor!"); 95 | 96 | StartPrepSDKCall(SDKCall_Raw); 97 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Approach"); 98 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 99 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 100 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 101 | if((g_hApproach = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Approach!"); 102 | 103 | StartPrepSDKCall(SDKCall_Raw); 104 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::FaceTowards"); 105 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 106 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 107 | if((g_hFaceTowards = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::FaceTowards!"); 108 | 109 | StartPrepSDKCall(SDKCall_Raw); 110 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "NextBotGroundLocomotion::SetVelocity"); 111 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 112 | if((g_hSetVelocity = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for NextBotGroundLocomotion::SetVelocity!"); 113 | 114 | StartPrepSDKCall(SDKCall_Raw); 115 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "NextBotGroundLocomotion::IsOnGround"); 116 | PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain); 117 | if((g_hIsOnGround = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for NextBotGroundLocomotion::IsOnGround!"); 118 | 119 | int iOffset = GameConfGetOffset(hConf, "CTFBaseBossLocomotion::GetStepHeight"); 120 | if(iOffset == -1) SetFailState("Failed to get offset of CTFBaseBossLocomotion::GetStepHeight"); 121 | g_hGetStepHeight = DHookCreate(iOffset, HookType_Raw, ReturnType_Float, ThisPointer_Address, NextBotGroundLocomotion_GetStepHeight); 122 | 123 | iOffset = GameConfGetOffset(hConf, "NextBotGroundLocomotion::GetGravity"); 124 | if(iOffset == -1) SetFailState("Failed to get offset of NextBotGroundLocomotion::GetGravity"); 125 | g_hGetGravity = DHookCreate(iOffset, HookType_Raw, ReturnType_Float, ThisPointer_Address, NextBotGroundLocomotion_GetGravity); 126 | 127 | iOffset = GameConfGetOffset(hConf, "NextBotGroundLocomotion::GetGroundNormal"); 128 | if(iOffset == -1) SetFailState("Failed to get offset of NextBotGroundLocomotion::GetGroundNormal"); 129 | g_hGetGroundNormal = DHookCreate(iOffset, HookType_Raw, ReturnType_VectorPtr, ThisPointer_Address, NextBotGroundLocomotion_GetGroundNormal); 130 | 131 | iOffset = GameConfGetOffset(hConf, "ILocomotion::ShouldCollideWith"); 132 | if(iOffset == -1) SetFailState("Failed to get offset of ILocomotion::ShouldCollideWith"); 133 | g_hShouldCollideWith = DHookCreate(iOffset, HookType_Raw, ReturnType_Bool, ThisPointer_Address, NextBotGroundLocomotion_ShouldCollideWith); 134 | DHookAddParam(g_hShouldCollideWith, HookParamType_CBaseEntity); 135 | 136 | delete hConf; 137 | } 138 | 139 | public void OnMapStart() 140 | { 141 | PrecacheModel(MODEL_CROW); 142 | PrecacheModel(MODEL_PIGEON); 143 | } 144 | 145 | enum NPCState 146 | { 147 | ERROR = 0, 148 | IDLE = 1, 149 | ROAM = 2, 150 | SEARCH = 3 151 | } 152 | 153 | methodmap Bird 154 | { 155 | public Bird(float vecPos[3], float vecAng[3]) 156 | { 157 | CBaseEntity zombie = CBaseEntity.CreateByName("base_boss"); 158 | zombie.KeyValueVector("origin", vecPos); 159 | zombie.KeyValueVector("angles", vecAng); 160 | 161 | switch(GetRandomInt(1, 2)) 162 | { 163 | case 1: zombie.KeyValue("model", MODEL_CROW); 164 | case 2: zombie.KeyValue("model", MODEL_PIGEON); 165 | } 166 | 167 | zombie.KeyValue("modelscale", "2"); 168 | zombie.KeyValue("health", "100000"); 169 | zombie.Spawn(); 170 | 171 | zombie.SetPropFloat(Prop_Send, "m_flPlaybackRate", 1.0); 172 | 173 | char strName[64]; 174 | Format(strName, sizeof(strName), "npc_%x", zombie.Ref); 175 | 176 | Dynamic brain = Dynamic(); 177 | brain.SetName(strName); 178 | brain.SetInt("State", int(IDLE)); 179 | brain.SetInt("Target", -1); 180 | 181 | return view_as(zombie.Index); 182 | } 183 | 184 | public Dynamic GetBrainInterface() 185 | { 186 | char strName[64]; 187 | Format(strName, sizeof(strName), "npc_%x", EntIndexToEntRef(int(this))); 188 | 189 | return Dynamic.FindByName(strName); 190 | } 191 | 192 | property NPCState State 193 | { 194 | public get() 195 | { 196 | Dynamic brain = this.GetBrainInterface(); 197 | if(brain.IsValid) 198 | { 199 | return view_as(brain.GetInt("State")); 200 | } 201 | 202 | return ERROR; 203 | } 204 | public set(NPCState state) 205 | { 206 | Dynamic brain = this.GetBrainInterface(); 207 | if(brain.IsValid) 208 | { 209 | brain.SetInt("State", int(state)); 210 | } 211 | } 212 | } 213 | 214 | public void Approach(float x, float y, float z) 215 | { 216 | Address pNB = SDKCall(g_hMyNextBotPointer, this); 217 | Address pLocomotion = SDKCall(g_hGetLocomotionInterface, pNB); 218 | 219 | float flGoal[3]; 220 | flGoal[0] = x; 221 | flGoal[1] = y; 222 | flGoal[2] = z; 223 | 224 | SDKCall(g_hStuckMonitor, pLocomotion); 225 | SDKCall(g_hRun, pLocomotion); 226 | SDKCall(g_hApproach, pLocomotion, flGoal, 1.0, 666); 227 | 228 | if(pLocomotion != Address_Null) 229 | { 230 | bool bOnGround = SDKCall(g_hIsOnGround, pLocomotion); 231 | if(bOnGround) 232 | { 233 | SDKCall(g_hFaceTowards, pLocomotion, flGoal, 666); 234 | } 235 | } 236 | } 237 | 238 | public void Update() 239 | { 240 | Dynamic brain = this.GetBrainInterface(); 241 | 242 | if(brain.IsValid) 243 | { 244 | int iCurrentTarget = brain.GetInt("Target"); 245 | 246 | int iTarget = FindNearestEnemy(int(this)); 247 | if(iTarget > 0) 248 | { 249 | if(PF_Exists(int(this)) && iTarget != iCurrentTarget) 250 | { 251 | brain.SetInt("Target", iTarget); 252 | PF_SetGoalEntity(int(this), iTarget); 253 | } 254 | 255 | float flZPos[3]; 256 | GetEntPropVector(int(this), Prop_Data, "m_vecOrigin", flZPos); 257 | float flCPos[3]; 258 | GetClientAbsOrigin(iTarget, flCPos); 259 | 260 | float flDistance = GetVectorDistance(flZPos, flCPos); 261 | 262 | int iSequence = -1; 263 | 264 | Address pNB = SDKCall(g_hMyNextBotPointer, int(this)); 265 | Address pLocomotion = SDKCall(g_hGetLocomotionInterface, pNB); 266 | bool bOnGround 267 | 268 | if(pLocomotion != Address_Null) 269 | { 270 | bOnGround = SDKCall(g_hIsOnGround, pLocomotion); 271 | if(bOnGround) 272 | { 273 | if (flDistance <= 100.0) 274 | { 275 | iSequence = SDKCall(g_hLookupSequence, this, "Idle01"); 276 | 277 | PF_StopPathing(int(this)); 278 | } 279 | else if(flDistance <= 300) 280 | { 281 | PF_StartPathing(int(this)); 282 | 283 | iSequence = SDKCall(g_hLookupSequence, this, "Walk"); 284 | 285 | SetEntDataFloat(int(this), FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 8, 35.0, true); 286 | } 287 | else 288 | { 289 | PF_StartPathing(int(this)); 290 | 291 | iSequence = SDKCall(g_hLookupSequence, this, "Run"); 292 | 293 | SetEntDataFloat(int(this), FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 8, 150.0, true); 294 | } 295 | } 296 | else 297 | { 298 | iSequence = SDKCall(g_hLookupSequence, this, "Fly01"); 299 | } 300 | } 301 | 302 | if(iSequence != -1) 303 | SDKCall(g_hResetSequence, this, iSequence); 304 | } 305 | } 306 | } 307 | } 308 | 309 | public void BirdThink(int iEntity) 310 | { 311 | CBaseEntity CBird = new CBaseEntity(iEntity); 312 | 313 | Bird bird = view_as(iEntity); 314 | 315 | SDKCall(g_hStudioFrameAdvance, CBird); 316 | SDKCall(g_hDispatchAnimEvents, CBird, CBird); 317 | 318 | CBird.SetProp(Prop_Data, "m_bSequenceLoops", true); 319 | 320 | if(CBird.GetPropFloat(Prop_Send, "m_flCycle") < 0.0) 321 | CBird.SetPropFloat(Prop_Send, "m_flCycle", 1.0); 322 | 323 | if(CBird.GetPropFloat(Prop_Send, "m_flCycle") >= 1.0) 324 | CBird.SetPropFloat(Prop_Send, "m_flCycle", 0.0); 325 | 326 | bird.Update(); 327 | } 328 | 329 | public Action Command_FastZombie(int client, int args) 330 | { 331 | CBasePlayer player = new CBasePlayer(client); 332 | 333 | float vecPos[3], vecAng[3]; 334 | GetAimPos(client, vecPos); 335 | player.GetEyeAngles(vecAng); 336 | 337 | int zombie = int(Bird(vecPos, vecAng)); 338 | 339 | SetEntityFlags(zombie, FL_NOTARGET); 340 | 341 | PF_Create(zombie, 18.0, 1.0, 10000.0, MASK_NPCSOLID, 1000.0, 0.50); 342 | PF_SetGoalEntity(zombie, client); 343 | PF_StartPathing(zombie); 344 | 345 | Address pNB = SDKCall(g_hMyNextBotPointer, zombie); 346 | Address pLocomotion = SDKCall(g_hGetLocomotionInterface, pNB); 347 | if(pLocomotion != Address_Null) 348 | { 349 | DHookRaw(g_hGetStepHeight, true, pLocomotion); 350 | DHookRaw(g_hGetGravity, true, pLocomotion); 351 | DHookRaw(g_hGetGroundNormal, true, pLocomotion); 352 | DHookRaw(g_hShouldCollideWith, true, pLocomotion); 353 | } 354 | 355 | SDKHook(zombie, SDKHook_Think, BirdThink); 356 | 357 | // CreateTimer(2.0, velocity, zombie); 358 | 359 | return Plugin_Handled; 360 | } 361 | 362 | public Action velocity(Handle timer, int entity) 363 | { 364 | Address pNB = SDKCall(g_hMyNextBotPointer, entity); 365 | Address pLocomotion = SDKCall(g_hGetLocomotionInterface, pNB); 366 | 367 | float flPos[3]; 368 | GetEntPropVector(entity, Prop_Send, "m_vecOrigin", flPos); 369 | 370 | flPos[2] += 10.0; 371 | 372 | TeleportEntity(entity, flPos, NULL_VECTOR, NULL_VECTOR); 373 | 374 | float flVelocity[3]; 375 | SDKCall(g_hGetSmoothedVelocity, entity, flVelocity); 376 | 377 | PrintToChatAll("%f %f %f", flVelocity[0], flVelocity[1], flVelocity[2]); 378 | 379 | flVelocity[2] = 100.0; 380 | 381 | SDKCall(g_hSetVelocity, pLocomotion, flVelocity); 382 | } 383 | 384 | public void PF_Approach(int entity, float x, float y, float z) 385 | { 386 | if(entity > MaxClients && entity <= 2048) 387 | { 388 | Bird zombie = view_as(entity); 389 | Dynamic brain = zombie.GetBrainInterface(); 390 | 391 | if(brain.IsValid) 392 | { 393 | zombie.Approach(x, y, z); 394 | } 395 | } 396 | } 397 | 398 | public void OnEntityDestroyed(int entity) 399 | { 400 | if(entity > MaxClients && entity <= 2048) 401 | { 402 | Bird zombie = view_as(entity); 403 | Dynamic brain = zombie.GetBrainInterface(); 404 | 405 | if(brain.IsValid) 406 | { 407 | brain.Dispose(); 408 | } 409 | } 410 | } 411 | 412 | public MRESReturn NextBotGroundLocomotion_GetStepHeight(Address pThis, Handle hReturn, Handle hParams) 413 | { 414 | DHookSetReturn(hReturn, 18.0); 415 | 416 | return MRES_Supercede; 417 | } 418 | 419 | public MRESReturn NextBotGroundLocomotion_GetGravity(Address pThis, Handle hReturn, Handle hParams) 420 | { 421 | DHookSetReturn(hReturn, 50.0); 422 | 423 | return MRES_Supercede; 424 | } 425 | 426 | public MRESReturn NextBotGroundLocomotion_GetGroundNormal(Address pThis, Handle hReturn, Handle hParams) 427 | { 428 | DHookSetReturnVector(hReturn, view_as( { 0.0, 0.0, 1.0 } )); 429 | 430 | return MRES_Supercede; 431 | } 432 | 433 | public MRESReturn NextBotGroundLocomotion_ShouldCollideWith(Address pThis, Handle hReturn, Handle hParams) 434 | { 435 | int iEntity = DHookGetParam(hParams, 1); 436 | if (IsValidEntity(iEntity)) 437 | { 438 | char strClass[32]; 439 | GetEdictClassname(iEntity, strClass, sizeof(strClass)); 440 | if(StrEqual(strClass, "base_boss")) 441 | { 442 | DHookSetReturn(hReturn, false); 443 | return MRES_Supercede; 444 | } 445 | } 446 | 447 | return MRES_Ignored; 448 | } 449 | 450 | stock bool GetAimPos(int client, float vecPos[3]) 451 | { 452 | float StartOrigin[3], Angles[3]; 453 | GetClientEyeAngles(client, Angles); 454 | GetClientEyePosition(client, StartOrigin); 455 | 456 | Handle TraceRay = TR_TraceRayFilterEx(StartOrigin, Angles, MASK_VISIBLE_AND_NPCS, RayType_Infinite, ExcludeFilter, client); 457 | if (TR_DidHit(TraceRay)) 458 | { 459 | TR_GetEndPosition(vecPos, TraceRay); 460 | } 461 | 462 | delete TraceRay; 463 | } 464 | 465 | public bool ExcludeFilter(int entityhit, int mask, any entity) 466 | { 467 | if (entityhit > MaxClients && entityhit != entity) 468 | { 469 | return true; 470 | } 471 | 472 | return false; 473 | } 474 | 475 | stock int FindNearestEnemy(int iEntity, float flMaxDistance = 999999.0) 476 | { 477 | float flPos[3]; 478 | GetEntPropVector(iEntity, Prop_Data, "m_vecOrigin", flPos); 479 | 480 | float flBestDistance = flMaxDistance; 481 | int iBestTarget = -1; 482 | 483 | for(int i = 1; i <= MaxClients; i++) 484 | { 485 | if(IsClientInGame(i) && IsPlayerAlive(i)) 486 | { 487 | float flTPos[3]; 488 | GetClientEyePosition(i, flTPos); 489 | 490 | if(PF_Exists(iEntity) && !PF_IsPathToEntityPossible(iEntity, i)) 491 | continue; 492 | 493 | float flDistance = GetVectorDistance(flPos, flTPos); 494 | 495 | if(flDistance < flBestDistance) 496 | { 497 | flBestDistance = flDistance; 498 | iBestTarget = i; 499 | } 500 | } 501 | } 502 | 503 | return iBestTarget; 504 | } 505 | -------------------------------------------------------------------------------- /npc_clot.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //#define DEBUG_UPDATE 9 | //#define DEBUG_ANIMATION 10 | //#define DEBUG_SOUND 11 | 12 | #include 13 | 14 | #pragma newdecls required; 15 | 16 | #define GORE_ABDOMEN (1 << 0) 17 | #define GORE_FOREARMLEFT (1 << 1) 18 | #define GORE_HANDRIGHT (1 << 2) 19 | #define GORE_FOREARMRIGHT (1 << 3) 20 | #define GORE_HEAD (1 << 4) 21 | #define GORE_HEADLEFT (1 << 5) 22 | #define GORE_HEADRIGHT (1 << 6) 23 | #define GORE_UPARMLEFT (1 << 7) 24 | #define GORE_UPARMRIGHT (1 << 8) 25 | #define GORE_HANDLEFT (1 << 9) 26 | 27 | char g_DeathSounds[][] = { 28 | ")clot/clot_death_01.wav", 29 | ")clot/clot_death_02.wav", 30 | ")clot/clot_death_03.wav", 31 | }; 32 | 33 | char g_HurtSounds[][] = { 34 | ")clot/clot_hurt_01.wav", 35 | ")clot/clot_hurt_02.wav", 36 | ")clot/clot_hurt_03.wav", 37 | //Not sure what these are for 38 | ")clot/clot_grunt_01.wav", 39 | ")clot/clot_grunt_02.wav", 40 | ")clot/clot_grunt_03.wav", 41 | ")clot/clot_grunt_04.wav", 42 | }; 43 | 44 | char g_IdleSounds[][] = { 45 | ")clot/clot_idle_raspy_01.wav", 46 | ")clot/clot_idle_raspy_02.wav", 47 | ")clot/clot_idle_raspy_03.wav", 48 | }; 49 | 50 | char g_IdleAlertedSounds[][] = { 51 | ")clot/clot_roar_01.wav", 52 | ")clot/clot_roar_02.wav", 53 | ")clot/clot_roar_03.wav", 54 | ")clot/clot_roar_04.wav", 55 | }; 56 | 57 | char g_MeleeHitSounds[][] = { 58 | ")npc/fast_zombie/claw_strike1.wav", 59 | ")npc/fast_zombie/claw_strike2.wav", 60 | ")npc/fast_zombie/claw_strike3.wav", 61 | }; 62 | 63 | char g_MeleeMissSounds[][] = { 64 | ")npc/fast_zombie/claw_miss1.wav", 65 | ")npc/fast_zombie/claw_miss2.wav", 66 | }; 67 | 68 | public Plugin myinfo = 69 | { 70 | name = "[TF2] KF2 Clot NPC", 71 | author = "Pelipoika", 72 | description = "", 73 | version = "1.0", 74 | url = "" 75 | }; 76 | 77 | public void OnPluginStart() 78 | { 79 | RegAdminCmd("sm_clot", Command_PetMenu, ADMFLAG_ROOT); 80 | 81 | InitGamedata(); 82 | } 83 | 84 | public void OnMapStart() 85 | { 86 | for (int i = 0; i < (sizeof(g_DeathSounds)); i++) { PrecacheSound(g_DeathSounds[i]); } 87 | for (int i = 0; i < (sizeof(g_HurtSounds)); i++) { PrecacheSound(g_HurtSounds[i]); } 88 | for (int i = 0; i < (sizeof(g_IdleSounds)); i++) { PrecacheSound(g_IdleSounds[i]); } 89 | for (int i = 0; i < (sizeof(g_IdleAlertedSounds)); i++) { PrecacheSound(g_IdleAlertedSounds[i]); } 90 | for (int i = 0; i < (sizeof(g_MeleeHitSounds)); i++) { PrecacheSound(g_MeleeHitSounds[i]); } 91 | for (int i = 0; i < (sizeof(g_MeleeMissSounds)); i++) { PrecacheSound(g_MeleeMissSounds[i]); } 92 | 93 | InitNavGamedata(); 94 | } 95 | 96 | methodmap Clot < CClotBody 97 | { 98 | property int m_iState 99 | { 100 | public get() { return this.ExtractStringValueAsInt("m_iState"); } 101 | public set(int iActivity) { char buff[8]; IntToString(iActivity, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_iState", buff, true); } 102 | } 103 | property float m_flNextTargetTime 104 | { 105 | public get() { return this.ExtractStringValueAsFloat("m_flNextTargetTime"); } 106 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextTargetTime", buff, true); } 107 | } 108 | property float m_flNextIdleSound 109 | { 110 | public get() { return this.ExtractStringValueAsFloat("m_flNextIdleSound"); } 111 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextIdleSound", buff, true); } 112 | } 113 | property float m_flNextHurtSound 114 | { 115 | public get() { return this.ExtractStringValueAsFloat("m_flNextHurtSound"); } 116 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextHurtSound", buff, true); } 117 | } 118 | property float m_flNextBloodSpray 119 | { 120 | public get() { return this.ExtractStringValueAsFloat("m_flNextBloodSpray"); } 121 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextBloodSpray", buff, true); } 122 | } 123 | 124 | //Stun 125 | property bool m_bStunned 126 | { 127 | public get() { return !!this.ExtractStringValueAsInt("m_bStunned"); } 128 | public set(bool bOnOff) { char buff[8]; IntToString(bOnOff, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_bStunned", buff, true); } 129 | } 130 | property int m_iStunState 131 | { 132 | public get() { return this.ExtractStringValueAsInt("m_iStunState"); } 133 | public set(int iActivity) { char buff[8]; IntToString(iActivity, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_iStunState", buff, true); } 134 | } 135 | property float m_flStunEndTime 136 | { 137 | public get() { return this.ExtractStringValueAsFloat("m_flStunEndTime"); } 138 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flStunEndTime", buff, true); } 139 | } 140 | 141 | public bool IsDecapitated() 142 | { 143 | int nBody = GetEntProp(this.index, Prop_Send, "m_nBody"); 144 | int nNoHeadMask = (GORE_HEADRIGHT | GORE_HEADLEFT | GORE_HEAD); 145 | 146 | return ((nBody & nNoHeadMask) == nNoHeadMask); 147 | } 148 | 149 | public void PlayIdleSound() { 150 | if(this.m_flNextIdleSound > GetGameTime() || this.IsDecapitated()) 151 | return; 152 | 153 | EmitSoundToAll(g_IdleSounds[GetRandomInt(0, sizeof(g_IdleSounds) - 1)], this.index, SNDCHAN_STATIC, 150, _, 1.0, GetRandomInt(95, 105)); 154 | this.m_flNextIdleSound = GetGameTime() + GetRandomFloat(3.0, 6.0); 155 | 156 | #if defined DEBUG_SOUND 157 | PrintToServer("CClot::PlayIdleSound()"); 158 | #endif 159 | } 160 | 161 | public void PlayIdleAlertSound() { 162 | if(this.m_flNextIdleSound > GetGameTime() || this.IsDecapitated()) 163 | return; 164 | 165 | EmitSoundToAll(g_IdleAlertedSounds[GetRandomInt(0, sizeof(g_IdleAlertedSounds) - 1)], this.index, SNDCHAN_STATIC, 150, _, 1.0, GetRandomInt(95, 105)); 166 | this.m_flNextIdleSound = GetGameTime() + GetRandomFloat(3.0, 6.0); 167 | 168 | #if defined DEBUG_SOUND 169 | PrintToServer("CClot::PlayIdleAlertSound()"); 170 | #endif 171 | } 172 | 173 | public void PlayHurtSound() { 174 | if(this.m_flNextHurtSound > GetGameTime() || this.IsDecapitated()) 175 | return; 176 | 177 | EmitSoundToAll(g_HurtSounds[GetRandomInt(0, sizeof(g_HurtSounds) - 1)], this.index, SNDCHAN_STATIC, 150, _, 1.0, GetRandomInt(95, 105)); 178 | this.m_flNextHurtSound = GetGameTime() + GetRandomFloat(0.6, 1.6); 179 | 180 | #if defined DEBUG_SOUND 181 | PrintToServer("CClot::PlayHurtSound()"); 182 | #endif 183 | } 184 | 185 | public void PlayDeathSound() { 186 | if (this.IsDecapitated()) 187 | return; 188 | 189 | EmitSoundToAll(g_DeathSounds[GetRandomInt(0, sizeof(g_DeathSounds) - 1)], this.index, SNDCHAN_STATIC, 150, _, 1.0, GetRandomInt(95, 105)); 190 | 191 | #if defined DEBUG_SOUND 192 | PrintToServer("CClot::PlayDeathSound()"); 193 | #endif 194 | } 195 | 196 | public void PlayMeleeHitSound() { 197 | EmitSoundToAll(g_MeleeHitSounds[GetRandomInt(0, sizeof(g_MeleeHitSounds) - 1)], this.index, SNDCHAN_STATIC, 160, _, 1.0, GetRandomInt(95, 105)); 198 | 199 | #if defined DEBUG_SOUND 200 | PrintToServer("CClot::PlayMeleeHitSound()"); 201 | #endif 202 | } 203 | 204 | public void PlayMeleeMissSound() { 205 | EmitSoundToAll(g_MeleeMissSounds[GetRandomInt(0, sizeof(g_MeleeMissSounds) - 1)], this.index, SNDCHAN_STATIC, 160, _, 1.0, GetRandomInt(95, 105)); 206 | 207 | #if defined DEBUG_SOUND 208 | PrintToServer("CGoreFast::PlayMeleeMissSound()"); 209 | #endif 210 | } 211 | 212 | public bool IsAlert() { return this.m_iState == 1; } 213 | 214 | public float GetRunSpeed() { return this.IsAlert() && !this.IsDecapitated() ? 300.0 : 110.0; } 215 | public float GetMaxJumpHeight() { return 50.0; } 216 | public float GetLeadRadius() { return 500.0; } 217 | 218 | public Clot(int client, float vecPos[3], float vecAng[3], const char[] model) 219 | { 220 | Clot npc = view_as(CBaseActor(vecPos, vecAng, model, "1.0", "125")); 221 | 222 | int iActivity = npc.LookupActivity("ACT_MP_STAND_MELEE"); 223 | if(iActivity > 0) npc.StartActivity(iActivity); 224 | 225 | npc.CreatePather(18.0, npc.GetMaxJumpHeight(), 1000.0, npc.GetSolidMask(), 150.0, 0.25, 1.5); 226 | npc.m_flNextTargetTime = GetGameTime() + GetRandomFloat(1.0, 4.0); 227 | npc.m_flNextMeleeAttack = npc.m_flNextTargetTime; 228 | 229 | SDKHook(npc.index, SDKHook_Think, ClotThink); 230 | SDKHook(npc.index, SDKHook_TraceAttack, ClotDamaged); 231 | 232 | //IDLE 233 | npc.m_iState = 0; 234 | npc.m_bStunned = false; 235 | 236 | return npc; 237 | } 238 | 239 | public bool DoSwingTrace(Handle &trace) 240 | { 241 | // Setup a volume for the melee weapon to be swung - approx size, so all melee behave the same. 242 | static float vecSwingMins[3]; vecSwingMins = view_as({-48, -48, -48}); 243 | static float vecSwingMaxs[3]; vecSwingMaxs = view_as({48, 48, 48}); 244 | 245 | // Setup the swing range. 246 | float vecForward[3], vecRight[3], vecUp[3]; 247 | this.GetVectors(vecForward, vecRight, vecUp); 248 | 249 | float vecSwingStart[3]; vecSwingStart = GetAbsOrigin(this.index); 250 | vecSwingStart[2] += 54.0; 251 | 252 | float vecSwingEnd[3]; 253 | vecSwingEnd[0] = vecSwingStart[0] + vecForward[0] * 64; 254 | vecSwingEnd[1] = vecSwingStart[1] + vecForward[1] * 64; 255 | vecSwingEnd[2] = vecSwingStart[2] + vecForward[2] * 64; 256 | 257 | // See if we hit anything. 258 | trace = TR_TraceRayFilterEx( vecSwingStart, vecSwingEnd, MASK_SOLID, RayType_EndPoint, FilterBaseActorsAndData, this.index ); 259 | if ( TR_GetFraction(trace) >= 1.0 ) 260 | { 261 | delete trace; 262 | trace = TR_TraceHullFilterEx( vecSwingStart, vecSwingEnd, vecSwingMins, vecSwingMaxs, MASK_SOLID, FilterBaseActorsAndData, this.index ); 263 | if ( TR_GetFraction(trace) < 1.0 ) 264 | { 265 | // This is the point on the actual surface (the hull could have hit space) 266 | TR_GetEndPosition(vecSwingEnd, trace); 267 | } 268 | } 269 | 270 | return ( TR_GetFraction(trace) < 1.0 ); 271 | } 272 | } 273 | 274 | //TODO 275 | //Rewrite 276 | public void ClotThink(int iNPC) 277 | { 278 | if(GetEntProp(iNPC, Prop_Data, "m_lifeState") == 1) 279 | { 280 | SDKUnhook(iNPC, SDKHook_Think, ClotThink); 281 | SDKUnhook(iNPC, SDKHook_TraceAttack, ClotDamaged); 282 | 283 | return; 284 | } 285 | 286 | Clot npc = view_as(iNPC); 287 | 288 | //Don't let clients decide the bodygroups :angry: 289 | SetEntProp(npc.index, Prop_Send, "m_nBody", GetEntProp(npc.index, Prop_Send, "m_nBody")); 290 | 291 | //Think throttling 292 | if(npc.m_flNextThinkTime > GetGameTime()) { 293 | return; 294 | } 295 | 296 | npc.m_flNextThinkTime = GetGameTime() + 0.02; 297 | 298 | if(npc.IsDecapitated() && npc.m_flNextBloodSpray < GetGameTime()) 299 | { 300 | npc.DispatchParticleEffect(npc.index, "blood_bread_biting2", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, true); 301 | npc.m_flNextBloodSpray = GetGameTime() + 5.0; 302 | } 303 | 304 | npc.Update(); 305 | 306 | if(npc.m_bStunned) 307 | { 308 | //Begin stun 309 | if(npc.m_iStunState == -1) 310 | { 311 | int iActivity = npc.LookupActivity("ACT_MP_STUN_BEGIN"); 312 | 313 | PF_StopPathing(npc.index); 314 | 315 | npc.StartActivity(iActivity); 316 | npc.m_iStunState = 1; 317 | 318 | //Stunned effect 319 | npc.DispatchParticleEffect(npc.index, "conc_stars", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, false); 320 | } 321 | 322 | //Stun loop 323 | if(npc.IsSequenceFinished() && npc.m_iStunState == 1) 324 | { 325 | int iActivity = npc.LookupActivity("ACT_MP_STUN_MIDDLE"); 326 | 327 | npc.StartActivity(iActivity); 328 | npc.m_iStunState = 2; 329 | } 330 | 331 | //Stun end 332 | if(npc.m_flStunEndTime - GetGameTime() <= 0.0 && npc.m_iStunState == 2) 333 | { 334 | int iActivity = npc.LookupActivity("ACT_MP_STUN_END"); 335 | 336 | npc.StartActivity(iActivity); 337 | npc.m_iStunState = 3; 338 | 339 | //Clear stunned effect 340 | npc.DispatchParticleEffect(npc.index, "killstreak_t1_lvl1", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, true); 341 | } 342 | 343 | //Stun exit 344 | //Wait for stun anim to end and start pathing again. 345 | if(npc.IsSequenceFinished() && npc.m_iStunState == 3) 346 | { 347 | npc.m_bStunned = false; 348 | npc.m_iStunState = -1; 349 | } 350 | 351 | return; 352 | } 353 | 354 | CKnownEntity PrimaryThreat = npc.GetVisionInterface().GetPrimaryKnownThreat(); 355 | 356 | if(PrimaryThreat.Address != Address_Null) 357 | { 358 | npc.m_iState = 1; 359 | 360 | int PrimaryThreatIndex = PrimaryThreat.GetEntity(); 361 | if(PrimaryThreatIndex <= MaxClients && !IsPlayerAlive(PrimaryThreatIndex)) 362 | { 363 | //Stop chasing dead target. 364 | PF_StopPathing(npc.index); 365 | npc.m_bPathing = false; 366 | } 367 | else 368 | { 369 | float vecTarget[3]; vecTarget = WorldSpaceCenter(PrimaryThreatIndex); 370 | 371 | float flDistanceToTarget = GetVectorDistance(vecTarget, WorldSpaceCenter(npc.index)); 372 | 373 | //Predict their pos. 374 | if(flDistanceToTarget < npc.GetLeadRadius()) { 375 | 376 | float vPredictedPos[3]; vPredictedPos = PredictSubjectPosition(npc, PrimaryThreatIndex); 377 | 378 | /* int color[4]; 379 | color[0] = 255; 380 | color[1] = 255; 381 | color[2] = 0; 382 | color[3] = 255; 383 | 384 | int xd = PrecacheModel("materials/sprites/laserbeam.vmt"); 385 | 386 | TE_SetupBeamPoints(vPredictedPos, vecTarget, xd, xd, 0, 0, 0.25, 0.5, 0.5, 5, 5.0, color, 30); 387 | TE_SendToAllInRange(vecTarget, RangeType_Visibility);*/ 388 | 389 | PF_SetGoalVector(npc.index, vPredictedPos); 390 | } else { 391 | PF_SetGoalEntity(npc.index, PrimaryThreatIndex); 392 | } 393 | 394 | //Target close enough to hit 395 | if(flDistanceToTarget < 80 && !npc.IsPlayingGesture("ACT_MP_GESTURE_FLINCH_CHEST")) 396 | { 397 | //Look at target so we hit. 398 | npc.FaceTowards(vecTarget); 399 | 400 | //Can we attack right now? 401 | if(npc.m_flNextMeleeAttack < GetGameTime()) 402 | { 403 | //Play attack anim 404 | npc.AddGesture("ACT_MP_ATTACK_Stand_MELEE_var1"); 405 | 406 | Handle swingTrace; 407 | if(npc.DoSwingTrace(swingTrace)) 408 | { 409 | int target = TR_GetEntityIndex(swingTrace); 410 | 411 | float vecHit[3]; 412 | TR_GetEndPosition(vecHit, swingTrace); 413 | 414 | if(target > 0) 415 | { 416 | SDKHooks_TakeDamage(target, npc.index, npc.index, 10.0, DMG_SLASH|DMG_CLUB); 417 | 418 | //Snare players 419 | if(target <= MaxClients) 420 | { 421 | TF2_StunPlayer(target, 1.0, 0.6, 1); 422 | } 423 | 424 | // Hit particle 425 | npc.DispatchParticleEffect(npc.index, "blood_impact_backscatter", vecHit, NULL_VECTOR, NULL_VECTOR); 426 | 427 | // Hit sound 428 | npc.PlayMeleeHitSound(); 429 | 430 | //Did we kill them? 431 | int iHealthPost = GetEntProp(target, Prop_Data, "m_iHealth"); 432 | if(iHealthPost <= 0) 433 | { 434 | //Yup, time to celebrate 435 | npc.AddGesture("ACT_MP_GESTURE_VC_FISTBUMP_MELEE"); 436 | } 437 | } 438 | else 439 | { 440 | // Miss 441 | npc.PlayMeleeMissSound(); 442 | 443 | // Hit particle if we hit something. 444 | if(target >= 0) 445 | { 446 | npc.DispatchParticleEffect(npc.index, "impact_dirt", vecHit, NULL_VECTOR, NULL_VECTOR); 447 | } 448 | } 449 | } 450 | 451 | delete swingTrace; 452 | 453 | npc.m_flNextMeleeAttack = GetGameTime() + 0.5; 454 | } 455 | 456 | PF_StopPathing(npc.index); 457 | npc.m_bPathing = false; 458 | } 459 | else 460 | { 461 | PF_StartPathing(npc.index); 462 | npc.m_bPathing = true; 463 | } 464 | } 465 | } 466 | else 467 | { 468 | npc.m_iState = 0; 469 | } 470 | 471 | if(!npc.IsAlert()) { 472 | npc.PlayIdleSound(); 473 | 474 | //Roam while idle 475 | 476 | //Is it time to pick a new place to go? 477 | if(npc.m_flNextTargetTime < GetGameTime()) 478 | { 479 | //Pick a random goal area 480 | NavArea RandomArea = PickRandomArea(); 481 | 482 | if(RandomArea == NavArea_Null) 483 | return; 484 | 485 | float vecGoal[3]; RandomArea.GetCenter(vecGoal); 486 | 487 | if(!PF_IsPathToVectorPossible(iNPC, vecGoal)) 488 | return; 489 | 490 | PF_SetGoalVector(iNPC, vecGoal); 491 | PF_StartPathing(iNPC); 492 | npc.m_bPathing = true; 493 | 494 | //Timeout 495 | npc.m_flNextTargetTime = GetGameTime() + 10.0; 496 | } 497 | } else { 498 | npc.PlayIdleAlertSound(); 499 | } 500 | 501 | //v Handle jumping and running v 502 | int idealActivity = -1; 503 | 504 | if(!npc.m_bJumping) 505 | { 506 | if(npc.m_bPathing) { 507 | if(npc.IsAlert() && !npc.IsDecapitated()) { 508 | idealActivity = npc.LookupActivity("ACT_MP_RUN_MELEE"); 509 | } else { 510 | idealActivity = npc.LookupActivity("ACT_MP_CROUCHWALK_MELEE"); 511 | } 512 | } else { 513 | idealActivity = npc.LookupActivity("ACT_MP_STAND_MELEE"); 514 | } 515 | } 516 | 517 | float vecVelocity[3]; 518 | npc.GetVelocity(vecVelocity); 519 | 520 | // Handle air walking before handling jumping - air walking supersedes jump 521 | if(vecVelocity[2] > 300.0 || npc.m_bInAirWalk) 522 | { 523 | // Check to see if we were in an airwalk and now we are basically on the ground. 524 | if(GetEntityFlags(iNPC) & FL_ONGROUND && npc.m_bInAirWalk) 525 | { 526 | npc.RestartMainSequence(); 527 | npc.m_bInAirWalk = false; 528 | 529 | npc.AddGesture("ACT_MP_JUMP_LAND_melee"); 530 | } 531 | else if ((GetEntityFlags(iNPC) & FL_ONGROUND) == 0) 532 | { 533 | // In an air walk. 534 | idealActivity = npc.LookupActivity("ACT_MP_AIRWALK_MELEE"); 535 | npc.m_bInAirWalk = true; 536 | } 537 | } 538 | //Jumping 539 | else 540 | { 541 | if(npc.m_bJumping) 542 | { 543 | // Don't check if he's on the ground for a sec.. sometimes the client still has the 544 | // on-ground flag set right when the message comes in. 545 | if ( GetGameTime() - npc.m_flJumpStartTime > 0.2 ) 546 | { 547 | if ( GetEntityFlags(iNPC) & FL_ONGROUND ) 548 | { 549 | npc.m_bJumping = false; 550 | npc.RestartMainSequence(); 551 | } 552 | } 553 | 554 | // if we're still jumping 555 | if ( npc.m_bJumping ) 556 | { 557 | if ( GetGameTime() - npc.m_flJumpStartTime > 0.3 ) { 558 | idealActivity = npc.LookupActivity("ACT_MP_JUMP_FLOAT_melee"); 559 | } else { 560 | idealActivity = npc.LookupActivity("ACT_MP_JUMP_START_melee"); 561 | } 562 | } 563 | } 564 | } 565 | 566 | if(idealActivity != -1) 567 | { 568 | if(npc.m_iActivity != idealActivity) { 569 | npc.StartActivity(idealActivity); 570 | } 571 | } 572 | } 573 | 574 | enum //hitgroup_t 575 | { 576 | HITGROUP_GENERIC, 577 | HITGROUP_HEAD, 578 | HITGROUP_CHEST, 579 | HITGROUP_STOMACH, 580 | HITGROUP_LEFTARM, 581 | HITGROUP_RIGHTARM, 582 | HITGROUP_LEFTLEG, 583 | HITGROUP_RIGHTLEG, 584 | 585 | NUM_HITGROUPS 586 | }; 587 | 588 | stock float HitGroupDamageMultiplier(int hitgroup) 589 | { 590 | switch(hitgroup) 591 | { 592 | case HITGROUP_HEAD: 593 | return 0.75; 594 | 595 | case HITGROUP_CHEST, 596 | HITGROUP_STOMACH: 597 | return 1.25; 598 | 599 | case HITGROUP_LEFTLEG, 600 | HITGROUP_RIGHTLEG, 601 | HITGROUP_LEFTARM, 602 | HITGROUP_RIGHTARM: 603 | return 0.75; 604 | } 605 | 606 | return 1.0; 607 | } 608 | 609 | public Action ClotDamaged(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& ammotype, int hitbox, int hitgroup) 610 | { 611 | //Friendly fire 612 | if(view_as(attacker).GetTeam() == view_as(victim).GetTeam()) 613 | return Plugin_Continue; 614 | 615 | //Valid attackers only. 616 | if(attacker <= 0 || attacker > MaxClients) 617 | return Plugin_Continue; 618 | 619 | //PrintToServer("ClotDamaged victim %i attacker %i inflictor %i damage %.1f hitbox %i hitgroup %i", victim, attacker, inflictor, damage, hitbox, hitgroup); 620 | 621 | Clot npc = view_as(victim); 622 | 623 | int nBody = GetEntProp(npc.index, Prop_Send, "m_nBody"); 624 | 625 | damage *= HitGroupDamageMultiplier(hitgroup); 626 | 627 | //Headshots always crit 628 | if(hitgroup == HITGROUP_HEAD) 629 | { 630 | if(damage > GetEntProp(npc.index, Prop_Data, "m_iHealth")) 631 | { 632 | //Remove head on big head ache 633 | nBody |= (GORE_HEADRIGHT | GORE_HEADLEFT | GORE_HEAD); 634 | } 635 | else 636 | { 637 | //Randomized brain damage 638 | switch(GetRandomInt(1, 3)) 639 | { 640 | case 1: 641 | { 642 | if ((nBody & GORE_HEADRIGHT) != GORE_HEADRIGHT) nBody |= GORE_HEADRIGHT; 643 | else if ((nBody & GORE_HEADLEFT) != GORE_HEADLEFT) nBody |= GORE_HEADLEFT; 644 | else if ((nBody & GORE_HEAD) != GORE_HEAD) nBody |= GORE_HEAD; 645 | } 646 | case 2: 647 | { 648 | if ((nBody & GORE_HEADLEFT) != GORE_HEADLEFT) nBody |= GORE_HEADLEFT; 649 | else if ((nBody & GORE_HEADRIGHT) != GORE_HEADRIGHT) nBody |= GORE_HEADRIGHT; 650 | else if ((nBody & GORE_HEAD) != GORE_HEAD) nBody |= GORE_HEAD; 651 | } 652 | case 3: 653 | { 654 | if ((nBody & GORE_HEAD) != GORE_HEAD) nBody |= GORE_HEAD; 655 | else if ((nBody & GORE_HEADLEFT) != GORE_HEADLEFT) nBody |= GORE_HEADLEFT; 656 | else if ((nBody & GORE_HEADRIGHT) != GORE_HEADRIGHT) nBody |= GORE_HEADRIGHT; 657 | } 658 | } 659 | } 660 | 661 | //Unless they don't have a head... 662 | if(!npc.IsDecapitated()) 663 | { 664 | if(!npc.IsPlayingGesture("ACT_MP_GESTURE_FLINCH_CHEST")) 665 | { 666 | npc.AddGesture("ACT_MP_GESTURE_FLINCH_CHEST"); 667 | npc.PlayHurtSound(); 668 | } 669 | 670 | npc.DispatchParticleEffect(npc.index, "crit_text", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, true); 671 | damagetype |= DMG_CRIT; 672 | } 673 | } 674 | else 675 | { 676 | if(!npc.IsPlayingGesture("ACT_MP_GESTURE_FLINCH_CHEST")) 677 | { 678 | npc.AddGesture("ACT_MP_GESTURE_FLINCH_CHEST"); 679 | npc.PlayHurtSound(); 680 | } 681 | } 682 | 683 | SetEntProp(npc.index, Prop_Send, "m_nBody", nBody); 684 | 685 | //Percentage of damage taken vs our health 686 | float flDamagePercentage = (damage / GetEntProp(npc.index, Prop_Data, "m_iMaxHealth") * 100); 687 | 688 | //Critical hits increase the stun chance 2x 689 | if (damagetype & DMG_CRIT) 690 | flDamagePercentage *= 2.0; 691 | 692 | //I got hit with over 50% of my max health damage 693 | //Stun chance = percentage of damage vs max health 694 | if(!npc.m_bStunned && GetRandomFloat(0.0, 100.0) < flDamagePercentage) 695 | { 696 | //Off, ouch, owie 697 | npc.m_bStunned = true; 698 | npc.m_flStunEndTime = GetGameTime() + GetRandomFloat(5.0, 6.0); 699 | } 700 | 701 | bool bIsKnownAttacker = (npc.GetVisionInterface().GetKnown(attacker).Address != Address_Null); 702 | 703 | if(!bIsKnownAttacker) 704 | { 705 | npc.GetVisionInterface().AddKnownEntity(attacker); 706 | } 707 | 708 | return Plugin_Changed; 709 | } 710 | 711 | public Action Command_PetMenu(int client, int argc) 712 | { 713 | //What are you. 714 | if(!(client > 0 && client <= MaxClients && IsClientInGame(client))) 715 | return Plugin_Handled; 716 | 717 | float flPos[3], flAng[3]; 718 | GetClientAbsOrigin(client, flPos); 719 | GetClientAbsAngles(client, flAng); 720 | 721 | Clot(client, flPos, flAng, "models/vince_sf_proxy/zed_clot/zed_clot_01.mdl"); 722 | 723 | return Plugin_Handled; 724 | } 725 | 726 | public MRESReturn ILocomotion_GetRunSpeed(Address pThis, Handle hReturn, Handle hParams) 727 | { 728 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).GetRunSpeed()); 729 | return MRES_Supercede; 730 | } 731 | 732 | public MRESReturn IBody_GetSolidMask(Address pThis, Handle hReturn, Handle hParams) 733 | { 734 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).GetSolidMask()); 735 | return MRES_Supercede; 736 | } 737 | 738 | public MRESReturn IBody_GetActivity(Address pThis, Handle hReturn, Handle hParams) 739 | { 740 | #if defined DEBUG_ANIMATION 741 | PrintToServer("IBody_GetActivity"); 742 | #endif 743 | 744 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).GetActivity()); 745 | return MRES_Supercede; 746 | } 747 | 748 | public MRESReturn IBody_IsActivity(Address pThis, Handle hReturn, Handle hParams) 749 | { 750 | int iActivity = DHookGetParam(hParams, 1); 751 | 752 | #if defined DEBUG_ANIMATION 753 | PrintToServer("IBody_IsActivity %i", iActivity); 754 | #endif 755 | 756 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).IsActivity(iActivity)); 757 | return MRES_Supercede; 758 | } 759 | 760 | public MRESReturn IBody_StartActivity(Address pThis, Handle hReturn, Handle hParams) 761 | { 762 | int iActivity = DHookGetParam(hParams, 1); 763 | int fFlags = DHookGetParam(hParams, 2); 764 | 765 | #if defined DEBUG_ANIMATION 766 | PrintToServer("IBody_StartActivity %i %i", iActivity, fFlags); 767 | #endif 768 | 769 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).StartActivity(iActivity, fFlags)); 770 | 771 | return MRES_Supercede; 772 | } 773 | 774 | stock float[] PredictSubjectPosition(Clot npc, int subject) 775 | { 776 | float botPos[3]; 777 | GetEntPropVector(npc.index, Prop_Data, "m_vecAbsOrigin", botPos); 778 | 779 | float subjectPos[3]; 780 | GetEntPropVector(subject, Prop_Data, "m_vecAbsOrigin", subjectPos); 781 | 782 | float to[3]; 783 | SubtractVectors(subjectPos, botPos, to); 784 | to[2] = 0.0; 785 | 786 | float flRangeSq = GetVectorLength(to, true); 787 | 788 | // don't lead if subject is very far away 789 | float flLeadRadiusSq = npc.GetLeadRadius(); 790 | flLeadRadiusSq *= flLeadRadiusSq; 791 | if ( flRangeSq > flLeadRadiusSq ) 792 | return subjectPos; 793 | 794 | // Normalize in place 795 | float range = SquareRoot( flRangeSq ); 796 | to[0] /= ( range + 0.0001 ); // avoid divide by zero 797 | to[1] /= ( range + 0.0001 ); // avoid divide by zero 798 | to[2] /= ( range + 0.0001 ); // avoid divide by zero 799 | 800 | // estimate time to reach subject, assuming maximum speed 801 | float leadTime = 0.5 + ( range / ( npc.GetRunSpeed() + 0.0001 ) ); 802 | 803 | // estimate amount to lead the subject 804 | float SubjectAbsVelocity[3]; 805 | GetEntPropVector(subject, Prop_Data, "m_vecAbsVelocity", SubjectAbsVelocity); 806 | float lead[3]; 807 | lead[0] = leadTime * SubjectAbsVelocity[0]; 808 | lead[1] = leadTime * SubjectAbsVelocity[1]; 809 | lead[2] = 0.0; 810 | 811 | if(GetVectorDotProduct(to, lead) < 0.0) 812 | { 813 | // the subject is moving towards us - only pay attention 814 | // to his perpendicular velocity for leading 815 | float to2D[3]; to2D = to; 816 | to2D[2] = 0.0; 817 | NormalizeVector(to2D, to2D); 818 | 819 | float perp[2]; 820 | perp[0] = -to2D[1]; 821 | perp[1] = to2D[0]; 822 | 823 | float enemyGroundSpeed = lead[0] * perp[0] + lead[1] * perp[1]; 824 | 825 | lead[0] = enemyGroundSpeed * perp[0]; 826 | lead[1] = enemyGroundSpeed * perp[1]; 827 | } 828 | 829 | // compute our desired destination 830 | float pathTarget[3]; 831 | AddVectors(subjectPos, lead, pathTarget); 832 | 833 | // validate this destination 834 | 835 | // don't lead through walls 836 | if (GetVectorLength(lead, true) > 36.0) 837 | { 838 | float fraction; 839 | if (!PF_IsPotentiallyTraversable( npc.index, subjectPos, pathTarget, IMMEDIATELY, fraction)) 840 | { 841 | // tried to lead through an unwalkable area - clip to walkable space 842 | pathTarget[0] = subjectPos[0] + fraction * ( pathTarget[0] - subjectPos[0] ); 843 | pathTarget[1] = subjectPos[1] + fraction * ( pathTarget[1] - subjectPos[1] ); 844 | pathTarget[2] = subjectPos[2] + fraction * ( pathTarget[2] - subjectPos[2] ); 845 | } 846 | } 847 | 848 | NavArea leadArea = TheNavMesh.GetNearestNavArea_Vec( pathTarget ); 849 | 850 | if (leadArea == NavArea_Null || leadArea.GetZ(pathTarget[0], pathTarget[1]) < pathTarget[2] - npc.GetMaxJumpHeight()) 851 | { 852 | // would fall off a cliff 853 | return subjectPos; 854 | } 855 | 856 | return pathTarget; 857 | } 858 | -------------------------------------------------------------------------------- /npc_delorean.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma newdecls required 8 | 9 | #define MODEL_NPC "models/delorean_drivable.mdl" 10 | 11 | enum ParticleAttachment 12 | { 13 | PATTACH_ABSORIGIN = 0, // Create at absorigin, but don't follow 14 | PATTACH_ABSORIGIN_FOLLOW, // Create at absorigin, and update to follow the entity 15 | PATTACH_CUSTOMORIGIN, // Create at a custom origin, but don't follow 16 | PATTACH_POINT, // Create on attachment point, but don't follow 17 | PATTACH_POINT_FOLLOW, // Create on attachment point, and update to follow the entity 18 | PATTACH_WORLDORIGIN, // Used for control points that don't attach to an entity 19 | PATTACH_ROOTBONE_FOLLOW, // Create at the root bone of the entity, and update to follow 20 | MAX_PATTACH_TYPES, 21 | }; 22 | 23 | #define EF_BONEMERGE (1 << 0) 24 | #define EF_PARENT_ANIMATES (1 << 9) 25 | 26 | Handle g_hMyNextBotPointer; 27 | Handle g_hGetLocomotionInterface; 28 | Handle g_hGetBodyInterface; 29 | Handle g_hGetGroundNormal; 30 | Handle g_hRun; 31 | Handle g_hApproach; 32 | Handle g_hFaceTowards; 33 | Handle g_hResetSequence; 34 | Handle g_hGetStepHeight; 35 | Handle g_hGetGravity; 36 | Handle g_hGetSolidMask; 37 | Handle g_hStudioFrameAdvance; 38 | Handle g_hGetVectors; 39 | 40 | Handle g_hDispatchParticleEffect; 41 | 42 | Handle g_hLookupPoseParameter; 43 | Handle g_hSetPoseParameter; 44 | Handle g_hGetPoseParameter; 45 | 46 | Handle g_hGetFrictionSideways; 47 | Handle g_hGetMaxAcceleration; 48 | 49 | Handle g_hStudio_FindAttachment; 50 | Handle g_hGetAttachment; 51 | 52 | Handle g_hGetGroundMotionVector 53 | Handle g_hGetGroundSpeed; 54 | 55 | public Plugin myinfo = 56 | { 57 | name = "[TF2] ", 58 | author = "Pelipoika", 59 | description = "", 60 | version = "1.0", 61 | url = "http://www.sourcemod.net/plugins.php?author=Pelipoika&search=1" 62 | }; 63 | 64 | public void OnPluginStart() 65 | { 66 | RegAdminCmd("sm_npctest", test, ADMFLAG_ROOT); 67 | 68 | Handle hConf = LoadGameConfigFile("tf2.pets"); 69 | 70 | //DispatchParticleEffect(const char *pszParticleName, ParticleAttachment_t iAttachType, CBaseEntity *pEntity, const char *pszAttachmentName, bool bResetAllParticlesOnEntity) 71 | StartPrepSDKCall(SDKCall_Static); 72 | PrepSDKCall_SetSignature(SDKLibrary_Server, "\x55\x8B\xEC\x56\x8B\x75\x10\x57\x83\xCF\xFF", 11); 73 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); //pszParticleName 74 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //iAttachType 75 | PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); //pEntity 76 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); //pszAttachmentName 77 | PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); //bResetAllParticlesOnEntity 78 | if ((g_hDispatchParticleEffect = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for DispatchParticleEffect signature!"); 79 | 80 | StartPrepSDKCall(SDKCall_Entity); 81 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::StudioFrameAdvance"); 82 | if ((g_hStudioFrameAdvance = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::StudioFrameAdvance offset!"); 83 | 84 | StartPrepSDKCall(SDKCall_Entity); 85 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::ResetSequence"); 86 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 87 | if ((g_hResetSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::ResetSequence signature!"); 88 | 89 | StartPrepSDKCall(SDKCall_Entity); 90 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::MyNextBotPointer"); 91 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 92 | if ((g_hMyNextBotPointer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseEntity::MyNextBotPointer offset!"); 93 | 94 | StartPrepSDKCall(SDKCall_Raw); 95 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetLocomotionInterface"); 96 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 97 | if((g_hGetLocomotionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetLocomotionInterface!"); 98 | 99 | StartPrepSDKCall(SDKCall_Raw); 100 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetBodyInterface"); 101 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 102 | if((g_hGetBodyInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetBodyInterface!"); 103 | 104 | StartPrepSDKCall(SDKCall_Raw); 105 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Run"); 106 | if((g_hRun = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Run!"); 107 | 108 | StartPrepSDKCall(SDKCall_Raw); 109 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Approach"); 110 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 111 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 112 | if((g_hApproach = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Approach!"); 113 | 114 | StartPrepSDKCall(SDKCall_Raw); 115 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::FaceTowards"); 116 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 117 | if((g_hFaceTowards = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::FaceTowards!"); 118 | 119 | //ILocomotion::GetGroundSpeed() 120 | StartPrepSDKCall(SDKCall_Raw); 121 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundSpeed"); 122 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 123 | if((g_hGetGroundSpeed = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundSpeed!"); 124 | 125 | //ILocomotion::GetGroundMotionVector() 126 | StartPrepSDKCall(SDKCall_Raw); 127 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundMotionVector"); 128 | PrepSDKCall_SetReturnInfo(SDKType_Vector, SDKPass_ByRef); 129 | if((g_hGetGroundMotionVector = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundMotionVector!"); 130 | 131 | //CBaseAnimating::GetPoseParameter(int iParameter) 132 | StartPrepSDKCall(SDKCall_Entity); 133 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::GetPoseParameter"); 134 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 135 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 136 | if((g_hGetPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::GetPoseParameter"); 137 | 138 | //SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); 139 | StartPrepSDKCall(SDKCall_Entity); 140 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::SetPoseParameter"); 141 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 142 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 143 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 144 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 145 | if((g_hSetPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::SetPoseParameter"); 146 | 147 | //LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); 148 | StartPrepSDKCall(SDKCall_Entity); 149 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::LookupPoseParameter"); 150 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 151 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); 152 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 153 | if((g_hLookupPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::LookupPoseParameter"); 154 | 155 | //CBaseEntity::GetVectors(Vector*, Vector*, Vector*) 156 | StartPrepSDKCall(SDKCall_Entity); 157 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::GetVectors"); 158 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 159 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 160 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 161 | if((g_hGetVectors = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for CBaseEntity::GetVectors!"); 162 | 163 | //----------------------------------------------------------------------------- 164 | // Purpose: lookup attachment by name 165 | //----------------------------------------------------------------------------- 166 | StartPrepSDKCall(SDKCall_Static); 167 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "Studio_FindAttachment"); 168 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //pStudioHdr 169 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); //pAttachmentName 170 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); //return index 171 | if((g_hStudio_FindAttachment = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for Studio_FindAttachment"); 172 | 173 | //----------------------------------------------------------------------------- 174 | // Purpose: Returns the world location and world angles of an attachment 175 | // Input : attachment name 176 | // Output : location and angles 177 | //----------------------------------------------------------------------------- 178 | StartPrepSDKCall(SDKCall_Entity); 179 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::GetAttachment"); 180 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //iAttachment 181 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); //absOrigin 182 | PrepSDKCall_AddParameter(SDKType_QAngle, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); //absAngles 183 | if((g_hGetAttachment = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::GetAttachment"); 184 | 185 | g_hGetStepHeight = DHookCreateEx(hConf, "ILocomotion::GetStepHeight", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetStepHeight); 186 | g_hGetGravity = DHookCreateEx(hConf, "ILocomotion::GetGravity", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetGravity); 187 | g_hGetGroundNormal = DHookCreateEx(hConf, "ILocomotion::GetGroundNormal", HookType_Raw, ReturnType_VectorPtr, ThisPointer_Address, ILocomotion_GetGroundNormal); 188 | g_hGetFrictionSideways = DHookCreateEx(hConf, "ILocomotion::GetFrictionSideways",HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetFrictionSideways); 189 | g_hGetMaxAcceleration = DHookCreateEx(hConf, "ILocomotion::GetMaxAcceleration", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetMaxAcceleration); 190 | g_hGetSolidMask = DHookCreateEx(hConf, "IBody::GetSolidMask", HookType_Raw, ReturnType_Int, ThisPointer_Address, IBody_GetSolidMask); 191 | 192 | delete hConf; 193 | } 194 | 195 | public void OnMapStart() 196 | { 197 | PrecacheModel(MODEL_NPC); 198 | 199 | PrecacheSound("dejavu.mp3"); 200 | 201 | PrecacheSound("vehicles/v8/skid_highfriction.wav"); 202 | PrecacheSound("vehicles/delorean/v8_turbo_on_loop1.wav"); 203 | PrecacheSound("vehicles/v8/v8_turbo_on_loop1.wav"); 204 | 205 | PrecacheSound("vehicles/v8/vehicle_impact_heavy1.wav"); 206 | } 207 | 208 | public Action test(int client, int args) 209 | { 210 | float vecPos[3], vecAng[3]; 211 | GetAimPos(client, vecPos); 212 | GetClientEyeAngles(client, vecAng); 213 | vecAng[0] = 0.0; 214 | 215 | int npc = CreateEntityByName("base_boss"); 216 | DispatchKeyValueVector(npc, "origin", vecPos); 217 | DispatchKeyValueVector(npc, "angles", vecAng); 218 | DispatchKeyValue(npc, "model", MODEL_NPC); 219 | DispatchKeyValue(npc, "modelscale", "0.5"); 220 | DispatchKeyValue(npc, "health", "100"); 221 | DispatchSpawn(npc); 222 | 223 | ActivateEntity(npc); 224 | 225 | //trigger_hurts hurt and spawn doors open for us, etc. 226 | SetEntityFlags(npc, FL_CLIENT|FL_NPC); 227 | 228 | //Don't bleed. 229 | SetEntProp(npc, Prop_Data, "m_bloodColor", -1); 230 | 231 | //Speedster 232 | SetEntPropFloat(npc, Prop_Data, "m_speed", 800.0); 233 | 234 | //I won'd touch you. 235 | SetEntData(npc, FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 28, false, 4, true); //ResolvePlayerCollisions 236 | 237 | //Don't touch me. 238 | SetEntProp(npc, Prop_Data, "m_nSolidType", 0); 239 | 240 | SetEntPropVector(npc, Prop_Send, "m_vecMaxs", view_as( { 32.0, 32.0, 16.0 } )); 241 | SetEntPropVector(npc, Prop_Data, "m_vecMaxs", view_as( { 32.0, 32.0, 16.0 } )); 242 | SetEntPropVector(npc, Prop_Send, "m_vecMins", view_as( { -32.0, -32.0, 0.0 } )); 243 | SetEntPropVector(npc, Prop_Data, "m_vecMins", view_as( { -32.0, -32.0, 0.0 } )); 244 | 245 | float pos[3]; 246 | NavArea area = TheNavMesh.GetNearestNavArea_Vec(vecPos); 247 | area.GetCenter(pos); 248 | 249 | PF_Create(npc, 18.0, 18.0, 1000.0, 0.6, MASK_PLAYERSOLID|MASK_NPCSOLID, 200.0, 0.1, 1.0, 1.0); 250 | PF_SetGoalVector(npc, pos); 251 | PF_EnableCallback(npc, PFCB_Approach, PluginBot_Approach); 252 | PF_EnableCallback(npc, PFCB_GetPathCost, PluginBot_PathCost); 253 | PF_StartPathing(npc); 254 | 255 | SDKHook(npc, SDKHook_Think, DeloreanThink); 256 | 257 | Address pLoco = GetLocomotionInterface(npc); 258 | Address pBody = GetBodyInterface(npc); 259 | 260 | DHookRaw(g_hGetStepHeight, true, pLoco); 261 | DHookRaw(g_hGetGravity, true, pLoco); 262 | DHookRaw(g_hGetGroundNormal, true, pLoco); 263 | DHookRaw(g_hGetSolidMask, true, pBody); 264 | DHookRaw(g_hGetMaxAcceleration, true, pBody); 265 | DHookRaw(g_hGetFrictionSideways, true, pBody); 266 | 267 | EmitSoundToAll("dejavu.mp3", npc); 268 | EmitSoundToAll("dejavu.mp3", npc); 269 | EmitSoundToAll("vehicles/v8/v8_turbo_on_loop1.wav", npc); 270 | EmitSoundToAll("vehicles/v8/v8_turbo_on_loop1.wav", npc); 271 | EmitSoundToAll("vehicles/v8/v8_turbo_on_loop1.wav", npc); 272 | 273 | DispatchParticleEffect("speed_boost_trail", PATTACH_ABSORIGIN_FOLLOW, npc, "vehicle_engine"); 274 | 275 | DispatchParticleEffect("kart_dust_trail_red", PATTACH_POINT_FOLLOW, npc, "rearlight_right"); 276 | DispatchParticleEffect("kart_dust_trail_red", PATTACH_POINT_FOLLOW, npc, "rearlight_left"); 277 | 278 | return Plugin_Handled; 279 | } 280 | 281 | void DispatchParticleEffect(const char[] pszParticleName, ParticleAttachment iAttachType, int pEntity, const char[] pszAttachmentName, bool bResetAllParticlesOnEntity = false) 282 | { 283 | SDKCall(g_hDispatchParticleEffect, pszParticleName, iAttachType, pEntity, pszAttachmentName, bResetAllParticlesOnEntity); 284 | } 285 | 286 | public void DeloreanThink(int iEntity) 287 | { 288 | Address pLocomotion = GetLocomotionInterface(iEntity); 289 | 290 | float flGroundSpeed = SDKCall(g_hGetGroundSpeed, pLocomotion); 291 | if (flGroundSpeed != 0.0) 292 | { 293 | float vecMyPos[3], vecAngles[3]; 294 | GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", vecMyPos); 295 | GetEntPropVector(iEntity, Prop_Data, "m_angAbsRotation", vecAngles); 296 | 297 | //Current direction accroding to our movement. 298 | float vecMotion[3] 299 | SDKCall(g_hGetGroundMotionVector, pLocomotion, vecMotion); 300 | 301 | //Our direction according to our angles. 302 | float vecMyForward[3]; 303 | GetAngleVectors(vecAngles, NULL_VECTOR, vecMyForward, NULL_VECTOR); 304 | 305 | //Our vecMotion as an angle. 306 | float vecMovementAngle[3]; 307 | GetVectorAngles(vecMotion, vecMovementAngle); 308 | 309 | //Our vecMyForward as an angle. 310 | float vecMyForwardAngle[3]; 311 | GetVectorAngles(vecMyForward, vecMyForwardAngle); 312 | vecMyForwardAngle[1] = AngleNormalizePositive(vecMyForwardAngle[1] - 180); 313 | 314 | float ang1 = vecMovementAngle[1]; 315 | float ang2 = vecMyForwardAngle[1]; 316 | float angDiff = FloatAbs(ang1 - ang2); 317 | 318 | int m_nSkin = GetEntProp(iEntity, Prop_Send, "m_nSkin"); 319 | 320 | if (angDiff > 30.0 && flGroundSpeed >= 120.0 && GetEntityFlags(iEntity) & FL_ONGROUND) 321 | { 322 | float origin[3], angles[3]; 323 | GetAttachment(iEntity, "wheel_rr", origin, angles); 324 | CreateParticle("doublejump_puff", origin, angles); 325 | 326 | GetAttachment(iEntity, "wheel_rl", origin, angles); 327 | CreateParticle("doublejump_puff", origin, angles); 328 | 329 | if(m_nSkin != 1) 330 | { 331 | SetEntProp(iEntity, Prop_Send, "m_nSkin", 1); 332 | EmitSoundToAll("vehicles/v8/skid_highfriction.wav", iEntity); 333 | EmitSoundToAll("vehicles/v8/skid_highfriction.wav", iEntity); 334 | EmitSoundToAll("vehicles/v8/skid_highfriction.wav", iEntity); 335 | } 336 | } 337 | else 338 | { 339 | if(m_nSkin != 0) 340 | { 341 | SetEntProp(iEntity, Prop_Send, "m_nSkin", 0); 342 | } 343 | } 344 | 345 | int m_iSteer = LookupPoseParameter(iEntity, "vehicle_steer"); 346 | if ( m_iSteer < 0 ) 347 | return; 348 | 349 | float flCurrentGoal[3]; 350 | PF_GetFutureSegment(iEntity, 0, flCurrentGoal); 351 | 352 | float vecToGoal[3]; 353 | MakeVectorFromPoints(vecMyPos, flCurrentGoal, vecToGoal); 354 | NormalizeVector(vecToGoal, vecToGoal); 355 | 356 | float vecForward[3], vecRight[3], vecUp[3]; 357 | SDKCall(g_hGetVectors, iEntity, vecForward, vecRight, vecUp); 358 | 359 | float flDot = GetVectorDotProduct(vecForward, vecToGoal) * 2; 360 | SetPoseParameter(iEntity, m_iSteer, flDot); 361 | // PrintCenterText(1, " vecMovementAngle %f\n- vecMyForwardAngle %f\n = %f\nGroundspeed %f\nflDot %f", ang1, ang2, angDiff, flGroundSpeed, flDot); 362 | 363 | int m_iWheel_rl_spin = LookupPoseParameter(iEntity, "vehicle_wheel_rl_spin"); 364 | int m_iWheel_rr_spin = LookupPoseParameter(iEntity, "vehicle_wheel_rr_spin"); 365 | int m_iWheel_fl_spin = LookupPoseParameter(iEntity, "vehicle_wheel_fl_spin"); 366 | int m_iWheel_fr_spin = LookupPoseParameter(iEntity, "vehicle_wheel_fr_spin"); 367 | 368 | float flSpinRate = 20.0; 369 | SetPoseParameter(iEntity, m_iWheel_rl_spin, GetPoseParameter(iEntity, m_iWheel_rl_spin) + flSpinRate); 370 | SetPoseParameter(iEntity, m_iWheel_rr_spin, GetPoseParameter(iEntity, m_iWheel_rr_spin) + flSpinRate); 371 | SetPoseParameter(iEntity, m_iWheel_fl_spin, GetPoseParameter(iEntity, m_iWheel_fl_spin) + flSpinRate); 372 | SetPoseParameter(iEntity, m_iWheel_fr_spin, GetPoseParameter(iEntity, m_iWheel_fr_spin) + flSpinRate); 373 | } 374 | } 375 | 376 | public void PluginBot_Approach(int bot_entidx, const float vec[3]) 377 | { 378 | Address pLocomotion = GetLocomotionInterface(bot_entidx); 379 | 380 | SDKCall(g_hStudioFrameAdvance, bot_entidx); 381 | SDKCall(g_hRun, pLocomotion); 382 | SDKCall(g_hApproach, pLocomotion, vec, 1.0); 383 | 384 | float vecMyPos[3]; 385 | GetEntPropVector(bot_entidx, Prop_Data, "m_vecAbsOrigin", vecMyPos); 386 | 387 | float trash[3], trash2[3]; 388 | bool bSeg1 = PF_GetFutureSegment(bot_entidx, 0, trash); 389 | bool bSeg2 = PF_GetFutureSegment(bot_entidx, 1, trash2); 390 | 391 | if(bSeg1 && GetVectorDistance(trash, vecMyPos) <= 200.0 && !bSeg2) 392 | { 393 | float vecDirection[3]; 394 | vecDirection[0] = GetRandomFloat(-1.0, 1.0); 395 | vecDirection[1] = GetRandomFloat(-1.0, 1.0); 396 | vecDirection[2] = 0.0; 397 | 398 | ScaleVector(vecDirection, 2000.0); 399 | 400 | AddVectors(vecMyPos, vecDirection, vecMyPos); 401 | 402 | //We've arrived. 403 | float pos[3]; 404 | NavArea area = TheNavMesh.GetNearestNavArea_Vec(vecMyPos, true); 405 | if(area != NavArea_Null) 406 | { 407 | area.GetCenter(pos); 408 | 409 | if(PF_IsPathToVectorPossible(bot_entidx, pos)) 410 | { 411 | PF_SetGoalVector(bot_entidx, pos); 412 | } 413 | } 414 | } 415 | 416 | float vecToTarget[3]; 417 | SubtractVectors(vecMyPos, vec, vecToTarget); 418 | 419 | float vecAngles[3]; 420 | GetVectorAngles(vecToTarget, vecAngles); 421 | 422 | float vRight[3]; 423 | GetAngleVectors(vecAngles, NULL_VECTOR, vRight, NULL_VECTOR); 424 | 425 | vecMyPos[0] += vRight[0] * -90.0; 426 | vecMyPos[1] += vRight[1] * -90.0; 427 | vecMyPos[2] += vRight[2] * -90.0; 428 | 429 | ConVar flTurnRate = FindConVar("tf_base_boss_max_turn_rate"); 430 | float flPrevValue = flTurnRate.FloatValue; 431 | flTurnRate.FloatValue = 200.0; 432 | SDKCall(g_hFaceTowards, pLocomotion, vecMyPos); 433 | flTurnRate.FloatValue = flPrevValue; 434 | } 435 | 436 | public float PluginBot_PathCost(int bot_entidx, NavArea area, NavArea from_area, float length) 437 | { 438 | float dist; 439 | if (length != 0.0) 440 | { 441 | dist = length; 442 | } 443 | else 444 | { 445 | float vecCenter[3], vecFromCenter[3]; 446 | area.GetCenter(vecCenter); 447 | from_area.GetCenter(vecFromCenter); 448 | 449 | float vecSubtracted[3] 450 | SubtractVectors(vecCenter, vecFromCenter, vecSubtracted) 451 | 452 | dist = GetVectorLength(vecSubtracted); 453 | } 454 | 455 | float multiplier = 50.0; 456 | 457 | float cost = dist * multiplier; 458 | 459 | return from_area.GetCostSoFar() + cost; 460 | } 461 | 462 | public MRESReturn IBody_GetSolidMask(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, (MASK_NPCSOLID|MASK_PLAYERSOLID)); return MRES_Supercede; } 463 | public MRESReturn ILocomotion_GetGroundNormal(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturnVector(hReturn, view_as( { 0.0, 0.0, 1.0 } )); return MRES_Supercede; } 464 | public MRESReturn ILocomotion_GetStepHeight(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 18.0); return MRES_Supercede; } 465 | public MRESReturn ILocomotion_GetMaxAcceleration(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 100.0); return MRES_Supercede; } 466 | public MRESReturn ILocomotion_GetFrictionSideways(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 3.0); return MRES_Supercede; } 467 | public MRESReturn ILocomotion_GetGravity(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 800.0); return MRES_Supercede; } 468 | 469 | public int FindAttachment(int iEntity, const char[] pAttachmentName) 470 | { 471 | Address pStudioHdr = view_as
(GetEntData(iEntity, 283 * 4)); 472 | if(pStudioHdr == Address_Null) 473 | return -1; 474 | 475 | return SDKCall(g_hStudio_FindAttachment, pStudioHdr, pAttachmentName) + 1; 476 | } 477 | 478 | public void GetAttachment(int iEntity, const char[] szName, float absOrigin[3], float absAngles[3]) 479 | { 480 | SDKCall(g_hGetAttachment, iEntity, FindAttachment(iEntity, szName), absOrigin, absAngles); 481 | } 482 | 483 | public float GetPoseParameter(int iEntity, int iParameter) 484 | { 485 | return SDKCall(g_hGetPoseParameter, iEntity, iParameter); 486 | } 487 | 488 | public void SetPoseParameter(int iEntity, int iParameter, float value) 489 | { 490 | Address pStudioHdr = view_as
(GetEntData(iEntity, 283 * 4)); 491 | if(pStudioHdr == Address_Null) 492 | return; 493 | 494 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, iParameter, value); 495 | } 496 | 497 | public int LookupPoseParameter(int iEntity, const char[] szName) 498 | { 499 | Address pStudioHdr = view_as
(GetEntData(iEntity, 283 * 4)); 500 | if(pStudioHdr == Address_Null) 501 | return -1; 502 | 503 | return SDKCall(g_hLookupPoseParameter, iEntity, pStudioHdr, szName); 504 | } 505 | 506 | stock void CreateParticle(char[] particle, float pos[3], float ang[3], int iEntityIndex = -1, int iAttachType = 5) 507 | { 508 | int tblidx = FindStringTable("ParticleEffectNames"); 509 | char tmp[256]; 510 | int count = GetStringTableNumStrings(tblidx); 511 | int stridx = INVALID_STRING_INDEX; 512 | 513 | for(int i = 0; i < count; i++) 514 | { 515 | ReadStringTable(tblidx, i, tmp, sizeof(tmp)); 516 | if(StrEqual(tmp, particle, false)) 517 | { 518 | stridx = i; 519 | break; 520 | } 521 | } 522 | 523 | TE_Start("TFParticleEffect"); 524 | TE_WriteFloat("m_vecOrigin[0]", pos[0]); 525 | TE_WriteFloat("m_vecOrigin[1]", pos[1]); 526 | TE_WriteFloat("m_vecOrigin[2]", pos[2]); 527 | TE_WriteVector("m_vecAngles", ang); 528 | TE_WriteNum("m_iParticleSystemIndex", stridx); 529 | TE_WriteNum("entindex", iEntityIndex); 530 | TE_WriteNum("m_iAttachType", iAttachType); 531 | TE_SendToAll(); 532 | } 533 | 534 | stock float AngleNormalizePositive( float angle ) 535 | { 536 | angle = fmodf(angle, 360.0); 537 | if (angle < 0.0) 538 | { 539 | angle += 360.0; 540 | } 541 | return angle; 542 | } 543 | 544 | stock float AngleNormalize( float angle ) 545 | { 546 | angle = fmodf(angle, 360.0); 547 | if (angle > 180) 548 | { 549 | angle -= 360; 550 | } 551 | if (angle < -180) 552 | { 553 | angle += 360; 554 | } 555 | return angle; 556 | } 557 | 558 | stock float fmodf(float num, float denom) 559 | { 560 | return num - denom * RoundToFloor(num / denom); 561 | } 562 | 563 | stock float operator%(float oper1, float oper2) 564 | { 565 | return fmodf(oper1, oper2); 566 | } 567 | 568 | public float clamp(float a, float b, float c) 569 | { 570 | return (a > c ? c : (a < b ? b : a)); 571 | } 572 | 573 | public Address GetLocomotionInterface(int index) 574 | { 575 | Address pNB = SDKCall(g_hMyNextBotPointer, index); 576 | return SDKCall(g_hGetLocomotionInterface, pNB); 577 | } 578 | 579 | public Address GetBodyInterface(int index) 580 | { 581 | Address pNB = SDKCall(g_hMyNextBotPointer, index); 582 | return SDKCall(g_hGetBodyInterface, pNB); 583 | } 584 | 585 | Handle DHookCreateEx(Handle gc, const char[] key, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback) 586 | { 587 | int iOffset = GameConfGetOffset(gc, key); 588 | if(iOffset == -1) 589 | { 590 | SetFailState("Failed to get offset of %s", key); 591 | return null; 592 | } 593 | 594 | return DHookCreate(iOffset, hooktype, returntype, thistype, callback); 595 | } 596 | 597 | stock bool GetAimPos(int client, float vecPos[3]) 598 | { 599 | float StartOrigin[3], Angles[3]; 600 | GetClientEyeAngles(client, Angles); 601 | GetClientEyePosition(client, StartOrigin); 602 | 603 | Handle TraceRay = TR_TraceRayFilterEx(StartOrigin, Angles, MASK_ALL, RayType_Infinite, ExcludeFilter, client); 604 | if (TR_DidHit(TraceRay)) 605 | { 606 | TR_GetEndPosition(vecPos, TraceRay); 607 | } 608 | 609 | delete TraceRay; 610 | } 611 | 612 | public bool ExcludeFilter(int entityhit, int mask, any entity) 613 | { 614 | if (entityhit > MaxClients && entityhit != entity) 615 | { 616 | return true; 617 | } 618 | 619 | return false; 620 | } -------------------------------------------------------------------------------- /npc_gorefast.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | //#define DEBUG_UPDATE 9 | #define DEBUG_ANIMATION 10 | //#define DEBUG_SOUND 11 | 12 | #include 13 | 14 | #pragma newdecls required; 15 | 16 | #define GORE_HEAD (1 << 0) 17 | #define GORE_HEADLEFT (1 << 1) 18 | #define GORE_HEADRIGHT (1 << 2) 19 | #define GORE_HANDLEFT (1 << 3) 20 | #define GORE_HANDRIGHT (1 << 4) 21 | #define GORE_UPARMLEFT (1 << 5) 22 | #define GORE_UPARMRIGHT (1 << 6) 23 | #define GORE_FOREARMLEFT (1 << 7) 24 | #define GORE_FOREARMRIGHT (1 << 8) 25 | #define GORE_ABDOMEN (1 << 9) 26 | 27 | char g_DeathSounds[][] = { 28 | ")gorefast/gorefast_death_01.wav", 29 | ")gorefast/gorefast_death_02.wav", 30 | ")gorefast/gorefast_death_03.wav", 31 | ")gorefast/gorefast_death_04.wav", 32 | }; 33 | 34 | char g_HurtSounds[][] = { 35 | ")gorefast/gorefast_hurt_01.wav", 36 | ")gorefast/gorefast_hurt_02.wav", 37 | ")gorefast/gorefast_hurt_03.wav", 38 | ")gorefast/gorefast_hurt_04.wav", 39 | }; 40 | 41 | char g_IdleSounds[][] = { 42 | ")gorefast/gorefast_idle_wet_01.wav", 43 | ")gorefast/gorefast_idle_wet_02.wav", 44 | ")gorefast/gorefast_idle_wet_03.wav", 45 | ")gorefast/gorefast_idle_wet_04.wav", 46 | ")gorefast/gorefast_idle_wet_05.wav", 47 | }; 48 | 49 | char g_IdleAlertedSounds[][] = { 50 | ")gorefast/gorefast_idle_inhale_creepy_01.wav", 51 | ")gorefast/gorefast_idle_inhale_creepy_02.wav", 52 | ")gorefast/gorefast_idle_alerted_01.wav", 53 | ")gorefast/gorefast_idle_alerted_02.wav", 54 | ")gorefast/gorefast_idle_alerted_03.wav", 55 | }; 56 | 57 | char g_MeleeHitSounds[][] = { 58 | ")weapons/halloween_boss/knight_axe_hit.wav", 59 | }; 60 | 61 | char g_MeleeMissSounds[][] = { 62 | ")weapons/demo_sword_hit_world1.wav", 63 | }; 64 | 65 | public Plugin myinfo = 66 | { 67 | name = "[TF2] KF2 Gorefast NPC", 68 | author = "Pelipoika", 69 | description = "", 70 | version = "1.0", 71 | url = "" 72 | }; 73 | 74 | public void OnMapStart() 75 | { 76 | for (int i = 0; i < (sizeof(g_DeathSounds)); i++) { PrecacheSound(g_DeathSounds[i]); } 77 | for (int i = 0; i < (sizeof(g_HurtSounds)); i++) { PrecacheSound(g_HurtSounds[i]); } 78 | for (int i = 0; i < (sizeof(g_IdleSounds)); i++) { PrecacheSound(g_IdleSounds[i]); } 79 | for (int i = 0; i < (sizeof(g_IdleAlertedSounds)); i++) { PrecacheSound(g_IdleAlertedSounds[i]); } 80 | for (int i = 0; i < (sizeof(g_MeleeHitSounds)); i++) { PrecacheSound(g_MeleeHitSounds[i]); } 81 | for (int i = 0; i < (sizeof(g_MeleeMissSounds)); i++) { PrecacheSound(g_MeleeMissSounds[i]); } 82 | 83 | InitNavGamedata(); 84 | } 85 | 86 | public void OnPluginStart() 87 | { 88 | RegAdminCmd("sm_gorefast", Command_PetMenu, ADMFLAG_ROOT); 89 | 90 | InitGamedata(); 91 | } 92 | 93 | methodmap Clot < CClotBody 94 | { 95 | property int m_iState 96 | { 97 | public get() { return this.ExtractStringValueAsInt("m_iState"); } 98 | public set(int iActivity) { char buff[8]; IntToString(iActivity, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_iState", buff, true); } 99 | } 100 | property float m_flNextTargetTime 101 | { 102 | public get() { return this.ExtractStringValueAsFloat("m_flNextTargetTime"); } 103 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextTargetTime", buff, true); } 104 | } 105 | property float m_flNextIdleSound 106 | { 107 | public get() { return this.ExtractStringValueAsFloat("m_flNextIdleSound"); } 108 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextIdleSound", buff, true); } 109 | } 110 | property float m_flNextHurtSound 111 | { 112 | public get() { return this.ExtractStringValueAsFloat("m_flNextHurtSound"); } 113 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextHurtSound", buff, true); } 114 | } 115 | property float m_flNextBloodSpray 116 | { 117 | public get() { return this.ExtractStringValueAsFloat("m_flNextBloodSpray"); } 118 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flNextBloodSpray", buff, true); } 119 | } 120 | 121 | //Stun 122 | property bool m_bStunned 123 | { 124 | public get() { return !!this.ExtractStringValueAsInt("m_bStunned"); } 125 | public set(bool bOnOff) { char buff[8]; IntToString(bOnOff, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_bStunned", buff, true); } 126 | } 127 | property int m_iStunState 128 | { 129 | public get() { return this.ExtractStringValueAsInt("m_iStunState"); } 130 | public set(int iActivity) { char buff[8]; IntToString(iActivity, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_iStunState", buff, true); } 131 | } 132 | property float m_flStunEndTime 133 | { 134 | public get() { return this.ExtractStringValueAsFloat("m_flStunEndTime"); } 135 | public set(float flNextTime) { char buff[8]; FloatToString(flNextTime, buff, sizeof(buff)); SetCustomKeyValue(this.index, "m_flStunEndTime", buff, true); } 136 | } 137 | 138 | public bool IsDecapitated() 139 | { 140 | int nBody = GetEntProp(this.index, Prop_Send, "m_nBody"); 141 | int nNoHeadMask = (GORE_HEADRIGHT | GORE_HEADLEFT | GORE_HEAD); 142 | 143 | return ((nBody & nNoHeadMask) == nNoHeadMask); 144 | } 145 | 146 | public void PlayIdleSound() { 147 | if(this.m_flNextIdleSound > GetGameTime() || this.IsDecapitated()) 148 | return; 149 | 150 | EmitSoundToAll(g_IdleSounds[GetRandomInt(0, sizeof(g_IdleSounds) - 1)], this.index, SNDCHAN_STATIC, 100, _, 1.0, GetRandomInt(95, 105)); 151 | this.m_flNextIdleSound = GetGameTime() + GetRandomFloat(3.0, 6.0); 152 | 153 | #if defined DEBUG_SOUND 154 | PrintToServer("CGoreFast::PlayIdleSound()"); 155 | #endif 156 | } 157 | 158 | public void PlayIdleAlertSound() { 159 | if(this.m_flNextIdleSound > GetGameTime() || this.IsDecapitated()) 160 | return; 161 | 162 | EmitSoundToAll(g_IdleAlertedSounds[GetRandomInt(0, sizeof(g_IdleAlertedSounds) - 1)], this.index, SNDCHAN_STATIC, 100, _, 1.0, GetRandomInt(95, 105)); 163 | this.m_flNextIdleSound = GetGameTime() + GetRandomFloat(3.0, 6.0); 164 | 165 | #if defined DEBUG_SOUND 166 | PrintToServer("CGoreFast::PlayIdleAlertSound()"); 167 | #endif 168 | } 169 | 170 | public void PlayHurtSound() { 171 | if(this.m_flNextHurtSound > GetGameTime() || this.IsDecapitated()) 172 | return; 173 | 174 | EmitSoundToAll(g_HurtSounds[GetRandomInt(0, sizeof(g_HurtSounds) - 1)], this.index, SNDCHAN_STATIC, 100, _, 1.0, GetRandomInt(95, 105)); 175 | this.m_flNextHurtSound = GetGameTime() + GetRandomFloat(0.6, 1.6); 176 | 177 | #if defined DEBUG_SOUND 178 | PrintToServer("CGoreFast::PlayHurtSound()"); 179 | #endif 180 | } 181 | 182 | public void PlayDeathSound() { 183 | if(this.IsDecapitated()) 184 | return; 185 | 186 | EmitSoundToAll(g_DeathSounds[GetRandomInt(0, sizeof(g_DeathSounds) - 1)], this.index, SNDCHAN_STATIC, 100, _, 1.0, GetRandomInt(95, 105)); 187 | 188 | #if defined DEBUG_SOUND 189 | PrintToServer("CGoreFast::PlayDeathSound()"); 190 | #endif 191 | } 192 | 193 | public void PlayMeleeHitSound() { 194 | EmitSoundToAll(g_MeleeHitSounds[GetRandomInt(0, sizeof(g_MeleeHitSounds) - 1)], this.index, SNDCHAN_STATIC, 160, _, 1.0, GetRandomInt(95, 105)); 195 | 196 | #if defined DEBUG_SOUND 197 | PrintToServer("CClot::PlayMeleeHitSound()"); 198 | #endif 199 | } 200 | 201 | public void PlayMeleeMissSound() { 202 | EmitSoundToAll(g_MeleeMissSounds[GetRandomInt(0, sizeof(g_MeleeMissSounds) - 1)], this.index, SNDCHAN_STATIC, 160, _, 1.0, GetRandomInt(95, 105)); 203 | 204 | #if defined DEBUG_SOUND 205 | PrintToServer("CGoreFast::PlayMeleeMissSound()"); 206 | #endif 207 | } 208 | 209 | public bool IsAlert() { return this.m_iState == 1; } 210 | 211 | public float GetRunSpeed() { return this.IsAlert() && !this.IsDecapitated() ? 300.0 : 110.0; } 212 | public float GetMaxJumpHeight() { return 50.0; } 213 | public float GetLeadRadius() { return 500.0; } 214 | 215 | public Clot(int client, float vecPos[3], float vecAng[3], const char[] model) 216 | { 217 | Clot npc = view_as(CBaseActor(vecPos, vecAng, model, "1.0", "200")); 218 | 219 | int iActivity = npc.LookupActivity("ACT_MP_STAND_MELEE"); 220 | if(iActivity > 0) npc.StartActivity(iActivity); 221 | 222 | npc.CreatePather(18.0, npc.GetMaxJumpHeight(), 1000.0, npc.GetSolidMask(), 150.0, 0.25, 1.5); 223 | npc.m_flNextTargetTime = GetGameTime() + GetRandomFloat(1.0, 4.0); 224 | npc.m_flNextMeleeAttack = npc.m_flNextTargetTime; 225 | 226 | SDKHook(npc.index, SDKHook_Think, ClotThink); 227 | SDKHook(npc.index, SDKHook_TraceAttack, ClotDamaged); 228 | 229 | //IDLE 230 | npc.m_iState = 0; 231 | npc.m_bStunned = false; 232 | 233 | return npc; 234 | } 235 | 236 | public bool DoSwingTrace(Handle &trace) 237 | { 238 | // Setup a volume for the melee weapon to be swung - approx size, so all melee behave the same. 239 | static float vecSwingMins[3]; vecSwingMins = view_as({-48, -48, -48}); 240 | static float vecSwingMaxs[3]; vecSwingMaxs = view_as({48, 48, 48}); 241 | 242 | // Setup the swing range. 243 | float vecForward[3], vecRight[3], vecUp[3]; 244 | this.GetVectors(vecForward, vecRight, vecUp); 245 | 246 | float vecSwingStart[3]; vecSwingStart = GetAbsOrigin(this.index); 247 | vecSwingStart[2] += 54.0; 248 | 249 | float vecSwingEnd[3]; 250 | vecSwingEnd[0] = vecSwingStart[0] + vecForward[0] * 100; 251 | vecSwingEnd[1] = vecSwingStart[1] + vecForward[1] * 100; 252 | vecSwingEnd[2] = vecSwingStart[2] + vecForward[2] * 100; 253 | 254 | // See if we hit anything. 255 | trace = TR_TraceRayFilterEx( vecSwingStart, vecSwingEnd, MASK_SOLID, RayType_EndPoint, FilterBaseActorsAndData, this.index ); 256 | if ( TR_GetFraction(trace) >= 1.0 ) 257 | { 258 | delete trace; 259 | trace = TR_TraceHullFilterEx( vecSwingStart, vecSwingEnd, vecSwingMins, vecSwingMaxs, MASK_SOLID, FilterBaseActorsAndData, this.index ); 260 | if ( TR_GetFraction(trace) < 1.0 ) 261 | { 262 | // This is the point on the actual surface (the hull could have hit space) 263 | TR_GetEndPosition(vecSwingEnd, trace); 264 | } 265 | } 266 | 267 | return ( TR_GetFraction(trace) < 1.0 ); 268 | } 269 | } 270 | 271 | //TODO 272 | //Rewrite 273 | public void ClotThink(int iNPC) 274 | { 275 | if(GetEntProp(iNPC, Prop_Data, "m_lifeState") == 1) 276 | { 277 | SDKUnhook(iNPC, SDKHook_Think, ClotThink); 278 | SDKUnhook(iNPC, SDKHook_TraceAttack, ClotDamaged); 279 | 280 | return; 281 | } 282 | 283 | Clot npc = view_as(iNPC); 284 | 285 | //Don't let clients decide the bodygroups :angry: 286 | SetEntProp(npc.index, Prop_Send, "m_nBody", GetEntProp(npc.index, Prop_Send, "m_nBody")); 287 | 288 | //Think throttling 289 | if(npc.m_flNextThinkTime > GetGameTime()) { 290 | return; 291 | } 292 | 293 | npc.m_flNextThinkTime = GetGameTime() + 0.02; 294 | 295 | if(npc.IsDecapitated() && npc.m_flNextBloodSpray < GetGameTime()) 296 | { 297 | npc.DispatchParticleEffect(npc.index, "blood_bread_biting2", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, true); 298 | npc.m_flNextBloodSpray = GetGameTime() + 5.0; 299 | } 300 | 301 | npc.Update(); 302 | 303 | if(npc.m_bStunned) 304 | { 305 | //Begin stun 306 | if(npc.m_iStunState == -1) 307 | { 308 | int iActivity = npc.LookupActivity("ACT_MP_STUN_BEGIN"); 309 | 310 | PF_StopPathing(npc.index); 311 | 312 | npc.StartActivity(iActivity); 313 | npc.m_iStunState = 1; 314 | 315 | //Stunned effect 316 | npc.DispatchParticleEffect(npc.index, "conc_stars", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, false); 317 | } 318 | 319 | //Stun loop 320 | if(npc.IsSequenceFinished() && npc.m_iStunState == 1) 321 | { 322 | int iActivity = npc.LookupActivity("ACT_MP_STUN_MIDDLE"); 323 | 324 | npc.StartActivity(iActivity); 325 | npc.m_iStunState = 2; 326 | } 327 | 328 | //Stun end 329 | if(npc.m_flStunEndTime - GetGameTime() <= 0.0 && npc.m_iStunState == 2) 330 | { 331 | int iActivity = npc.LookupActivity("ACT_MP_STUN_END"); 332 | 333 | npc.StartActivity(iActivity); 334 | npc.m_iStunState = 3; 335 | 336 | //Clear stunned effect 337 | npc.DispatchParticleEffect(npc.index, "killstreak_t1_lvl1", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, true); 338 | } 339 | 340 | //Stun exit 341 | //Wait for stun anim to end and start pathing again. 342 | if(npc.IsSequenceFinished() && npc.m_iStunState == 3) 343 | { 344 | npc.m_bStunned = false; 345 | npc.m_iStunState = -1; 346 | } 347 | 348 | return; 349 | } 350 | 351 | CKnownEntity PrimaryThreat = npc.GetVisionInterface().GetPrimaryKnownThreat(); 352 | 353 | if(PrimaryThreat.Address != Address_Null) 354 | { 355 | npc.m_iState = 1; 356 | 357 | int PrimaryThreatIndex = PrimaryThreat.GetEntity(); 358 | if(PrimaryThreatIndex <= MaxClients && !IsPlayerAlive(PrimaryThreatIndex)) 359 | { 360 | //Stop chasing dead target. 361 | PF_StopPathing(npc.index); 362 | npc.m_bPathing = false; 363 | } 364 | else 365 | { 366 | float vecTarget[3]; vecTarget = WorldSpaceCenter(PrimaryThreatIndex); 367 | 368 | float flDistanceToTarget = GetVectorDistance(vecTarget, WorldSpaceCenter(npc.index)); 369 | 370 | //Predict their pos. 371 | if(flDistanceToTarget < npc.GetLeadRadius()) { 372 | 373 | float vPredictedPos[3]; vPredictedPos = PredictSubjectPosition(npc, PrimaryThreatIndex); 374 | 375 | /* int color[4]; 376 | color[0] = 255; 377 | color[1] = 255; 378 | color[2] = 0; 379 | color[3] = 255; 380 | 381 | int xd = PrecacheModel("materials/sprites/laserbeam.vmt"); 382 | 383 | TE_SetupBeamPoints(vPredictedPos, vecTarget, xd, xd, 0, 0, 0.25, 0.5, 0.5, 5, 5.0, color, 30); 384 | TE_SendToAllInRange(vecTarget, RangeType_Visibility);*/ 385 | 386 | PF_SetGoalVector(npc.index, vPredictedPos); 387 | } else { 388 | PF_SetGoalEntity(npc.index, PrimaryThreatIndex); 389 | } 390 | 391 | //Target close enough to hit 392 | if(flDistanceToTarget < 100.0 && !npc.IsPlayingGesture("ACT_MP_GESTURE_FLINCH_CHEST")) 393 | { 394 | //Look at target so we hit. 395 | npc.FaceTowards(vecTarget); 396 | 397 | //Can we attack right now? 398 | if(npc.m_flNextMeleeAttack < GetGameTime()) 399 | { 400 | //Play attack anim 401 | npc.AddGesture("ACT_MP_ATTACK_Stand_MELEE"); 402 | 403 | Handle swingTrace; 404 | if(npc.DoSwingTrace(swingTrace)) 405 | { 406 | int target = TR_GetEntityIndex(swingTrace); 407 | 408 | float vecHit[3]; 409 | TR_GetEndPosition(vecHit, swingTrace); 410 | 411 | if(target > 0) 412 | { 413 | SDKHooks_TakeDamage(target, npc.index, npc.index, 25.0, DMG_SLASH|DMG_ALWAYSGIB|DMG_BLAST|DMG_CLUB); 414 | 415 | //Snare players 416 | if(target <= MaxClients) { 417 | TF2_StunPlayer(target, 1.0, 0.75, 1); 418 | } 419 | 420 | // Hit particle 421 | npc.DispatchParticleEffect(npc.index, "halloween_boss_axe_hit_sparks", vecHit, NULL_VECTOR, NULL_VECTOR); 422 | 423 | // Hit sound 424 | npc.PlayMeleeHitSound(); 425 | 426 | //Did we kill them? 427 | int iHealthPost = GetEntProp(target, Prop_Data, "m_iHealth"); 428 | if(iHealthPost <= 0) 429 | { 430 | npc.AddGesture("ACT_MP_GESTURE_VC_FISTBUMP_MELEE"); 431 | } 432 | } 433 | else 434 | { 435 | // Miss 436 | npc.PlayMeleeMissSound(); 437 | 438 | // Hit particle if we hit something. 439 | if(target >= 0) 440 | { 441 | npc.DispatchParticleEffect(npc.index, "halloween_boss_axe_hit_world", vecHit, NULL_VECTOR, NULL_VECTOR); 442 | npc.DispatchParticleEffect(npc.index, "impact_dirt", vecHit, NULL_VECTOR, NULL_VECTOR); 443 | } 444 | } 445 | } 446 | 447 | delete swingTrace; 448 | 449 | npc.m_flNextMeleeAttack = GetGameTime() + 0.5; 450 | } 451 | 452 | PF_StopPathing(npc.index); 453 | npc.m_bPathing = false; 454 | } 455 | else 456 | { 457 | PF_StartPathing(npc.index); 458 | npc.m_bPathing = true; 459 | } 460 | } 461 | } 462 | else 463 | { 464 | npc.m_iState = 0; 465 | } 466 | 467 | if(!npc.IsAlert()) { 468 | npc.PlayIdleSound(); 469 | 470 | //Roam while idle 471 | 472 | //Is it time to pick a new place to go? 473 | if(npc.m_flNextTargetTime < GetGameTime()) 474 | { 475 | //Pick a random goal area 476 | NavArea RandomArea = PickRandomArea(); 477 | 478 | if(RandomArea == NavArea_Null) 479 | return; 480 | 481 | float vecGoal[3]; RandomArea.GetCenter(vecGoal); 482 | 483 | if(!PF_IsPathToVectorPossible(iNPC, vecGoal)) 484 | return; 485 | 486 | PF_SetGoalVector(iNPC, vecGoal); 487 | PF_StartPathing(iNPC); 488 | npc.m_bPathing = true; 489 | 490 | //Timeout 491 | npc.m_flNextTargetTime = GetGameTime() + 10.0; 492 | } 493 | } else { 494 | npc.PlayIdleAlertSound(); 495 | } 496 | 497 | //v Handle jumping and running v 498 | int idealActivity = -1; 499 | 500 | if(!npc.m_bJumping) 501 | { 502 | if(npc.m_bPathing) { 503 | if(npc.IsAlert() && !npc.IsDecapitated()) { 504 | idealActivity = npc.LookupActivity("ACT_MP_RUN_MELEE"); 505 | } else { 506 | idealActivity = npc.LookupActivity("ACT_MP_CROUCHWALK_MELEE"); 507 | } 508 | } else { 509 | idealActivity = npc.LookupActivity("ACT_MP_STAND_MELEE"); 510 | } 511 | } 512 | 513 | float vecVelocity[3]; 514 | npc.GetVelocity(vecVelocity); 515 | 516 | // Handle air walking before handling jumping - air walking supersedes jump 517 | if(vecVelocity[2] > 300.0 || npc.m_bInAirWalk) 518 | { 519 | // Check to see if we were in an airwalk and now we are basically on the ground. 520 | if(GetEntityFlags(iNPC) & FL_ONGROUND && npc.m_bInAirWalk) 521 | { 522 | npc.RestartMainSequence(); 523 | npc.m_bInAirWalk = false; 524 | 525 | npc.AddGesture("ACT_MP_JUMP_LAND_melee"); 526 | } 527 | else if ((GetEntityFlags(iNPC) & FL_ONGROUND) == 0) 528 | { 529 | // In an air walk. 530 | idealActivity = npc.LookupActivity("ACT_MP_AIRWALK_MELEE"); 531 | npc.m_bInAirWalk = true; 532 | } 533 | } 534 | //Jumping 535 | else 536 | { 537 | if(npc.m_bJumping) 538 | { 539 | // Don't check if he's on the ground for a sec.. sometimes the client still has the 540 | // on-ground flag set right when the message comes in. 541 | if ( GetGameTime() - npc.m_flJumpStartTime > 0.2 ) 542 | { 543 | if ( GetEntityFlags(iNPC) & FL_ONGROUND ) 544 | { 545 | npc.m_bJumping = false; 546 | npc.RestartMainSequence(); 547 | } 548 | } 549 | 550 | // if we're still jumping 551 | if ( npc.m_bJumping ) 552 | { 553 | if ( GetGameTime() - npc.m_flJumpStartTime > 0.3 ) { 554 | idealActivity = npc.LookupActivity("ACT_MP_JUMP_FLOAT_melee"); 555 | } else { 556 | idealActivity = npc.LookupActivity("ACT_MP_JUMP_START_melee"); 557 | } 558 | } 559 | } 560 | } 561 | 562 | if(idealActivity != -1) 563 | { 564 | if(npc.m_iActivity != idealActivity) { 565 | npc.StartActivity(idealActivity); 566 | } 567 | } 568 | } 569 | 570 | public Action Command_PetMenu(int client, int argc) 571 | { 572 | //What are you. 573 | if(!(client > 0 && client <= MaxClients && IsClientInGame(client))) 574 | return Plugin_Handled; 575 | 576 | float flPos[3], flAng[3]; 577 | GetClientAbsOrigin(client, flPos); 578 | GetClientAbsAngles(client, flAng); 579 | 580 | Clot(client, flPos, flAng, "models/vince_sf_proxy/zed_gorefast/zed_gorefast_01.mdl"); 581 | 582 | return Plugin_Handled; 583 | } 584 | 585 | public MRESReturn ILocomotion_GetRunSpeed(Address pThis, Handle hReturn, Handle hParams) 586 | { 587 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).GetRunSpeed()); 588 | return MRES_Supercede; 589 | } 590 | 591 | public MRESReturn IBody_GetSolidMask(Address pThis, Handle hReturn, Handle hParams) 592 | { 593 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).GetSolidMask()); 594 | return MRES_Supercede; 595 | } 596 | 597 | public MRESReturn IBody_GetActivity(Address pThis, Handle hReturn, Handle hParams) 598 | { 599 | #if defined DEBUG_ANIMATION 600 | PrintToServer("IBody_GetActivity"); 601 | #endif 602 | 603 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).GetActivity()); 604 | return MRES_Supercede; 605 | } 606 | 607 | public MRESReturn IBody_IsActivity(Address pThis, Handle hReturn, Handle hParams) 608 | { 609 | int iActivity = DHookGetParam(hParams, 1); 610 | 611 | #if defined DEBUG_ANIMATION 612 | PrintToServer("IBody_IsActivity %i", iActivity); 613 | #endif 614 | 615 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).IsActivity(iActivity)); 616 | return MRES_Supercede; 617 | } 618 | 619 | public MRESReturn IBody_StartActivity(Address pThis, Handle hReturn, Handle hParams) 620 | { 621 | int iActivity = DHookGetParam(hParams, 1); 622 | int fFlags = DHookGetParam(hParams, 2); 623 | 624 | #if defined DEBUG_ANIMATION 625 | PrintToServer("IBody_StartActivity %i %i", iActivity, fFlags); 626 | #endif 627 | 628 | DHookSetReturn(hReturn, view_as(SDKCall(g_hGetEntity, SDKCall(g_hGetBot, pThis))).StartActivity(iActivity, fFlags)); 629 | 630 | return MRES_Supercede; 631 | } 632 | 633 | enum //hitgroup_t 634 | { 635 | HITGROUP_GENERIC, 636 | HITGROUP_HEAD, 637 | HITGROUP_CHEST, 638 | HITGROUP_STOMACH, 639 | HITGROUP_LEFTARM, 640 | HITGROUP_RIGHTARM, 641 | HITGROUP_LEFTLEG, 642 | HITGROUP_RIGHTLEG, 643 | 644 | NUM_HITGROUPS 645 | }; 646 | 647 | public Action ClotDamaged(int victim, int& attacker, int& inflictor, float& damage, int& damagetype, int& ammotype, int hitbox, int hitgroup) 648 | { 649 | //Friendly fire 650 | if(view_as(attacker).GetTeam() == view_as(victim).GetTeam()) 651 | return Plugin_Continue; 652 | 653 | //Valid attackers only. 654 | if(attacker <= 0 || attacker > MaxClients) 655 | return Plugin_Continue; 656 | 657 | //PrintToServer("ClotDamaged victim %i attacker %i inflictor %i damage %.1f hitbox %i hitgroup %i", victim, attacker, inflictor, damage, hitbox, hitgroup); 658 | 659 | Clot npc = view_as(victim); 660 | 661 | Action result = Plugin_Continue; 662 | int nBody = GetEntProp(npc.index, Prop_Send, "m_nBody"); 663 | 664 | //Headshots always crit 665 | if(hitgroup == HITGROUP_HEAD) 666 | { 667 | if(damage > GetEntProp(npc.index, Prop_Data, "m_iHealth")) 668 | { 669 | //Remove head on big head ache 670 | nBody |= (GORE_HEADRIGHT | GORE_HEADLEFT | GORE_HEAD); 671 | } 672 | else 673 | { 674 | //Randomized brain damage 675 | switch(GetRandomInt(1, 3)) 676 | { 677 | case 1: 678 | { 679 | if ((nBody & GORE_HEADRIGHT) != GORE_HEADRIGHT) nBody |= GORE_HEADRIGHT; 680 | else if ((nBody & GORE_HEADLEFT) != GORE_HEADLEFT) nBody |= GORE_HEADLEFT; 681 | else if ((nBody & GORE_HEAD) != GORE_HEAD) nBody |= GORE_HEAD; 682 | } 683 | case 2: 684 | { 685 | if ((nBody & GORE_HEADLEFT) != GORE_HEADLEFT) nBody |= GORE_HEADLEFT; 686 | else if ((nBody & GORE_HEADRIGHT) != GORE_HEADRIGHT) nBody |= GORE_HEADRIGHT; 687 | else if ((nBody & GORE_HEAD) != GORE_HEAD) nBody |= GORE_HEAD; 688 | } 689 | case 3: 690 | { 691 | if ((nBody & GORE_HEAD) != GORE_HEAD) nBody |= GORE_HEAD; 692 | else if ((nBody & GORE_HEADLEFT) != GORE_HEADLEFT) nBody |= GORE_HEADLEFT; 693 | else if ((nBody & GORE_HEADRIGHT) != GORE_HEADRIGHT) nBody |= GORE_HEADRIGHT; 694 | } 695 | } 696 | } 697 | 698 | //Unless they don't have a head... 699 | if(!npc.IsDecapitated()) 700 | { 701 | if(!npc.IsPlayingGesture("ACT_MP_GESTURE_FLINCH_CHEST")) 702 | { 703 | npc.AddGesture("ACT_MP_GESTURE_FLINCH_CHEST"); 704 | npc.PlayHurtSound(); 705 | } 706 | 707 | npc.DispatchParticleEffect(npc.index, "crit_text", NULL_VECTOR, NULL_VECTOR, NULL_VECTOR, npc.FindAttachment("gore_headfrontright"), PATTACH_POINT_FOLLOW, true); 708 | damagetype |= DMG_CRIT; 709 | } 710 | 711 | result = Plugin_Changed; 712 | } 713 | else 714 | { 715 | if(!npc.IsPlayingGesture("ACT_MP_GESTURE_FLINCH_CHEST")) 716 | { 717 | npc.AddGesture("ACT_MP_GESTURE_FLINCH_CHEST"); 718 | npc.PlayHurtSound(); 719 | } 720 | } 721 | 722 | SetEntProp(npc.index, Prop_Send, "m_nBody", nBody); 723 | 724 | //Percentage of damage taken vs our max health 725 | float flDamagePercentage = (damage / GetEntProp(npc.index, Prop_Data, "m_iMaxHealth") * 100); 726 | 727 | //Critical hits increase the stun chance 2x 728 | if (damagetype & DMG_CRIT) 729 | flDamagePercentage *= 2.0; 730 | 731 | //I got hit with over 50% of my max health damage 732 | //Stun chance = percentage of damage vs max health 733 | if(!npc.m_bStunned && GetRandomFloat(0.0, 100.0) < flDamagePercentage) 734 | { 735 | //Off, ouch, owie 736 | npc.m_bStunned = true; 737 | npc.m_flStunEndTime = GetGameTime() + GetRandomFloat(5.0, 6.0); 738 | } 739 | 740 | bool bIsKnownAttacker = (npc.GetVisionInterface().GetKnown(attacker).Address != Address_Null); 741 | 742 | if(!bIsKnownAttacker) 743 | { 744 | npc.GetVisionInterface().AddKnownEntity(attacker); 745 | } 746 | 747 | return result; 748 | } 749 | 750 | stock float[] PredictSubjectPosition(Clot npc, int subject) 751 | { 752 | float botPos[3]; 753 | GetEntPropVector(npc.index, Prop_Data, "m_vecAbsOrigin", botPos); 754 | 755 | float subjectPos[3]; 756 | GetEntPropVector(subject, Prop_Data, "m_vecAbsOrigin", subjectPos); 757 | 758 | float to[3]; 759 | SubtractVectors(subjectPos, botPos, to); 760 | to[2] = 0.0; 761 | 762 | float flRangeSq = GetVectorLength(to, true); 763 | 764 | // don't lead if subject is very far away 765 | float flLeadRadiusSq = npc.GetLeadRadius(); 766 | flLeadRadiusSq *= flLeadRadiusSq; 767 | if ( flRangeSq > flLeadRadiusSq ) 768 | return subjectPos; 769 | 770 | // Normalize in place 771 | float range = SquareRoot( flRangeSq ); 772 | to[0] /= ( range + 0.0001 ); // avoid divide by zero 773 | to[1] /= ( range + 0.0001 ); // avoid divide by zero 774 | to[2] /= ( range + 0.0001 ); // avoid divide by zero 775 | 776 | // estimate time to reach subject, assuming maximum speed 777 | float leadTime = 0.5 + ( range / ( npc.GetRunSpeed() + 0.0001 ) ); 778 | 779 | // estimate amount to lead the subject 780 | float SubjectAbsVelocity[3]; 781 | GetEntPropVector(subject, Prop_Data, "m_vecAbsVelocity", SubjectAbsVelocity); 782 | float lead[3]; 783 | lead[0] = leadTime * SubjectAbsVelocity[0]; 784 | lead[1] = leadTime * SubjectAbsVelocity[1]; 785 | lead[2] = 0.0; 786 | 787 | if(GetVectorDotProduct(to, lead) < 0.0) 788 | { 789 | // the subject is moving towards us - only pay attention 790 | // to his perpendicular velocity for leading 791 | float to2D[3]; to2D = to; 792 | to2D[2] = 0.0; 793 | NormalizeVector(to2D, to2D); 794 | 795 | float perp[2]; 796 | perp[0] = -to2D[1]; 797 | perp[1] = to2D[0]; 798 | 799 | float enemyGroundSpeed = lead[0] * perp[0] + lead[1] * perp[1]; 800 | 801 | lead[0] = enemyGroundSpeed * perp[0]; 802 | lead[1] = enemyGroundSpeed * perp[1]; 803 | } 804 | 805 | // compute our desired destination 806 | float pathTarget[3]; 807 | AddVectors(subjectPos, lead, pathTarget); 808 | 809 | // validate this destination 810 | 811 | // don't lead through walls 812 | if (GetVectorLength(lead, true) > 36.0) 813 | { 814 | float fraction; 815 | if (!PF_IsPotentiallyTraversable( npc.index, subjectPos, pathTarget, IMMEDIATELY, fraction)) 816 | { 817 | // tried to lead through an unwalkable area - clip to walkable space 818 | pathTarget[0] = subjectPos[0] + fraction * ( pathTarget[0] - subjectPos[0] ); 819 | pathTarget[1] = subjectPos[1] + fraction * ( pathTarget[1] - subjectPos[1] ); 820 | pathTarget[2] = subjectPos[2] + fraction * ( pathTarget[2] - subjectPos[2] ); 821 | } 822 | } 823 | 824 | NavArea leadArea = TheNavMesh.GetNearestNavArea_Vec( pathTarget ); 825 | 826 | if (leadArea == NavArea_Null || leadArea.GetZ(pathTarget[0], pathTarget[1]) < pathTarget[2] - npc.GetMaxJumpHeight()) 827 | { 828 | // would fall off a cliff 829 | return subjectPos; 830 | } 831 | 832 | return pathTarget; 833 | } 834 | -------------------------------------------------------------------------------- /npc_playerclone.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #pragma newdecls required 7 | 8 | //Animation 9 | Handle g_hResetSequence; 10 | Handle g_hStudioFrameAdvance; 11 | Handle g_hAllocateLayer; 12 | 13 | //NextBoat 14 | Handle g_hMyNextBotPointer; 15 | Handle g_hGetLocomotionInterface; 16 | 17 | //DHooks 18 | Handle g_hGetStepHeight; 19 | 20 | float g_vecLastClonePos[MAXPLAYERS + 1][3]; 21 | 22 | public Plugin myinfo = 23 | { 24 | name = "[TF2] Player Clone", 25 | author = "Pelipoika", 26 | description = "", 27 | version = "1.0", 28 | url = "http://www.sourcemod.net/plugins.php?author=Pelipoika&search=1" 29 | }; 30 | 31 | public Action test(int client, int args) 32 | { 33 | SDKHook(client, SDKHook_GetMaxHealth, OnPlayerThink); 34 | 35 | ReplyToCommand(client, "[SM] Cloning you"); 36 | 37 | return Plugin_Handled; 38 | } 39 | 40 | public void OnPlayerThink(int client) 41 | { 42 | SpawnClone(client); 43 | } 44 | 45 | stock void SpawnClone(int client) 46 | { 47 | float pos[3]; GetClientAbsOrigin(client, pos); 48 | float ang[3]; GetClientAbsAngles(client, ang); 49 | 50 | float flDistance = GetVectorDistance(g_vecLastClonePos[client], pos, true); 51 | if(flDistance < 500) 52 | return; 53 | 54 | char strModel[PLATFORM_MAX_PATH]; 55 | GetEntPropString(client, Prop_Data, "m_ModelName", strModel, PLATFORM_MAX_PATH); 56 | 57 | int npc = CreateEntityByName("base_boss"); 58 | DispatchKeyValueVector(npc, "origin", pos); 59 | DispatchKeyValueVector(npc, "angles", ang); 60 | DispatchKeyValue(npc, "model", strModel); 61 | DispatchKeyValue(npc, "modelscale", "1.0"); 62 | DispatchKeyValue(npc, "health", "0"); 63 | DispatchSpawn(npc); 64 | 65 | //////////////////////////// 66 | int table = FindStringTable("modelprecache"); 67 | ReadStringTable(table, GetEntProp(GetEntPropEnt(client, Prop_Data, "m_hActiveWeapon"), Prop_Send, "m_iWorldModelIndex"), strModel, PLATFORM_MAX_PATH); 68 | 69 | if(!StrEqual(strModel, "")) 70 | { 71 | int item = CreateEntityByName("prop_dynamic"); 72 | DispatchKeyValue(item, "model", strModel); 73 | DispatchSpawn(item); 74 | 75 | SetEntProp(item, Prop_Send, "m_nSkin", GetEntProp(client, Prop_Send, "m_nSkin")); 76 | SetEntProp(item, Prop_Send, "m_hOwnerEntity", npc); 77 | SetEntProp(item, Prop_Send, "m_fEffects", (1 << 0)|(1 << 9)); 78 | 79 | SetVariantString("!activator"); 80 | AcceptEntityInput(item, "SetParent", npc); 81 | 82 | SetVariantString("head"); 83 | AcceptEntityInput(item, "SetParentAttachmentMaintainOffset"); 84 | } 85 | //////////////////////////// 86 | 87 | //NextBot hack to get it to stay in air 88 | DHookRaw(g_hGetStepHeight, true, SDKCall(g_hGetLocomotionInterface, SDKCall(g_hMyNextBotPointer, npc))); 89 | 90 | SetEntProp(npc, Prop_Data, "m_takedamage", 0); 91 | 92 | SetEntityMoveType(npc, MOVETYPE_NONE); 93 | SetEntityRenderMode(npc, RENDER_NONE); 94 | 95 | SetEntProp(npc, Prop_Data, "m_bloodColor", -1); //Don't bleed 96 | SetEntProp(npc, Prop_Send, "m_nSkin", GetEntProp(client, Prop_Send, "m_nSkin")); //Don't bleed 97 | SetEntPropEnt(npc, Prop_Data, "m_hOwnerEntity", client); 98 | SetEntData(npc, FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 28, false, 4, true); //ResolvePlayerCollisions 99 | 100 | ActivateEntity(npc); 101 | 102 | //Gotta wait a bit 103 | RequestFrame(SetupAnimations, npc); 104 | 105 | g_vecLastClonePos[client] = pos; 106 | } 107 | 108 | public void SetupAnimations(int iEntity) 109 | { 110 | //Allocate 15 layers for max copycat 111 | for (int i = 0; i <= 12; i++) 112 | SDKCall(g_hAllocateLayer, iEntity, 0); 113 | 114 | int client = GetEntPropEnt(iEntity, Prop_Data, "m_hOwnerEntity"); 115 | if(client <= 0) 116 | return; 117 | 118 | SDKCall(g_hResetSequence, iEntity, GetEntProp(client, Prop_Send, "m_nSequence")); 119 | 120 | CBaseAnimatingOverlay overlayP = CBaseAnimatingOverlay(client); 121 | CBaseAnimatingOverlay overlay = CBaseAnimatingOverlay(iEntity); 122 | 123 | for (int i = 0; i <= 12; i++) 124 | { 125 | CAnimationLayer layerP = overlayP.GetLayer(i); 126 | CAnimationLayer layer = overlay.GetLayer(i); 127 | 128 | if(!(layerP.IsActive())) 129 | continue; 130 | 131 | //PrintToServer("%i", i); 132 | 133 | layer.Set(m_fFlags, layerP.Get(m_fFlags)); 134 | layer.Set(m_bSequenceFinished, layerP.Get(m_bSequenceFinished)); 135 | layer.Set(m_bLooping, layerP.Get(m_bLooping)); 136 | layer.Set(m_nSequence, layerP.Get(m_nSequence)); 137 | layer.Set(m_flCycle, layerP.Get(m_flCycle)); 138 | layer.Set(m_flPrevCycle, layerP.Get(m_flPrevCycle)); 139 | layer.Set(m_flWeight, layerP.Get(m_flWeight)); 140 | layer.Set(m_flPlaybackRate, layerP.Get(m_flPlaybackRate)); 141 | layer.Set(m_flBlendIn, layerP.Get(m_flBlendIn)); 142 | layer.Set(m_flBlendOut, layerP.Get(m_flBlendOut)); 143 | layer.Set(m_flKillRate, 0.0); 144 | layer.Set(m_flKillDelay, 50000000000.0); 145 | layer.Set(m_flLayerAnimtime, layerP.Get(m_flLayerAnimtime)); 146 | layer.Set(m_flLayerFadeOuttime, layerP.Get(m_flLayerFadeOuttime)); 147 | layer.Set(m_nActivity, layerP.Get(m_nActivity)); 148 | layer.Set(m_nPriority, layerP.Get(m_nPriority)); 149 | layer.Set(m_nOrder, layerP.Get(m_nOrder)); 150 | } 151 | 152 | for (int i = 0; i < 24; i++) 153 | { 154 | float flValue = GetEntPropFloat(client, Prop_Send, "m_flPoseParameter", i); 155 | SetEntPropFloat(iEntity, Prop_Send, "m_flPoseParameter", flValue, i); 156 | } 157 | 158 | //Done 159 | SetEntityRenderMode(iEntity, RENDER_NORMAL); 160 | 161 | //Play anims a bit so they get played to their set values 162 | SDKCall(g_hStudioFrameAdvance, iEntity); 163 | 164 | SDKHook(iEntity, SDKHook_Think, GroundEntChanged); 165 | 166 | SetEntityFlags(iEntity, FL_ONGROUND); 167 | SetEntPropEnt(iEntity, Prop_Data, "m_hGroundEntity", 0); 168 | } 169 | 170 | public void GroundEntChanged(int iEntity) 171 | { 172 | SetEntityFlags(iEntity, FL_ONGROUND); 173 | SetEntPropEnt(iEntity, Prop_Data, "m_hGroundEntity", 0); 174 | 175 | SetEntPropVector(iEntity, Prop_Data, "m_vecAbsVelocity", NULL_VECTOR); 176 | } 177 | 178 | public void OnPluginStart() 179 | { 180 | RegAdminCmd("sm_clone", test, ADMFLAG_ROOT); 181 | 182 | Handle hConf = LoadGameConfigFile("tf2.pets"); 183 | 184 | //SDKCalls 185 | StartPrepSDKCall(SDKCall_Entity); 186 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::StudioFrameAdvance"); 187 | if ((g_hStudioFrameAdvance = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::StudioFrameAdvance offset!"); 188 | 189 | //ResetSequence( int nSequence ); 190 | StartPrepSDKCall(SDKCall_Entity); 191 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::ResetSequence"); 192 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 193 | if ((g_hResetSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::ResetSequence signature!"); 194 | 195 | StartPrepSDKCall(SDKCall_Entity); 196 | PrepSDKCall_SetSignature(SDKLibrary_Server, "\x55\x8B\xEC\x83\xEC\x18\x8B\xC1\x33\xD2", 10); 197 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //priority 198 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); //return iOpenLayer 199 | if((g_hAllocateLayer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimatingOverlay::AllocateLayer"); 200 | 201 | //MyNextBotPointer( ); 202 | StartPrepSDKCall(SDKCall_Entity); 203 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::MyNextBotPointer"); 204 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 205 | if ((g_hMyNextBotPointer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseEntity::MyNextBotPointer offset!"); 206 | 207 | StartPrepSDKCall(SDKCall_Raw); 208 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetLocomotionInterface"); 209 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 210 | if((g_hGetLocomotionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetLocomotionInterface!"); 211 | 212 | 213 | //DHooks 214 | //Dumbass base_boss quirk 215 | g_hGetStepHeight = DHookCreateEx(hConf, "ILocomotion::GetStepHeight", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetStepHeight); 216 | 217 | delete hConf; 218 | } 219 | 220 | public Address GetLocomotionInterface(int index) { return SDKCall(g_hGetLocomotionInterface, SDKCall(g_hMyNextBotPointer, index)); } 221 | 222 | public MRESReturn ILocomotion_GetStepHeight(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 0.0); return MRES_Supercede; } 223 | 224 | Handle DHookCreateEx(Handle gc, const char[] key, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback) 225 | { 226 | int iOffset = GameConfGetOffset(gc, key); 227 | if(iOffset == -1) 228 | { 229 | SetFailState("Failed to get offset of %s", key); 230 | return null; 231 | } 232 | 233 | return DHookCreate(iOffset, hooktype, returntype, thistype, callback); 234 | } 235 | -------------------------------------------------------------------------------- /npc_sentrybuster.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma newdecls required 8 | 9 | #define MODEL_NPC "models/bots/demo/bot_sentry_buster.mdl" 10 | 11 | ConVar g_hIgnoreOwner; 12 | 13 | Handle g_hMyNextBotPointer; 14 | Handle g_hGetLocomotionInterface; 15 | Handle g_hGetBodyInterface; 16 | Handle g_hGetGroundNormal; 17 | Handle g_hRun; 18 | Handle g_hApproach; 19 | Handle g_hFaceTowards; 20 | Handle g_hResetSequence; 21 | Handle g_hGetStepHeight; 22 | Handle g_hGetGravity; 23 | Handle g_hGetSolidMask; 24 | Handle g_hStudioFrameAdvance; 25 | Handle g_hDispatchAnimEvents; 26 | 27 | Handle g_hGetMaxAcceleration; 28 | Handle g_hShouldCollideWith; 29 | Handle g_hGetGroundSpeed; 30 | Handle g_hGetVectors; 31 | Handle g_hGetGroundMotionVector; 32 | Handle g_hHandleAnimEvent; 33 | 34 | Handle g_hLookupPoseParameter; 35 | Handle g_hSetPoseParameter; 36 | 37 | #define ANIM_MOVE 78 38 | #define ANIM_IDLE 48 39 | #define ANIM_EXPL 103 40 | #define ANIM_FLOA 86 41 | 42 | /* 43 | struct animevent_t 44 | { 45 | int event; 46 | const char *options; 47 | float cycle; 48 | float eventtime; 49 | int type; 50 | CBaseAnimating *pSource; 51 | }; 52 | 53 | https://mxr.alliedmods.net/hl2sdk-sdk2013/source/game/server/hl2/npc_citizen17.cpp#1860 54 | */ 55 | 56 | public Plugin myinfo = 57 | { 58 | name = "[TF2] NextBot Sentry Buster", 59 | author = "Pelipoika", 60 | description = "", 61 | version = "1.0", 62 | url = "http://www.sourcemod.net/plugins.php?author=Pelipoika&search=1" 63 | }; 64 | 65 | public void OnMapStart() 66 | { 67 | PrecacheModel(MODEL_NPC); 68 | 69 | //Absolutely fucking retarded. 70 | PrecacheSound(")mvm/sentrybuster/mvm_sentrybuster_explode.wav"); 71 | PrecacheSound(")mvm/sentrybuster/mvm_sentrybuster_spin.wav"); 72 | PrecacheSound("mvm/sentrybuster/mvm_sentrybuster_loop.wav"); 73 | PrecacheSound(")mvm/sentrybuster/mvm_sentrybuster_intro.wav"); 74 | 75 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_01.wav"); 76 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_02.wav"); 77 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_03.wav"); 78 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_04.wav"); 79 | 80 | PrecacheScriptSound("MVM.SentryBusterExplode"); 81 | PrecacheScriptSound("MVM.SentryBusterSpin"); 82 | PrecacheScriptSound("MVM.SentryBusterLoop"); 83 | PrecacheScriptSound("MVM.SentryBusterIntro"); 84 | PrecacheScriptSound("MVM.SentryBusterStep"); 85 | } 86 | 87 | public void OnEntityDestroyed(int entity) 88 | { 89 | if(entity > MaxClients && entity <= 2048) 90 | { 91 | StopSound(entity, SNDCHAN_STATIC, "mvm/sentrybuster/mvm_sentrybuster_loop.wav"); 92 | } 93 | } 94 | 95 | public Action test(int client, int args) 96 | { 97 | int iTarget = GetClientAimTarget(client, false); 98 | if(IsValidEntity(iTarget) && PF_IsEntityACombatCharacter(iTarget)) 99 | { 100 | SpawnBuster(client, GetEnemyTeam(client), _, iTarget, NULL_VECTOR); 101 | ReplyToCommand(client, "[SM] Spawned a Sentry Buster after whatever you aimed at"); 102 | } 103 | else 104 | { 105 | SpawnBuster(client, GetEnemyTeam(client), _, client, NULL_VECTOR); 106 | ReplyToCommand(client, "[SM] Spawned a Sentry Buster after YOU!"); 107 | } 108 | 109 | return Plugin_Handled; 110 | } 111 | 112 | //sm_buster [blue/red] [health] 113 | public Action test2(int client, int args) 114 | { 115 | if(args < 2) 116 | { 117 | ReplyToCommand(client, "Usage: sm_buster [blue/red] [health]"); 118 | return Plugin_Handled; 119 | } 120 | 121 | char sharedBuff[8]; 122 | GetCmdArg(1, sharedBuff, sizeof(sharedBuff)); 123 | 124 | TFTeam busterTeam = TFTeam_Blue; 125 | if(StrEqual(sharedBuff, "red", false)) 126 | { 127 | busterTeam = TFTeam_Red; 128 | } 129 | else if(StrEqual(sharedBuff, "blu", false) 130 | || StrEqual(sharedBuff, "blue", false)) 131 | { 132 | busterTeam = TFTeam_Blue; 133 | } 134 | else 135 | { 136 | ReplyToCommand(client, "ERROR; Unknown team: \"%s\"", sharedBuff); 137 | return Plugin_Handled; 138 | } 139 | 140 | GetCmdArg(2, sharedBuff, sizeof(sharedBuff)); 141 | 142 | float vAimPos[3]; GetAimPos(client, vAimPos); 143 | 144 | //Deploy 145 | int target = GetClosestBustableTarget(client, vAimPos, busterTeam); 146 | 147 | if(target <= 0) 148 | { 149 | ReplyToCommand(client, "ERROR; Cannot find any bustable target!"); 150 | return Plugin_Handled; 151 | } 152 | 153 | SpawnBuster(client, busterTeam, sharedBuff, target, vAimPos); 154 | 155 | ReplyToCommand(client, "[SM] Spawned a Sentry Buster on \"%s\" [%i] with \"%s\" health after %d", ((busterTeam == TFTeam_Red) ? ("Red") : ("Blue")), busterTeam, sharedBuff, target); 156 | 157 | return Plugin_Handled; 158 | } 159 | 160 | stock void SpawnBuster(int iOwner, TFTeam iSpawnTeam, char[] sHealth = "1000", int iTarget, float vSpawnPoint[3]) 161 | { 162 | float vSpawn[3]; 163 | 164 | if(!IsNullVector(vSpawnPoint)) 165 | { 166 | vSpawn = vSpawnPoint; 167 | } 168 | else if(!GetSpawnPoint(iSpawnTeam, vSpawn)) 169 | { 170 | ReplyToCommand(iOwner, "[SM] Failed to find a spawn point for buster."); 171 | return; 172 | } 173 | 174 | PrintToServer("owner %i target %i team %i", iOwner, iTarget, iSpawnTeam); 175 | 176 | int npc = CreateEntityByName("base_boss"); 177 | DispatchKeyValueVector(npc, "origin", vSpawn); 178 | DispatchKeyValue(npc, "model", MODEL_NPC); 179 | DispatchKeyValue(npc, "modelscale", "1.75"); 180 | DispatchKeyValue(npc, "health", sHealth); 181 | DispatchSpawn(npc); 182 | 183 | //trigger_hurts hurt. 184 | SetEntityFlags(npc, FL_CLIENT); 185 | 186 | //Yucky 187 | SetEntProp(npc, Prop_Data, "m_bloodColor", -1); //Don't bleed 188 | 189 | //Skinny boye 190 | SetEntProp(npc, Prop_Send, "m_nSkin", view_as(iSpawnTeam) - 2); 191 | 192 | //Set team 193 | SetEntProp(npc, Prop_Send, "m_iTeamNum", view_as(iSpawnTeam)); 194 | 195 | //Spawner 196 | SetEntPropEnt(npc, Prop_Data, "m_hOwnerEntity", iOwner); 197 | 198 | //Target subject 199 | SetEntPropEnt(npc, Prop_Data, "m_hEffectEntity", iTarget); 200 | 201 | //Speedy boys 202 | SetEntPropFloat(npc, Prop_Data, "m_speed", 400.0); 203 | 204 | //No pushy 205 | SetEntData(npc, FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 28, false, 4, true); //ResolvePlayerCollisions 206 | 207 | SDKCall(g_hResetSequence, npc, ANIM_IDLE); 208 | 209 | ActivateEntity(npc); 210 | 211 | DHookEntity(g_hHandleAnimEvent, false, npc); 212 | 213 | Address pLoco = GetLocomotionInterface(npc); 214 | DHookRaw(g_hGetStepHeight, true, pLoco); 215 | DHookRaw(g_hGetGravity, true, pLoco); 216 | DHookRaw(g_hGetGroundNormal, true, pLoco); 217 | DHookRaw(g_hShouldCollideWith, true, pLoco); 218 | DHookRaw(g_hGetMaxAcceleration, true, pLoco); 219 | 220 | Address pBody = GetBodyInterface(npc); 221 | DHookRaw(g_hGetSolidMask, true, pBody); 222 | 223 | PF_Create(npc, 18.0, 18.0, 1000.0, 0.6, MASK_PLAYERSOLID, 200.0, 0.5, 1.0, 0.3); 224 | PF_SetGoalEntity(npc, iTarget); 225 | PF_EnableCallback(npc, PFCB_Approach, PluginBot_Approach); 226 | //PF_EnableCallback(npc, PFCB_IsEntityTraversable, PluginBot_Traversible); 227 | PF_EnableCallback(npc, PFCB_GetPathCost, PluginBot_PathCost); 228 | PF_EnableCallback(npc, PFCB_PathFailed, PluginBot_PathFailed); 229 | PF_StartPathing(npc); 230 | 231 | SDKHook(npc, SDKHook_Think, OnBotThink); 232 | SDKHook(npc, SDKHook_OnTakeDamageAlive, OnBotDamaged); 233 | 234 | //Spawn sounds 235 | EmitGameSoundToAll("MVM.SentryBusterIntro", npc); 236 | EmitGameSoundToAll("MVM.SentryBusterLoop", npc); 237 | } 238 | 239 | stock bool GetSpawnPoint(TFTeam iTeam, float vSpawn[3]) 240 | { 241 | int spawn = -1; 242 | while((spawn = FindEntityByClassname(spawn, "info_player_teamspawn")) != -1) 243 | { 244 | bool bDisabled = !!GetEntProp(spawn, Prop_Data, "m_bDisabled"); 245 | TFTeam iSpawnTeam = view_as(GetEntProp(spawn, Prop_Data, "m_iTeamNum")); 246 | 247 | if(!bDisabled && iSpawnTeam == iTeam) 248 | break; 249 | } 250 | 251 | if(spawn == INVALID_ENT_REFERENCE) 252 | return false; 253 | 254 | GetEntPropVector(spawn, Prop_Data, "m_vecAbsOrigin", vSpawn); 255 | 256 | return true; 257 | } 258 | 259 | public Action OnBotDamaged(int victim, int &attacker, int &inflictor, float &damage, int &damagetype) 260 | { 261 | int iHealth = GetEntProp(victim, Prop_Data, "m_iHealth"); 262 | 263 | CreateParticle("bot_impact_heavy", victim); 264 | 265 | if(damage > iHealth) 266 | { 267 | damage = 0.0; 268 | Buster_StartDetonation(victim); 269 | return Plugin_Changed; 270 | } 271 | 272 | return Plugin_Continue; 273 | } 274 | 275 | public void OnBotThink(int iEntity) 276 | { 277 | Address pLocomotion = GetLocomotionInterface(iEntity); 278 | if(pLocomotion == Address_Null) 279 | return; 280 | 281 | Address pStudioHdr = view_as
(GetEntData(iEntity, 283 * 4)); 282 | 283 | int m_iMoveX = SDKCall(g_hLookupPoseParameter, iEntity, pStudioHdr, "move_x"); 284 | int m_iMoveY = SDKCall(g_hLookupPoseParameter, iEntity, pStudioHdr, "move_y"); 285 | 286 | if ( m_iMoveX < 0 || m_iMoveY < 0 ) 287 | return; 288 | 289 | int iSequence = GetEntProp(iEntity, Prop_Send, "m_nSequence"); 290 | 291 | if(iSequence != ANIM_EXPL) 292 | { 293 | float flGroundSpeed = SDKCall(g_hGetGroundSpeed, pLocomotion); 294 | if ( flGroundSpeed != 0.0 ) 295 | { 296 | if(!(GetEntityFlags(iEntity) & FL_ONGROUND)) 297 | { 298 | if(iSequence != ANIM_FLOA) 299 | { 300 | SDKCall(g_hResetSequence, iEntity, ANIM_FLOA); 301 | } 302 | } 303 | else 304 | { 305 | if(iSequence != ANIM_MOVE) 306 | { 307 | SDKCall(g_hResetSequence, iEntity, ANIM_MOVE); 308 | } 309 | } 310 | 311 | float vecForward[3], vecRight[3], vecUp[3]; 312 | SDKCall(g_hGetVectors, iEntity, vecForward, vecRight, vecUp); 313 | 314 | float vecMotion[3] 315 | SDKCall(g_hGetGroundMotionVector, pLocomotion, vecMotion); 316 | 317 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveX, GetVectorDotProduct(vecMotion, vecForward)); 318 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveY, GetVectorDotProduct(vecMotion, vecRight)); 319 | } 320 | else 321 | { 322 | if(iSequence != ANIM_IDLE) 323 | { 324 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveX, 0.0); 325 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveY, 0.0); 326 | 327 | SDKCall(g_hResetSequence, iEntity, ANIM_IDLE); 328 | } 329 | } 330 | 331 | float m_flGroundSpeed = GetEntPropFloat(iEntity, Prop_Data, "m_flGroundSpeed"); 332 | if(m_flGroundSpeed != 0.0) 333 | { 334 | float flReturnValue = clamp(flGroundSpeed / m_flGroundSpeed, -4.0, 12.0); 335 | 336 | SetEntPropFloat(iEntity, Prop_Send, "m_flPlaybackRate", flReturnValue); 337 | } 338 | } 339 | else 340 | { 341 | float flCycle = GetEntPropFloat(iEntity, Prop_Data, "m_flCycle"); 342 | if(flCycle >= 1.0) //PreDetonate animation complete. 343 | { 344 | Buster_Detonate(iEntity); 345 | } 346 | } 347 | 348 | SDKCall(g_hStudioFrameAdvance, iEntity); 349 | SDKCall(g_hDispatchAnimEvents, iEntity, iEntity); 350 | } 351 | 352 | //public bool PluginBot_Traversible(int bot_entidx, int other_entidx, TraverseWhenType when) { return true; } 353 | 354 | public void PluginBot_PathFailed(int bot_entidx) 355 | { 356 | PF_DisableCallback(bot_entidx, PFCB_PathFailed); 357 | PF_StopPathing(bot_entidx); 358 | 359 | Buster_StartDetonation(bot_entidx); 360 | } 361 | 362 | public float PluginBot_PathCost(int bot_entidx, NavArea area, NavArea from_area, float length) 363 | { 364 | float dist; 365 | if (length != 0.0) 366 | { 367 | dist = length; 368 | } 369 | else 370 | { 371 | float vecCenter[3], vecFromCenter[3]; 372 | area.GetCenter(vecCenter); 373 | from_area.GetCenter(vecFromCenter); 374 | 375 | float vecSubtracted[3] 376 | SubtractVectors(vecCenter, vecFromCenter, vecSubtracted) 377 | 378 | dist = GetVectorLength(vecSubtracted); 379 | } 380 | 381 | float multiplier = 1.0; 382 | 383 | int seed = RoundToFloor(GetGameTime() * 0.1) + 1; 384 | seed *= area.GetID(); 385 | seed *= bot_entidx; 386 | 387 | multiplier += (Cosine(float(seed)) + 1.0) * 10.0; 388 | 389 | float cost = dist * multiplier; 390 | 391 | return from_area.GetCostSoFar() + cost; 392 | } 393 | 394 | public void PluginBot_Approach(int bot_entidx, const float vec[3]) 395 | { 396 | Address pLocomotion = GetLocomotionInterface(bot_entidx); 397 | 398 | SDKCall(g_hRun, pLocomotion); 399 | SDKCall(g_hApproach, pLocomotion, vec, 1.0); 400 | 401 | ConVar flTurnRate = FindConVar("tf_base_boss_max_turn_rate"); 402 | float flPrevValue = flTurnRate.FloatValue; 403 | flTurnRate.FloatValue = 200.0; 404 | SDKCall(g_hFaceTowards, pLocomotion, vec); 405 | flTurnRate.FloatValue = flPrevValue; 406 | 407 | float vOrigin[3]; 408 | GetEntPropVector(bot_entidx, Prop_Data, "m_vecAbsOrigin", vOrigin); 409 | 410 | int iGoalEntity = GetEntPropEnt(bot_entidx, Prop_Data, "m_hEffectEntity"); 411 | if(iGoalEntity != INVALID_ENT_REFERENCE) 412 | { 413 | float vTargetPos[3]; 414 | GetEntPropVector(iGoalEntity, Prop_Data, "m_vecAbsOrigin", vTargetPos); 415 | 416 | if(GetVectorDistance(vOrigin, vTargetPos) <= 99.0) 417 | { 418 | Buster_StartDetonation(bot_entidx); 419 | } 420 | } 421 | } 422 | 423 | void Buster_StartDetonation(int bot) 424 | { 425 | //Start Detonation 426 | EmitGameSoundToAll("MVM.SentryBusterSpin", bot); 427 | SDKCall(g_hResetSequence, bot, ANIM_EXPL); 428 | SDKCall(g_hResetSequence, bot, ANIM_EXPL); 429 | PF_StopPathing(bot); 430 | 431 | SetEntProp(bot, Prop_Data, "m_takedamage", 0); 432 | SetEntPropFloat(bot, Prop_Send, "m_flPlaybackRate", 1.0); 433 | 434 | StopSound(bot, SNDCHAN_STATIC, "mvm/sentrybuster/mvm_sentrybuster_loop.wav"); 435 | 436 | SDKUnhook(bot, SDKHook_OnTakeDamageAlive, OnBotDamaged); 437 | } 438 | 439 | void Buster_Detonate(int bot) 440 | { 441 | //Finish Detonation 442 | float vPos[3]; 443 | GetEntPropVector(bot, Prop_Data, "m_vecAbsOrigin", vPos); 444 | vPos[2] += 64.0; 445 | 446 | CreateParticle("fluidSmokeExpl_ring_mvm", bot); 447 | Explode(vPos, 5000.0, 300.0, "explosionTrail_seeds_mvm", "MVM.SentryBusterExplode"); 448 | 449 | StopSound(bot, SNDCHAN_STATIC, "mvm/sentrybuster/mvm_sentrybuster_loop.wav"); 450 | 451 | AcceptEntityInput(bot, "Kill"); 452 | } 453 | 454 | public MRESReturn IBody_GetSolidMask(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 0x203400B); return MRES_Supercede; } 455 | public MRESReturn ILocomotion_GetGravity(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 800.0); return MRES_Supercede; } 456 | public MRESReturn ILocomotion_GetStepHeight(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 20.0); return MRES_Supercede; } 457 | public MRESReturn ILocomotion_GetMaxAcceleration(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 1700.0); return MRES_Supercede; } 458 | public MRESReturn ILocomotion_ShouldCollideWith(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, false); return MRES_Supercede; } 459 | public MRESReturn ILocomotion_GetGroundNormal(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturnVector(hReturn, view_as( { 0.0, 0.0, 1.0 } )); return MRES_Supercede; } 460 | 461 | public MRESReturn CBaseAnimating_HandleAnimEvent(int pThis, Handle hParams) 462 | { 463 | int event = DHookGetParamObjectPtrVar(hParams, 1, 0, ObjectValueType_Int); 464 | if(event == 7001) //Footstep 465 | { 466 | EmitGameSoundToAll("MVM.SentryBusterStep", pThis); 467 | } 468 | } 469 | 470 | public float clamp(float a, float b, float c) { return (a > c ? c : (a < b ? b : a)); } 471 | 472 | public Address GetLocomotionInterface(int index) { return SDKCall(g_hGetLocomotionInterface, SDKCall(g_hMyNextBotPointer, index)); } 473 | public Address GetBodyInterface(int index) { return SDKCall(g_hGetBodyInterface, SDKCall(g_hMyNextBotPointer, index)); } 474 | 475 | stock void Explode(float flPos[3], float flDamage, float flRadius, const char[] strParticle, const char[] strSound) 476 | { 477 | int iBomb = CreateEntityByName("tf_generic_bomb"); 478 | DispatchKeyValueVector(iBomb, "origin", flPos); 479 | DispatchKeyValueFloat(iBomb, "damage", flDamage); 480 | DispatchKeyValueFloat(iBomb, "radius", flRadius); 481 | DispatchKeyValue(iBomb, "health", "1"); 482 | DispatchKeyValue(iBomb, "explode_particle", strParticle); 483 | DispatchKeyValue(iBomb, "sound", strSound); 484 | DispatchSpawn(iBomb); 485 | 486 | AcceptEntityInput(iBomb, "Detonate"); 487 | } 488 | 489 | stock void CreateParticle(char[] particle, int iEntity) 490 | { 491 | int tblidx = FindStringTable("ParticleEffectNames"); 492 | char tmp[256]; 493 | int count = GetStringTableNumStrings(tblidx); 494 | int stridx = INVALID_STRING_INDEX; 495 | 496 | for(int i = 0; i < count; i++) 497 | { 498 | ReadStringTable(tblidx, i, tmp, sizeof(tmp)); 499 | if(StrEqual(tmp, particle, false)) 500 | { 501 | stridx = i; 502 | break; 503 | } 504 | } 505 | 506 | float vPos[3], vAng[3]; 507 | GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", vPos); 508 | GetEntPropVector(iEntity, Prop_Data, "m_angRotation", vAng); 509 | 510 | TE_Start("TFParticleEffect"); 511 | TE_WriteFloat("m_vecOrigin[0]", vPos[0]); 512 | TE_WriteFloat("m_vecOrigin[1]", vPos[1]); 513 | TE_WriteFloat("m_vecOrigin[2]", vPos[2]); 514 | TE_WriteVector("m_vecAngles", vAng); 515 | TE_WriteNum("m_iParticleSystemIndex", stridx); 516 | TE_WriteNum("entindex", iEntity); 517 | TE_WriteNum("m_iAttachType", 0); 518 | TE_SendToAll(); 519 | } 520 | 521 | stock bool GetAimPos(int client, float vecPos[3]) 522 | { 523 | float StartOrigin[3], Angles[3]; 524 | GetClientEyeAngles(client, Angles); 525 | GetClientEyePosition(client, StartOrigin); 526 | 527 | Handle TraceRay = TR_TraceRayFilterEx(StartOrigin, Angles, MASK_ALL, RayType_Infinite, ExcludeFilter, client); 528 | if (TR_DidHit(TraceRay)) 529 | { 530 | TR_GetEndPosition(vecPos, TraceRay); 531 | } 532 | 533 | delete TraceRay; 534 | } 535 | 536 | public bool ExcludeFilter(int entityhit, int mask, any entity) 537 | { 538 | if (entityhit > MaxClients && entityhit != entity) 539 | { 540 | return true; 541 | } 542 | 543 | return false; 544 | } 545 | 546 | stock TFTeam GetEnemyTeam(int ent) 547 | { 548 | TFTeam enemy_team = TF2_GetClientTeam(ent); 549 | switch(enemy_team) 550 | { 551 | case TFTeam_Red: enemy_team = TFTeam_Blue; 552 | case TFTeam_Blue: enemy_team = TFTeam_Red; 553 | } 554 | 555 | return enemy_team; 556 | } 557 | 558 | stock int GetClosestBustableTarget(int owner, float vSpawn[3], TFTeam iTeam) 559 | { 560 | int ClosestEntity = 0; 561 | float flClosestDistance = 99999.0; 562 | 563 | for (int i = 1; i <= MaxClients; i++) 564 | { 565 | if (!IsClientInGame(i)) 566 | continue; 567 | 568 | if (!IsPlayerAlive(i)) 569 | continue; 570 | 571 | //Ignore owner if sm_buster_ignore_owner is true 572 | if(g_hIgnoreOwner.BoolValue && i == owner) 573 | continue; 574 | 575 | if (TF2_GetClientTeam(i) == iTeam) 576 | continue; 577 | 578 | float flDistance = GetVectorDistance(vSpawn, GetAbsOrigin(i)); 579 | if (flClosestDistance > flDistance) 580 | { 581 | flClosestDistance = flDistance; 582 | ClosestEntity = i; 583 | } 584 | } 585 | 586 | int index = -1; 587 | while ((index = FindEntityByClassname(index, "*")) != INVALID_ENT_REFERENCE) 588 | { 589 | if(index <= MaxClients || index > 2048) 590 | continue; 591 | 592 | if(!IsValidEntity(index)) 593 | continue; 594 | 595 | if(!PF_IsEntityACombatCharacter(index)) 596 | continue; 597 | 598 | if (GetEntProp(index, Prop_Send, "m_iTeamNum") == view_as(iTeam)) 599 | continue; 600 | 601 | float flDistance = GetVectorDistance(vSpawn, GetAbsOrigin(index)); 602 | if (flClosestDistance > flDistance) 603 | { 604 | flClosestDistance = flDistance; 605 | ClosestEntity = index; 606 | } 607 | } 608 | 609 | return ClosestEntity; 610 | } 611 | 612 | stock float[] GetAbsOrigin(int client) 613 | { 614 | if(client <= 0) 615 | return NULL_VECTOR; 616 | 617 | float v[3]; 618 | GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", v); 619 | return v; 620 | } 621 | 622 | public void OnPluginStart() 623 | { 624 | g_hIgnoreOwner = CreateConVar("sm_buster_ignore_owner", "1", "Sentry Buster will ignore owner upon spawning when choosing target", _, true, 0.0, true, 1.0); 625 | 626 | RegAdminCmd("sm_bustthat", test, ADMFLAG_ROOT); 627 | 628 | RegAdminCmd("sm_bust", test2, ADMFLAG_ROOT); 629 | RegAdminCmd("sm_buster", test2, ADMFLAG_ROOT); 630 | 631 | Handle hConf = LoadGameConfigFile("tf2.pets"); 632 | 633 | //SDKCalls 634 | StartPrepSDKCall(SDKCall_Entity); 635 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::StudioFrameAdvance"); 636 | if ((g_hStudioFrameAdvance = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::StudioFrameAdvance offset!"); 637 | 638 | StartPrepSDKCall(SDKCall_Entity); 639 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::DispatchAnimEvents"); 640 | PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); 641 | if ((g_hDispatchAnimEvents = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::DispatchAnimEvents offset!"); 642 | 643 | //ResetSequence( int nSequence ); 644 | StartPrepSDKCall(SDKCall_Entity); 645 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::ResetSequence"); 646 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 647 | if ((g_hResetSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::ResetSequence signature!"); 648 | 649 | //MyNextBotPointer( ); 650 | StartPrepSDKCall(SDKCall_Entity); 651 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::MyNextBotPointer"); 652 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 653 | if ((g_hMyNextBotPointer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseEntity::MyNextBotPointer offset!"); 654 | 655 | StartPrepSDKCall(SDKCall_Raw); 656 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetLocomotionInterface"); 657 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 658 | if((g_hGetLocomotionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetLocomotionInterface!"); 659 | 660 | StartPrepSDKCall(SDKCall_Raw); 661 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetBodyInterface"); 662 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 663 | if((g_hGetBodyInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetBodyInterface!"); 664 | 665 | StartPrepSDKCall(SDKCall_Raw); 666 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Run"); 667 | if((g_hRun = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Run!"); 668 | 669 | StartPrepSDKCall(SDKCall_Raw); 670 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Approach"); 671 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 672 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 673 | if((g_hApproach = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Approach!"); 674 | 675 | StartPrepSDKCall(SDKCall_Raw); 676 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::FaceTowards"); 677 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 678 | if((g_hFaceTowards = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::FaceTowards!"); 679 | 680 | //ILocomotion::GetGroundSpeed() 681 | StartPrepSDKCall(SDKCall_Raw); 682 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundSpeed"); 683 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 684 | if((g_hGetGroundSpeed = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundSpeed!"); 685 | 686 | //ILocomotion::GetGroundMotionVector() 687 | StartPrepSDKCall(SDKCall_Raw); 688 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundMotionVector"); 689 | PrepSDKCall_SetReturnInfo(SDKType_Vector, SDKPass_ByRef); 690 | if((g_hGetGroundMotionVector = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundMotionVector!"); 691 | 692 | //CBaseEntity::GetVectors(Vector*, Vector*, Vector*) 693 | StartPrepSDKCall(SDKCall_Entity); 694 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::GetVectors"); 695 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 696 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 697 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 698 | if((g_hGetVectors = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for CBaseEntity::GetVectors!"); 699 | 700 | //SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); 701 | StartPrepSDKCall(SDKCall_Entity); 702 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::SetPoseParameter"); 703 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 704 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 705 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 706 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 707 | if((g_hSetPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::SetPoseParameter"); 708 | 709 | //LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); 710 | StartPrepSDKCall(SDKCall_Entity); 711 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::LookupPoseParameter"); 712 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 713 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); 714 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 715 | if((g_hLookupPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::LookupPoseParameter"); 716 | 717 | //DHooks 718 | g_hGetSolidMask = DHookCreateEx(hConf, "IBody::GetSolidMask", HookType_Raw, ReturnType_Int, ThisPointer_Address, IBody_GetSolidMask); 719 | g_hGetStepHeight = DHookCreateEx(hConf, "ILocomotion::GetStepHeight", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetStepHeight); 720 | g_hGetGravity = DHookCreateEx(hConf, "ILocomotion::GetGravity", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetGravity); 721 | g_hGetGroundNormal = DHookCreateEx(hConf, "ILocomotion::GetGroundNormal", HookType_Raw, ReturnType_VectorPtr, ThisPointer_Address, ILocomotion_GetGroundNormal); 722 | g_hGetMaxAcceleration = DHookCreateEx(hConf, "ILocomotion::GetMaxAcceleration", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetMaxAcceleration); 723 | 724 | g_hShouldCollideWith = DHookCreateEx(hConf, "ILocomotion::ShouldCollideWith", HookType_Raw, ReturnType_Bool, ThisPointer_Address, ILocomotion_ShouldCollideWith); 725 | DHookAddParam(g_hShouldCollideWith, HookParamType_CBaseEntity); 726 | 727 | g_hHandleAnimEvent = DHookCreateEx(hConf, "CBaseAnimating::HandleAnimEvent", HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, CBaseAnimating_HandleAnimEvent); 728 | DHookAddParam(g_hHandleAnimEvent, HookParamType_ObjectPtr, -1); 729 | 730 | delete hConf; 731 | } 732 | 733 | //I should of have done this long ago. 734 | Handle DHookCreateEx(Handle gc, const char[] key, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback) 735 | { 736 | int iOffset = GameConfGetOffset(gc, key); 737 | if(iOffset == -1) 738 | { 739 | SetFailState("Failed to get offset of %s", key); 740 | return null; 741 | } 742 | 743 | return DHookCreate(iOffset, hooktype, returntype, thistype, callback); 744 | } -------------------------------------------------------------------------------- /npc_soccer.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma newdecls required 8 | 9 | 10 | //SDKCalls 11 | Handle g_hMyNextBotPointer; 12 | Handle g_hGetLocomotionInterface; 13 | Handle g_hGetBodyInterface; 14 | Handle g_hGetVisionInterface; 15 | Handle g_hRun; 16 | Handle g_hApproach; 17 | Handle g_hFaceTowards; 18 | Handle g_hResetSequence; 19 | Handle g_hStudioFrameAdvance; 20 | Handle g_hJump; 21 | Handle g_hDispatchAnimEvents; 22 | Handle g_hGetMaxAcceleration; 23 | Handle g_hGetGroundSpeed; 24 | Handle g_hGetVectors; 25 | Handle g_hGetGroundMotionVector; 26 | Handle g_hLookupPoseParameter; 27 | Handle g_hSetPoseParameter; 28 | Handle g_hGetPoseParameter; 29 | Handle g_hLookupSequence; 30 | Handle g_hSDKWorldSpaceCenter; 31 | Handle g_hStudio_FindAttachment; 32 | Handle g_hGetAttachment; 33 | Handle g_hAddGestureSequence; 34 | 35 | 36 | //Stuck detection 37 | Handle g_hStuckMonitor; 38 | Handle g_hClearStuckStatus; 39 | Handle g_hIsStuck; 40 | 41 | //DHooks 42 | Handle g_hGetStepHeight; 43 | Handle g_hGetGravity; 44 | Handle g_hGetGroundNormal; 45 | Handle g_hShouldCollideWith; 46 | Handle g_hGetSolidMask; 47 | 48 | public Plugin myinfo = 49 | { 50 | name = "[TF2] Balls", 51 | author = "Pelipoika", 52 | description = "", 53 | version = "1.0", 54 | url = "" 55 | }; 56 | 57 | public void OnPluginStart() 58 | { 59 | RegAdminCmd("sm_spawnball", Command_SpawnBall, ADMFLAG_ROOT); 60 | RegAdminCmd("sm_spawnplayer", Command_SpawnPlayer, ADMFLAG_ROOT); 61 | 62 | Handle hConf = LoadGameConfigFile("tf2.pets"); 63 | 64 | //SDKCalls 65 | //This call is used to get an entitys center position 66 | StartPrepSDKCall(SDKCall_Entity); 67 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::WorldSpaceCenter"); 68 | PrepSDKCall_SetReturnInfo(SDKType_Vector, SDKPass_ByRef); 69 | if ((g_hSDKWorldSpaceCenter = EndPrepSDKCall()) == null) SetFailState("Failed to create SDKCall for CBaseEntity::WorldSpaceCenter offset!"); 70 | 71 | //========================================================= 72 | // StudioFrameAdvance - advance the animation frame up some interval (default 0.1) into the future 73 | //========================================================= 74 | StartPrepSDKCall(SDKCall_Entity); 75 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::StudioFrameAdvance"); 76 | if ((g_hStudioFrameAdvance = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::StudioFrameAdvance offset!"); 77 | 78 | //ResetSequence( int nSequence ); 79 | StartPrepSDKCall(SDKCall_Entity); 80 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::ResetSequence"); 81 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 82 | if ((g_hResetSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::ResetSequence signature!"); 83 | 84 | StartPrepSDKCall(SDKCall_Entity); 85 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::MyNextBotPointer"); 86 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 87 | if ((g_hMyNextBotPointer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseEntity::MyNextBotPointer offset!"); 88 | 89 | StartPrepSDKCall(SDKCall_Raw); 90 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetLocomotionInterface"); 91 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 92 | if((g_hGetLocomotionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetLocomotionInterface!"); 93 | 94 | StartPrepSDKCall(SDKCall_Raw); 95 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetBodyInterface"); 96 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 97 | if((g_hGetBodyInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetBodyInterface!"); 98 | 99 | StartPrepSDKCall(SDKCall_Raw); 100 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetVisionInterface"); 101 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 102 | if((g_hGetVisionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetVisionInterface!"); 103 | 104 | StartPrepSDKCall(SDKCall_Raw); 105 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Run"); 106 | if((g_hRun = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Run!"); 107 | 108 | StartPrepSDKCall(SDKCall_Raw); 109 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Approach"); 110 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 111 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 112 | if((g_hApproach = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Approach!"); 113 | 114 | StartPrepSDKCall(SDKCall_Raw); 115 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::FaceTowards"); 116 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 117 | if((g_hFaceTowards = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::FaceTowards!"); 118 | 119 | StartPrepSDKCall(SDKCall_Raw); 120 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Jump"); 121 | if((g_hJump = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Jump!"); 122 | 123 | StartPrepSDKCall(SDKCall_Entity); 124 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::DispatchAnimEvents"); 125 | PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); 126 | if ((g_hDispatchAnimEvents = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::DispatchAnimEvents offset!"); 127 | 128 | //ILocomotion::GetGroundSpeed() 129 | StartPrepSDKCall(SDKCall_Raw); 130 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundSpeed"); 131 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 132 | if((g_hGetGroundSpeed = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundSpeed!"); 133 | 134 | //ILocomotion::GetGroundMotionVector() 135 | StartPrepSDKCall(SDKCall_Raw); 136 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundMotionVector"); 137 | PrepSDKCall_SetReturnInfo(SDKType_Vector, SDKPass_ByRef); 138 | if((g_hGetGroundMotionVector = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundMotionVector!"); 139 | 140 | //ILocomotion::IsStuck() 141 | StartPrepSDKCall(SDKCall_Raw); 142 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::IsStuck"); 143 | PrepSDKCall_SetReturnInfo(SDKType_Bool, SDKPass_Plain); 144 | if((g_hIsStuck = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::IsStuck!"); 145 | 146 | //ILocomotion::ClearStuckStatus(char const* reason) 147 | StartPrepSDKCall(SDKCall_Raw); 148 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::ClearStuckStatus"); 149 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); 150 | if((g_hClearStuckStatus = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::ClearStuckStatus!"); 151 | 152 | //ILocomotion::StuckMonitor 153 | StartPrepSDKCall(SDKCall_Raw); 154 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::StuckMonitor"); 155 | if((g_hStuckMonitor = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::StuckMonitor!"); 156 | 157 | //CBaseEntity::GetVectors(Vector*, Vector*, Vector*) 158 | StartPrepSDKCall(SDKCall_Entity); 159 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::GetVectors"); 160 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 161 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 162 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 163 | if((g_hGetVectors = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for CBaseEntity::GetVectors!"); 164 | 165 | //CBaseAnimating::GetPoseParameter(int iParameter) 166 | StartPrepSDKCall(SDKCall_Entity); 167 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::GetPoseParameter"); 168 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 169 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 170 | if((g_hGetPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::GetPoseParameter"); 171 | 172 | //SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); 173 | StartPrepSDKCall(SDKCall_Entity); 174 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::SetPoseParameter"); 175 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 176 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 177 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 178 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 179 | if((g_hSetPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::SetPoseParameter"); 180 | 181 | //LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); 182 | StartPrepSDKCall(SDKCall_Entity); 183 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::LookupPoseParameter"); 184 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 185 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); 186 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 187 | if((g_hLookupPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::LookupPoseParameter"); 188 | 189 | //CBaseAnimatingOverlay::AddGestureSequence( int nSequence, bool autokill ) 190 | StartPrepSDKCall(SDKCall_Entity); 191 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimatingOverlay::AddGestureSequence"); 192 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 193 | PrepSDKCall_AddParameter(SDKType_Bool, SDKPass_Plain); 194 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 195 | if((g_hAddGestureSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimatingOverlay::AddGestureSequence"); 196 | 197 | //----------------------------------------------------------------------------- 198 | // Purpose: Looks up a sequence by sequence name first, then by activity name. 199 | // Input : label - The sequence name or activity name to look up. 200 | // Output : Returns the sequence index of the matching sequence, or ACT_INVALID. 201 | //----------------------------------------------------------------------------- 202 | //LookupSequence( CStudioHdr *pStudioHdr, const char *label ); 203 | StartPrepSDKCall(SDKCall_Static); 204 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "LookupSequence"); 205 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //pStudioHdr 206 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); //label 207 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); //return index 208 | if((g_hLookupSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for LookupSequence"); 209 | 210 | //----------------------------------------------------------------------------- 211 | // Purpose: lookup attachment by name 212 | //----------------------------------------------------------------------------- 213 | StartPrepSDKCall(SDKCall_Static); 214 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "Studio_FindAttachment"); 215 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //pStudioHdr 216 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); //pAttachmentName 217 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); //return index 218 | if((g_hStudio_FindAttachment = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for Studio_FindAttachment"); 219 | 220 | //----------------------------------------------------------------------------- 221 | // Purpose: Returns the world location and world angles of an attachment 222 | // Input : attachment name 223 | // Output : location and angles 224 | //----------------------------------------------------------------------------- 225 | StartPrepSDKCall(SDKCall_Entity); 226 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::GetAttachment"); 227 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); //iAttachment 228 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); //absOrigin 229 | PrepSDKCall_AddParameter(SDKType_QAngle, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); //absAngles 230 | if((g_hGetAttachment = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::GetAttachment"); 231 | 232 | //DHooks 233 | g_hGetStepHeight = DHookCreateEx(hConf, "ILocomotion::GetStepHeight", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetStepHeight); 234 | g_hGetGravity = DHookCreateEx(hConf, "ILocomotion::GetGravity", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetGravity); 235 | g_hGetGroundNormal = DHookCreateEx(hConf, "ILocomotion::GetGroundNormal", HookType_Raw, ReturnType_VectorPtr, ThisPointer_Address, ILocomotion_GetGroundNormal); 236 | g_hGetMaxAcceleration = DHookCreateEx(hConf, "ILocomotion::GetMaxAcceleration", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetMaxAcceleration); 237 | g_hShouldCollideWith = DHookCreateEx(hConf, "ILocomotion::ShouldCollideWith", HookType_Raw, ReturnType_Bool, ThisPointer_Address, ILocomotion_ShouldCollideWith); 238 | DHookAddParam(g_hShouldCollideWith, HookParamType_CBaseEntity); 239 | 240 | g_hGetSolidMask = DHookCreateEx(hConf, "IBody::GetSolidMask", HookType_Raw, ReturnType_Int, ThisPointer_Address, IBody_GetSolidMask); 241 | 242 | delete hConf; 243 | } 244 | 245 | methodmap BaseNPC 246 | { 247 | public BaseNPC(float vecPos[3], float vecAng[3], const char[] model, const char[] modelscale = "1.0", const char[] health = "5000", bool bGroundNormal = true) 248 | { 249 | int npc = CreateEntityByName("base_boss"); 250 | DispatchKeyValueVector(npc, "origin", vecPos); 251 | DispatchKeyValueVector(npc, "angles", vecAng); 252 | DispatchKeyValue(npc, "model", model); 253 | DispatchKeyValue(npc, "modelscale", modelscale); 254 | DispatchKeyValue(npc, "health", health); 255 | DispatchSpawn(npc); 256 | 257 | //CreateParticle("ghost_appearation", vecPos, vecAng); 258 | 259 | Address pNB = SDKCall(g_hMyNextBotPointer, npc); 260 | Address pLocomotion = SDKCall(g_hGetLocomotionInterface, pNB); 261 | 262 | DHookRaw(g_hGetStepHeight, true, pLocomotion); 263 | DHookRaw(g_hGetGravity, true, pLocomotion); 264 | DHookRaw(g_hShouldCollideWith, true, pLocomotion); 265 | DHookRaw(g_hGetMaxAcceleration, true, pLocomotion); 266 | 267 | if(bGroundNormal) 268 | DHookRaw(g_hGetGroundNormal, true, pLocomotion) 269 | 270 | Address pBody = SDKCall(g_hGetBodyInterface, pNB); 271 | 272 | //Collide with the correct stuff 273 | DHookRaw(g_hGetSolidMask, true, pBody); 274 | 275 | //trigger_hurts hurt and spawn doors open for us, etc. 276 | SetEntityFlags(npc, FL_CLIENT|FL_FAKECLIENT|FL_NPC); 277 | 278 | //Don't ResolvePlayerCollisions. 279 | SetEntData(npc, FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 28, false, 4, true); 280 | 281 | //Don't bleed. 282 | SetEntProp(npc, Prop_Data, "m_bloodColor", -1); 283 | 284 | ActivateEntity(npc); 285 | 286 | return view_as(npc); 287 | } 288 | 289 | property int index 290 | { 291 | public get() 292 | { 293 | return view_as(this); 294 | } 295 | } 296 | public Address GetLocomotionInterface() 297 | { 298 | Address pNB = SDKCall(g_hMyNextBotPointer, this.index); 299 | return SDKCall(g_hGetLocomotionInterface, pNB); 300 | } 301 | public Address GetBodyInterface() 302 | { 303 | Address pNB = SDKCall(g_hMyNextBotPointer, this.index); 304 | return SDKCall(g_hGetBodyInterface, pNB); 305 | } 306 | public Address GetVisionInterface() 307 | { 308 | Address pNB = SDKCall(g_hMyNextBotPointer, this.index); 309 | return SDKCall(g_hGetVisionInterface, pNB); 310 | } 311 | public bool IsStuck() 312 | { 313 | return SDKCall(g_hIsStuck, this.GetLocomotionInterface()); 314 | } 315 | public int GetTeam() 316 | { 317 | return GetEntProp(this.index, Prop_Send, "m_iTeamNum"); 318 | } 319 | public Address GetStudioHdr() 320 | { 321 | if(IsValidEntity(this.index)) 322 | { 323 | return view_as
(GetEntData(this.index, 283 * 4)); 324 | } 325 | 326 | return Address_Null; 327 | } 328 | public float GetPoseParameter(int iParameter) 329 | { 330 | return SDKCall(g_hGetPoseParameter, this.index, iParameter); 331 | } 332 | public void SetPoseParameter(int iParameter, float value) 333 | { 334 | Address pStudioHdr = this.GetStudioHdr(); 335 | if(pStudioHdr == Address_Null) 336 | return; 337 | 338 | SDKCall(g_hSetPoseParameter, this.index, pStudioHdr, iParameter, value); 339 | } 340 | public int FindAttachment(const char[] pAttachmentName) 341 | { 342 | Address pStudioHdr = this.GetStudioHdr(); 343 | if(pStudioHdr == Address_Null) 344 | return -1; 345 | 346 | return SDKCall(g_hStudio_FindAttachment, pStudioHdr, pAttachmentName) + 1; 347 | } 348 | public void GetAttachment(const char[] szName, float absOrigin[3], float absAngles[3]) 349 | { 350 | SDKCall(g_hGetAttachment, this.index, this.FindAttachment(szName), absOrigin, absAngles); 351 | } 352 | public int LookupPoseParameter(const char[] szName) 353 | { 354 | Address pStudioHdr = this.GetStudioHdr(); 355 | if(pStudioHdr == Address_Null) 356 | return -1; 357 | 358 | return SDKCall(g_hLookupPoseParameter, this.index, pStudioHdr, szName); 359 | } 360 | public int LookupSequence(const char[] anim) 361 | { 362 | Address pStudioHdr = this.GetStudioHdr(); 363 | if(pStudioHdr == Address_Null) 364 | return -1; 365 | 366 | return SDKCall(g_hLookupSequence, pStudioHdr, anim); 367 | } 368 | public void SetAnimation(const char[] anim) 369 | { 370 | int iSequence = this.LookupSequence(anim); 371 | if(iSequence >= 0) 372 | SDKCall(g_hResetSequence, this.index, iSequence); 373 | } 374 | public void PlayGesture(const char[] anim) 375 | { 376 | int iSequence = this.LookupSequence(anim); 377 | if(iSequence < 0) 378 | return; 379 | 380 | SDKCall(g_hAddGestureSequence, this.index, iSequence, true); 381 | } 382 | public void CreatePather(int iTarget, float flStep, float flJump, float flDrop, int iSolid, float flAhead, float flRePath, float flHull) 383 | { 384 | PF_Create(this.index, flStep, flJump, flDrop, 0.6, iSolid, flAhead, flRePath, flHull); 385 | PF_EnableCallback(this.index, PFCB_Approach, PluginBot_Approach); 386 | PF_EnableCallback(this.index, PFCB_GetPathCost, PluginBot_PathCost); 387 | 388 | if(IsValidEntity(iTarget) && PF_IsEntityACombatCharacter(iTarget)) 389 | { 390 | PF_SetGoalEntity(this.index, iTarget); 391 | } 392 | } 393 | public void Approach(const float vecGoal[3]) 394 | { 395 | SDKCall(g_hApproach, this.GetLocomotionInterface(), vecGoal, 0.1); 396 | } 397 | public void FaceTowards(const float vecGoal[3]) 398 | { 399 | //Sad! 400 | ConVar flTurnRate = FindConVar("tf_base_boss_max_turn_rate"); 401 | float flPrevValue = flTurnRate.FloatValue; 402 | 403 | flTurnRate.FloatValue = 200.0; 404 | SDKCall(g_hFaceTowards, this.GetLocomotionInterface(), vecGoal); 405 | flTurnRate.FloatValue = flPrevValue; 406 | } 407 | public void Jump() 408 | { 409 | SDKCall(g_hJump, this.GetLocomotionInterface()); 410 | } 411 | public void Update() 412 | { 413 | SDKCall(g_hRun, this.GetLocomotionInterface()); 414 | SDKCall(g_hStudioFrameAdvance, this.index); 415 | SDKCall(g_hDispatchAnimEvents, this.index, this.index); 416 | SDKCall(g_hStuckMonitor, this.GetLocomotionInterface()); 417 | 418 | bool bStuck = this.IsStuck(); 419 | if(bStuck) 420 | { 421 | float there[3]; 422 | bool bYes = false; 423 | 424 | if (PF_GetFutureSegment(this.index, 1, there)) 425 | { 426 | bYes = true; 427 | } 428 | else if(PF_GetFutureSegment(this.index, 0, there)) 429 | { 430 | bYes = true; 431 | } 432 | 433 | if(bYes) 434 | { 435 | SDKCall(g_hClearStuckStatus, this.GetLocomotionInterface(), "Un-Stuck"); 436 | there[2] += 18.0; 437 | TeleportEntity(this.index, there, NULL_VECTOR, NULL_VECTOR); 438 | } 439 | else 440 | { 441 | NavArea area = TheNavMesh.GetNearestNavArea_Vec(WorldSpaceCenter(this.index), true); 442 | if(area != NavArea_Null) 443 | { 444 | SDKCall(g_hClearStuckStatus, this.GetLocomotionInterface(), "Un-Stuck"); 445 | float center[3]; 446 | area.GetCenter(center); 447 | center[2] += 18.0; 448 | TeleportEntity(this.index, center, NULL_VECTOR, NULL_VECTOR); 449 | } 450 | } 451 | } 452 | } 453 | } 454 | 455 | public Action Command_SpawnBall(int client, int argc) 456 | { 457 | float vOrigin[3]; 458 | GetClientAbsOrigin(client, vOrigin); 459 | 460 | int ball = CreateEntityByName("prop_soccer_ball"); 461 | DispatchKeyValue(ball, "targetname", "NextBot_SoccerBall"); 462 | DispatchKeyValue(ball, "model", "models/player/items/scout/soccer_ball.mdl"); 463 | DispatchKeyValueVector(ball, "origin", vOrigin); 464 | DispatchSpawn(ball); 465 | 466 | return Plugin_Handled; 467 | } 468 | 469 | public Action Command_SpawnPlayer(int client, int argc) 470 | { 471 | float vOrigin[3]; 472 | GetClientAbsOrigin(client, vOrigin); 473 | 474 | SpawnPlayer(vOrigin); 475 | 476 | return Plugin_Handled; 477 | } 478 | 479 | 480 | char s_cast[][] = 481 | { 482 | {"models/bots/skeleton_sniper/skeleton_sniper.mdl"}, 483 | {"models/bots/skeleton_sniper_boss/skeleton_sniper_boss.mdl"}, 484 | {"models/bots/engineer/bot_engineer.mdl"}, 485 | {"models/player/demo.mdl"}, 486 | {"models/player/engineer.mdl"}, 487 | {"models/player/heavy.mdl"}, 488 | {"models/player/medic.mdl"}, 489 | {"models/player/pyro.mdl"}, 490 | {"models/player/scout.mdl"}, 491 | {"models/player/sniper.mdl"}, 492 | {"models/player/soldier.mdl"}, 493 | {"models/player/spy.mdl"} 494 | } 495 | 496 | stock void SpawnPlayer(float vOrigin[3]) 497 | { 498 | BaseNPC npc = BaseNPC(vOrigin, NULL_VECTOR, s_cast[GetRandomInt(0, sizeof(s_cast) - 1)], "0.6", "5000", true); 499 | 500 | AcceptEntityInput(npc.index, "DisableShadow"); 501 | 502 | SetEntityFlags(npc.index, FL_NOTARGET); 503 | 504 | SetEntProp(npc.index, Prop_Data, "m_takedamage", 0); 505 | SetEntProp(npc.index, Prop_Data, "m_lifeState", 1); 506 | 507 | int skin = GetRandomInt(0, 1); 508 | SetEntProp(npc.index, Prop_Send, "m_nSkin", skin); 509 | 510 | SetEntPropFloat(npc.index, Prop_Data, "m_speed", 300.0); 511 | 512 | npc.SetAnimation("run_LOSER"); 513 | 514 | SDKHook(npc.index, SDKHook_Think, OnBotThink); 515 | SDKHook(npc.index, SDKHook_TouchPost, OnBotTouch); 516 | } 517 | 518 | const float g_flBallerCoolDownAmount = 0.1; 519 | 520 | public void OnBotThink(int entity) 521 | { 522 | BaseNPC iEntity = view_as(entity); 523 | 524 | Do9WayBlendAnimation(iEntity); 525 | iEntity.Update(); 526 | 527 | int iBallClosest = INVALID_ENT_REFERENCE; 528 | float flClosestDistance = 99999999.0; 529 | 530 | int iBall = INVALID_ENT_REFERENCE; 531 | while ((iBall = FindEntityByClassname(iBall, "prop_soccer_ball")) != -1) 532 | { 533 | float flDistance = GetVectorDistance(WorldSpaceCenter(iBall), WorldSpaceCenter(iEntity.index), true); 534 | 535 | if(flDistance > flClosestDistance) 536 | continue; 537 | 538 | flClosestDistance = flDistance; 539 | iBallClosest = iBall; 540 | } 541 | 542 | if(iBallClosest == INVALID_ENT_REFERENCE) 543 | return; 544 | 545 | if(!PF_Exists(iEntity.index)) 546 | { 547 | iEntity.CreatePather(-1, 18.0, 18.0, 1000.0, MASK_PLAYERSOLID, 100.0, g_flBallerCoolDownAmount, 1.0); 548 | PF_SetGoalVector(iEntity.index, WorldSpaceCenter(iBallClosest)); 549 | PF_StartPathing(iEntity.index); 550 | } 551 | else 552 | { 553 | PF_SetGoalVector(iEntity.index, WorldSpaceCenter(iBallClosest)); 554 | } 555 | 556 | //PrintToServer("flClosestDistance %f, iBallClosest %i", flClosestDistance, iBallClosest); 557 | } 558 | 559 | public void OnBotTouch(int entity, int ball) 560 | { 561 | if(ball <= 0) 562 | return; 563 | 564 | if(!IsValidEntity(ball)) 565 | return; 566 | 567 | char class[64]; GetEntityClassname(ball, class, sizeof(class)); 568 | if(!StrEqual(class, "prop_soccer_ball")) 569 | return; 570 | 571 | BaseNPC iEntity = view_as(entity); 572 | 573 | float m_vecAbsVelocity[3]; 574 | SDKCall(g_hGetGroundMotionVector, iEntity.GetLocomotionInterface(), m_vecAbsVelocity); 575 | 576 | ScaleVector(m_vecAbsVelocity, GetEntPropFloat(iEntity.index, Prop_Data, "m_flGroundSpeed")); 577 | 578 | m_vecAbsVelocity[2] = 0.0; 579 | 580 | //PrintToServer("%f %f %f", m_vecAbsVelocity[0], m_vecAbsVelocity[1], m_vecAbsVelocity[2]); 581 | 582 | float velocity_2d_dot = SquareRoot(GetVectorDotProduct(m_vecAbsVelocity, m_vecAbsVelocity)); 583 | m_vecAbsVelocity[2] = 0.0; 584 | 585 | NormalizeVector(m_vecAbsVelocity, m_vecAbsVelocity); 586 | //VMX_VectorNormalize(m_vecAbsVelocity); 587 | 588 | float soccer_ball_up_max = FindConVar("tf_soccer_ball_up_max").FloatValue; 589 | float halloween_kart_dash_speed = FindConVar("tf_halloween_kart_dash_speed").FloatValue; 590 | float soccer_ball_min_speed = FindConVar("tf_soccer_ball_min_speed").FloatValue; 591 | float soccer_ball_multiplier = FindConVar("tf_soccer_ball_multiplier").FloatValue; 592 | float soccer_front_hit_range = FindConVar("tf_soccer_front_hit_range").FloatValue; 593 | 594 | float soccerball_up_amount = (velocity_2d_dot / halloween_kart_dash_speed) * soccer_ball_up_max; 595 | 596 | float up_multiplier = 5.0; 597 | 598 | if ( soccerball_up_amount >= 5.0 ) 599 | { 600 | if ( soccerball_up_amount <= soccer_ball_up_max ) { 601 | up_multiplier = (velocity_2d_dot / halloween_kart_dash_speed) * soccer_ball_up_max; 602 | } else { 603 | up_multiplier = soccer_ball_up_max; 604 | } 605 | } 606 | 607 | //POSITION 608 | float ball_to_kicker[3]; 609 | SubtractVectors(GetAbsOrigin(ball), GetAbsOrigin(iEntity.index), ball_to_kicker); 610 | ball_to_kicker[2] = 0.0; 611 | 612 | NormalizeVector(ball_to_kicker, ball_to_kicker); 613 | //VMX_VectorNormalize(ball_to_kicker); 614 | 615 | float kick_dot = GetVectorDotProduct(ball_to_kicker, m_vecAbsVelocity); 616 | 617 | if ( kick_dot < 0.1 ) 618 | kick_dot = 0.1; 619 | 620 | float kick_speed_scaled = kick_dot * velocity_2d_dot; 621 | 622 | if ( (kick_dot * velocity_2d_dot) <= soccer_ball_min_speed ) 623 | kick_speed_scaled = soccer_ball_min_speed; 624 | 625 | float final_multiplier = kick_speed_scaled * soccer_ball_multiplier; 626 | 627 | 628 | if ( kick_dot < soccer_front_hit_range ) 629 | { 630 | m_vecAbsVelocity[0] = ball_to_kicker[0]; 631 | m_vecAbsVelocity[1] = ball_to_kicker[1]; 632 | } 633 | 634 | //v17 = *(_DWORD *)(ball + 500); 635 | 636 | float final_vel[3]; 637 | final_vel[0] = m_vecAbsVelocity[0] * final_multiplier; 638 | final_vel[1] = m_vecAbsVelocity[1] * final_multiplier; 639 | final_vel[2] = up_multiplier * soccer_ball_multiplier; 640 | 641 | //PrintToServer("%f %f %f", final_vel[0], final_vel[1], final_vel[2]); 642 | 643 | TeleportEntity(ball, NULL_VECTOR, NULL_VECTOR, final_vel); 644 | } 645 | 646 | stock void Do9WayBlendAnimation(BaseNPC iEntity) 647 | { 648 | Address pLocomotion = iEntity.GetLocomotionInterface(); 649 | if(pLocomotion == Address_Null) 650 | return; 651 | 652 | int m_iMoveX = iEntity.LookupPoseParameter("move_x"); 653 | int m_iMoveY = iEntity.LookupPoseParameter("move_y"); 654 | 655 | if ( m_iMoveX < 0 || m_iMoveY < 0 ) 656 | return; 657 | 658 | float flGroundSpeed = SDKCall(g_hGetGroundSpeed, pLocomotion); 659 | if ( flGroundSpeed != 0.0 ) 660 | { 661 | float vecForward[3], vecRight[3], vecUp[3]; 662 | SDKCall(g_hGetVectors, iEntity, vecForward, vecRight, vecUp); 663 | 664 | float vecMotion[3] 665 | SDKCall(g_hGetGroundMotionVector, pLocomotion, vecMotion); 666 | 667 | iEntity.SetPoseParameter(m_iMoveX, GetVectorDotProduct(vecMotion, vecForward)); 668 | iEntity.SetPoseParameter(m_iMoveY, GetVectorDotProduct(vecMotion, vecRight)); 669 | } 670 | 671 | float m_flGroundSpeed = GetEntPropFloat(iEntity.index, Prop_Data, "m_flGroundSpeed"); 672 | if(m_flGroundSpeed != 0.0) 673 | { 674 | float flReturnValue = clamp(flGroundSpeed / m_flGroundSpeed, -4.0, 12.0); 675 | 676 | SetEntPropFloat(iEntity.index, Prop_Send, "m_flPlaybackRate", flReturnValue); 677 | } 678 | } 679 | 680 | 681 | public void PluginBot_Approach(int bot_entidx, const float vec[3]) 682 | { 683 | BaseNPC npc = view_as(bot_entidx); 684 | npc.Approach(vec); 685 | npc.FaceTowards(vec); 686 | } 687 | 688 | public float PluginBot_PathCost(int bot_entidx, NavArea area, NavArea from_area, float length) 689 | { 690 | float dist; 691 | if (length != 0.0) 692 | { 693 | dist = length; 694 | } 695 | else 696 | { 697 | float vecCenter[3], vecFromCenter[3]; 698 | area.GetCenter(vecCenter); 699 | from_area.GetCenter(vecFromCenter); 700 | 701 | float vecSubtracted[3] 702 | SubtractVectors(vecCenter, vecFromCenter, vecSubtracted) 703 | 704 | dist = GetVectorLength(vecSubtracted); 705 | } 706 | 707 | float multiplier = 1.0; 708 | 709 | /* very similar to CTFBot::TransientlyConsistentRandomValue */ 710 | int seed = RoundToFloor(GetGameTime() * 0.1) + 1; 711 | seed *= area.GetID(); 712 | seed *= bot_entidx; 713 | 714 | /* huge random cost modifier [0, 100] for non-giant bots! */ 715 | multiplier += (Cosine(float(seed)) + 1.0) * 50.0; 716 | 717 | float cost = dist * multiplier; 718 | 719 | return from_area.GetCostSoFar() + cost; 720 | } 721 | 722 | stock float[] GetAbsOrigin(int client) 723 | { 724 | float v[3]; 725 | GetEntPropVector(client, Prop_Data, "m_vecAbsOrigin", v); 726 | return v; 727 | } 728 | 729 | stock float[] WorldSpaceCenter(int entity) 730 | { 731 | float vecPos[3]; 732 | SDKCall(g_hSDKWorldSpaceCenter, entity, vecPos); 733 | 734 | return vecPos; 735 | } 736 | 737 | public float clamp(float a, float b, float c) { return (a > c ? c : (a < b ? b : a)); } 738 | 739 | public MRESReturn IBody_GetSolidMask(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, MASK_PLAYERSOLID); return MRES_Supercede; } 740 | public MRESReturn ILocomotion_GetGravity(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 800.0); return MRES_Supercede; } 741 | public MRESReturn ILocomotion_GetStepHeight(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 20.0); return MRES_Supercede; } 742 | public MRESReturn ILocomotion_GetMaxAcceleration(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 1700.0); return MRES_Supercede; } 743 | public MRESReturn ILocomotion_GetGroundNormal(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturnVector(hReturn, view_as( { 0.0, 0.0, 1.0 } )); return MRES_Supercede; } 744 | public MRESReturn ILocomotion_ShouldCollideWith(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, false); return MRES_Supercede; } 745 | 746 | //I should of have done this long ago. 747 | Handle DHookCreateEx(Handle gc, const char[] key, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback) 748 | { 749 | int iOffset = GameConfGetOffset(gc, key); 750 | if(iOffset == -1) 751 | { 752 | SetFailState("Failed to get offset of %s", key); 753 | return null; 754 | } 755 | 756 | return DHookCreate(iOffset, hooktype, returntype, thistype, callback); 757 | } 758 | -------------------------------------------------------------------------------- /npc_weeper.sp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #pragma newdecls required 8 | 9 | #define MODEL_NPC "models/bots/skeleton_sniper/skeleton_sniper.mdl" 10 | 11 | Handle g_hMyNextBotPointer; 12 | Handle g_hGetLocomotionInterface; 13 | Handle g_hGetBodyInterface; 14 | Handle g_hGetGroundNormal; 15 | Handle g_hRun; 16 | Handle g_hApproach; 17 | Handle g_hFaceTowards; 18 | Handle g_hResetSequence; 19 | Handle g_hGetStepHeight; 20 | Handle g_hGetGravity; 21 | Handle g_hGetSolidMask; 22 | Handle g_hStudioFrameAdvance; 23 | Handle g_hDispatchAnimEvents; 24 | 25 | Handle g_hGetMaxAcceleration; 26 | Handle g_hShouldCollideWith; 27 | Handle g_hGetGroundSpeed; 28 | Handle g_hGetVectors; 29 | Handle g_hGetGroundMotionVector; 30 | Handle g_hHandleAnimEvent; 31 | 32 | Handle g_hLookupPoseParameter; 33 | Handle g_hSetPoseParameter; 34 | 35 | #define ANIM_MOVE 3 36 | #define ANIM_IDLE 144 37 | #define ANIM_FLOAT 4 38 | 39 | public Plugin myinfo = 40 | { 41 | name = "[TF2] NextBot Weeper", 42 | author = "Pelipoika", 43 | description = "", 44 | version = "1.0", 45 | url = "http://www.sourcemod.net/plugins.php?author=Pelipoika&search=1" 46 | }; 47 | 48 | public void OnMapStart() 49 | { 50 | PrecacheModel(MODEL_NPC); 51 | 52 | //Absolutely fucking retarded. 53 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_01.wav"); 54 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_02.wav"); 55 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_03.wav"); 56 | PrecacheSound("^mvm/sentrybuster/mvm_sentrybuster_step_04.wav"); 57 | 58 | PrecacheScriptSound("MVM.SentryBusterStep"); 59 | } 60 | 61 | public Action test(int client, int args) 62 | { 63 | SpawnBuster(GetClientTeam(client), client); 64 | ReplyToCommand(client, "[SM] Spawned"); 65 | 66 | return Plugin_Handled; 67 | } 68 | 69 | stock void SpawnBuster(int iTeam, int iTarget = -1) 70 | { 71 | int spawn = -1; 72 | while((spawn = FindEntityByClassname(spawn, "info_player_teamspawn")) != -1) 73 | { 74 | bool bDisabled = !!GetEntProp(spawn, Prop_Data, "m_bDisabled"); 75 | int iSpawnTeam = GetEntProp(spawn, Prop_Data, "m_iTeamNum"); 76 | 77 | if(!bDisabled && iSpawnTeam == iTeam) 78 | break; 79 | } 80 | 81 | if(spawn == -1) 82 | return; 83 | 84 | float vSpawn[3]; 85 | GetEntPropVector(spawn, Prop_Data, "m_vecAbsOrigin", vSpawn); 86 | 87 | int npc = CreateEntityByName("base_boss"); 88 | DispatchKeyValueVector(npc, "origin", vSpawn); 89 | DispatchKeyValue(npc, "model", MODEL_NPC); 90 | DispatchKeyValue(npc, "modelscale", "1.0"); 91 | DispatchKeyValue(npc, "health", "200"); 92 | DispatchSpawn(npc); 93 | 94 | //trigger_hurts hurt. 95 | SetEntityFlags(npc, FL_CLIENT|FL_NOTARGET); 96 | 97 | SetEntProp(npc, Prop_Data, "m_bloodColor", -1); //Don't bleed 98 | SetEntPropEnt(npc, Prop_Data, "m_hOwnerEntity", iTarget); 99 | SetEntPropFloat(npc, Prop_Data, "m_speed", 200.0); 100 | SetEntProp(npc, Prop_Data, "m_takedamage", 0.0); 101 | SetEntData(npc, FindSendPropInfo("CTFBaseBoss", "m_lastHealthPercentage") + 28, false, 4, true); //ResolvePlayerCollisions 102 | 103 | SDKCall(g_hResetSequence, npc, ANIM_IDLE); 104 | 105 | ActivateEntity(npc); 106 | 107 | DHookEntity(g_hHandleAnimEvent, false, npc); 108 | 109 | Address pLoco = GetLocomotionInterface(npc); 110 | DHookRaw(g_hGetStepHeight, true, pLoco); 111 | DHookRaw(g_hGetGravity, true, pLoco); 112 | DHookRaw(g_hGetGroundNormal, true, pLoco); 113 | DHookRaw(g_hShouldCollideWith, true, pLoco); 114 | DHookRaw(g_hGetMaxAcceleration, true, pLoco); 115 | 116 | Address pBody = GetBodyInterface(npc); 117 | DHookRaw(g_hGetSolidMask, true, pBody); 118 | 119 | PF_Create(npc, 18.0, 18.0, 1000.0, 0.6, MASK_PLAYERSOLID, 200.0, 1.0, 1.0, 0.3); 120 | PF_SetGoalEntity(npc, iTarget); 121 | PF_EnableCallback(npc, PFCB_Approach, PluginBot_Approach); 122 | PF_EnableCallback(npc, PFCB_IsEntityTraversable, PluginBot_Traversible); 123 | PF_StartPathing(npc); 124 | 125 | SDKHook(npc, SDKHook_Think, OnBotThink); 126 | } 127 | 128 | bool bSeen = false; 129 | 130 | public void OnBotThink(int iEntity) 131 | { 132 | float vecMe[3]; 133 | GetEntPropVector(iEntity, Prop_Data, "m_vecAbsOrigin", vecMe); 134 | 135 | float vecMeAng[3]; 136 | GetEntPropVector(iEntity, Prop_Data, "m_angRotation", vecMeAng); 137 | 138 | for (int i = 1; i <= MaxClients; i++) 139 | { 140 | if(!IsClientInGame(i)) 141 | continue; 142 | 143 | if(!IsPlayerAlive(i)) 144 | continue; 145 | 146 | if(GetClientTeam(i) == 0) 147 | continue; 148 | 149 | if(GetClientTeam(i) == 1) 150 | continue; 151 | 152 | float vecThem[3]; 153 | GetClientEyePosition(i, vecThem); 154 | 155 | TR_TraceRayFilter(vecMe, vecThem, MASK_SHOT|CONTENTS_GRATE, RayType_EndPoint, AimTargetFilter, iEntity); 156 | if(TR_DidHit()) 157 | { 158 | int entity = TR_GetEntityIndex(); 159 | if(entity == i) 160 | { 161 | vecThem[2] = 0.0; 162 | vecMe[2] = 0.0; 163 | 164 | float wsc_spy_to_victim[3] 165 | SubtractVectors(vecThem, vecMe, wsc_spy_to_victim); 166 | NormalizeVector(wsc_spy_to_victim, wsc_spy_to_victim); 167 | 168 | float vecTheirEye[3]; 169 | GetEntPropVector(iEntity, Prop_Data, "m_angRotation", vecTheirEye); 170 | GetAngleVectors(vecTheirEye, vecTheirEye, NULL_VECTOR, NULL_VECTOR); 171 | vecTheirEye[2] = 0.0; 172 | NormalizeVector(vecTheirEye, vecTheirEye); 173 | 174 | float eye_victim[3]; 175 | GetClientEyeAngles(i, eye_victim); 176 | GetAngleVectors(eye_victim, eye_victim, NULL_VECTOR, NULL_VECTOR); 177 | eye_victim[2] = 0.0; 178 | NormalizeVector(eye_victim, eye_victim); 179 | 180 | bSeen = (GetVectorDotProduct(wsc_spy_to_victim, eye_victim) <= 0.0); 181 | if(bSeen) 182 | break; 183 | } 184 | } 185 | } 186 | 187 | if(bSeen) 188 | { 189 | SetEntPropFloat(iEntity, Prop_Data, "m_speed", 0.0); 190 | return; 191 | } 192 | else 193 | { 194 | SetEntPropFloat(iEntity, Prop_Data, "m_speed", 400.0); 195 | } 196 | 197 | Address pLocomotion = GetLocomotionInterface(iEntity); 198 | if(pLocomotion == Address_Null) 199 | return; 200 | 201 | Address pStudioHdr = view_as
(GetEntData(iEntity, 283 * 4)); 202 | 203 | int m_iMoveX = SDKCall(g_hLookupPoseParameter, iEntity, pStudioHdr, "move_x"); 204 | int m_iMoveY = SDKCall(g_hLookupPoseParameter, iEntity, pStudioHdr, "move_y"); 205 | 206 | if ( m_iMoveX < 0 || m_iMoveY < 0 ) 207 | return; 208 | 209 | int iSequence = GetEntProp(iEntity, Prop_Send, "m_nSequence"); 210 | 211 | float flGroundSpeed = SDKCall(g_hGetGroundSpeed, pLocomotion); 212 | if ( flGroundSpeed != 0.0 ) 213 | { 214 | if(iSequence != ANIM_MOVE) 215 | { 216 | SDKCall(g_hResetSequence, iEntity, ANIM_MOVE); 217 | } 218 | 219 | float vecForward[3], vecRight[3], vecUp[3]; 220 | SDKCall(g_hGetVectors, iEntity, vecForward, vecRight, vecUp); 221 | 222 | float vecMotion[3] 223 | SDKCall(g_hGetGroundMotionVector, pLocomotion, vecMotion); 224 | 225 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveX, GetVectorDotProduct(vecMotion, vecForward)); 226 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveY, GetVectorDotProduct(vecMotion, vecRight)); 227 | } 228 | else 229 | { 230 | if(iSequence != ANIM_IDLE) 231 | { 232 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveX, 0.0); 233 | SDKCall(g_hSetPoseParameter, iEntity, pStudioHdr, m_iMoveY, 0.0); 234 | 235 | SDKCall(g_hResetSequence, iEntity, ANIM_IDLE); 236 | } 237 | } 238 | 239 | float m_flGroundSpeed = GetEntPropFloat(iEntity, Prop_Data, "m_flGroundSpeed"); 240 | if(m_flGroundSpeed != 0.0) 241 | { 242 | float flReturnValue = clamp(flGroundSpeed / m_flGroundSpeed, -4.0, 12.0); 243 | 244 | SetEntPropFloat(iEntity, Prop_Send, "m_flPlaybackRate", flReturnValue); 245 | } 246 | 247 | SDKCall(g_hStudioFrameAdvance, iEntity); 248 | SDKCall(g_hDispatchAnimEvents, iEntity, iEntity); 249 | } 250 | 251 | public bool PluginBot_Traversible(int bot_entidx, int other_entidx) { return true; } 252 | 253 | public void PluginBot_Approach(int bot_entidx, const float vec[3]) 254 | { 255 | Address pLocomotion = GetLocomotionInterface(bot_entidx); 256 | SDKCall(g_hRun, pLocomotion); 257 | 258 | if(bSeen) 259 | return; 260 | 261 | int iGoalEntity = GetEntPropEnt(bot_entidx, Prop_Data, "m_hOwnerEntity"); 262 | if(iGoalEntity != -1) 263 | { 264 | float vTargetPos[3]; 265 | GetEntPropVector(iGoalEntity, Prop_Data, "m_vecAbsOrigin", vTargetPos); 266 | 267 | float vOrigin[3]; 268 | GetEntPropVector(bot_entidx, Prop_Data, "m_vecAbsOrigin", vOrigin); 269 | 270 | if(GetVectorDistance(vOrigin, vTargetPos) > 99.0) 271 | { 272 | SDKCall(g_hApproach, pLocomotion, vec, 1.0); 273 | 274 | ConVar flTurnRate = FindConVar("tf_base_boss_max_turn_rate"); 275 | float flPrevValue = flTurnRate.FloatValue; 276 | flTurnRate.FloatValue = 500.0; 277 | SDKCall(g_hFaceTowards, pLocomotion, vec); 278 | flTurnRate.FloatValue = flPrevValue; 279 | } 280 | } 281 | } 282 | 283 | public MRESReturn IBody_GetSolidMask(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 0x203400B); return MRES_Supercede; } 284 | public MRESReturn ILocomotion_GetGravity(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 800.0); return MRES_Supercede; } 285 | public MRESReturn ILocomotion_GetStepHeight(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 20.0); return MRES_Supercede; } 286 | public MRESReturn ILocomotion_GetMaxAcceleration(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, 1700.0); return MRES_Supercede; } 287 | public MRESReturn ILocomotion_ShouldCollideWith(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturn(hReturn, false); return MRES_Supercede; } 288 | public MRESReturn ILocomotion_GetGroundNormal(Address pThis, Handle hReturn, Handle hParams) { DHookSetReturnVector(hReturn, view_as( { 0.0, 0.0, 1.0 } )); return MRES_Supercede; } 289 | 290 | public MRESReturn CBaseAnimating_HandleAnimEvent(int pThis, Handle hParams) 291 | { 292 | int event = DHookGetParamObjectPtrVar(hParams, 1, 0, ObjectValueType_Int); 293 | if(event == 7001) //Footstep 294 | { 295 | EmitGameSoundToAll("MVM.SentryBusterStep", pThis); 296 | } 297 | } 298 | 299 | public float clamp(float a, float b, float c) { return (a > c ? c : (a < b ? b : a)); } 300 | 301 | public Address GetLocomotionInterface(int index) { return SDKCall(g_hGetLocomotionInterface, SDKCall(g_hMyNextBotPointer, index)); } 302 | public Address GetBodyInterface(int index) { return SDKCall(g_hGetBodyInterface, SDKCall(g_hMyNextBotPointer, index)); } 303 | 304 | public void OnPluginStart() 305 | { 306 | RegAdminCmd("sm_weeper", test, ADMFLAG_ROOT); 307 | 308 | Handle hConf = LoadGameConfigFile("tf2.pets"); 309 | 310 | //SDKCalls 311 | StartPrepSDKCall(SDKCall_Entity); 312 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::StudioFrameAdvance"); 313 | if ((g_hStudioFrameAdvance = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::StudioFrameAdvance offset!"); 314 | 315 | StartPrepSDKCall(SDKCall_Entity); 316 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseAnimating::DispatchAnimEvents"); 317 | PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); 318 | if ((g_hDispatchAnimEvents = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::DispatchAnimEvents offset!"); 319 | 320 | //ResetSequence( int nSequence ); 321 | StartPrepSDKCall(SDKCall_Entity); 322 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::ResetSequence"); 323 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 324 | if ((g_hResetSequence = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseAnimating::ResetSequence signature!"); 325 | 326 | //MyNextBotPointer( ); 327 | StartPrepSDKCall(SDKCall_Entity); 328 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::MyNextBotPointer"); 329 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 330 | if ((g_hMyNextBotPointer = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create SDKCall for CBaseEntity::MyNextBotPointer offset!"); 331 | 332 | StartPrepSDKCall(SDKCall_Raw); 333 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetLocomotionInterface"); 334 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 335 | if((g_hGetLocomotionInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetLocomotionInterface!"); 336 | 337 | StartPrepSDKCall(SDKCall_Raw); 338 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "INextBot::GetBodyInterface"); 339 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 340 | if((g_hGetBodyInterface = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for INextBot::GetBodyInterface!"); 341 | 342 | StartPrepSDKCall(SDKCall_Raw); 343 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Run"); 344 | if((g_hRun = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Run!"); 345 | 346 | StartPrepSDKCall(SDKCall_Raw); 347 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::Approach"); 348 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 349 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 350 | if((g_hApproach = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::Approach!"); 351 | 352 | StartPrepSDKCall(SDKCall_Raw); 353 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::FaceTowards"); 354 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef); 355 | if((g_hFaceTowards = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::FaceTowards!"); 356 | 357 | //ILocomotion::GetGroundSpeed() 358 | StartPrepSDKCall(SDKCall_Raw); 359 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundSpeed"); 360 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 361 | if((g_hGetGroundSpeed = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundSpeed!"); 362 | 363 | //ILocomotion::GetGroundMotionVector() 364 | StartPrepSDKCall(SDKCall_Raw); 365 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "ILocomotion::GetGroundMotionVector"); 366 | PrepSDKCall_SetReturnInfo(SDKType_Vector, SDKPass_ByRef); 367 | if((g_hGetGroundMotionVector = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for ILocomotion::GetGroundMotionVector!"); 368 | 369 | //CBaseEntity::GetVectors(Vector*, Vector*, Vector*) 370 | StartPrepSDKCall(SDKCall_Entity); 371 | PrepSDKCall_SetFromConf(hConf, SDKConf_Virtual, "CBaseEntity::GetVectors"); 372 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 373 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 374 | PrepSDKCall_AddParameter(SDKType_Vector, SDKPass_ByRef, _, VENCODE_FLAG_COPYBACK); 375 | if((g_hGetVectors = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Virtual Call for CBaseEntity::GetVectors!"); 376 | 377 | //SetPoseParameter( CStudioHdr *pStudioHdr, int iParameter, float flValue ); 378 | StartPrepSDKCall(SDKCall_Entity); 379 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::SetPoseParameter"); 380 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 381 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 382 | PrepSDKCall_AddParameter(SDKType_Float, SDKPass_Plain); 383 | PrepSDKCall_SetReturnInfo(SDKType_Float, SDKPass_Plain); 384 | if((g_hSetPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::SetPoseParameter"); 385 | 386 | //LookupPoseParameter( CStudioHdr *pStudioHdr, const char *szName ); 387 | StartPrepSDKCall(SDKCall_Entity); 388 | PrepSDKCall_SetFromConf(hConf, SDKConf_Signature, "CBaseAnimating::LookupPoseParameter"); 389 | PrepSDKCall_AddParameter(SDKType_PlainOldData, SDKPass_Plain); 390 | PrepSDKCall_AddParameter(SDKType_String, SDKPass_Pointer); 391 | PrepSDKCall_SetReturnInfo(SDKType_PlainOldData, SDKPass_Plain); 392 | if((g_hLookupPoseParameter = EndPrepSDKCall()) == INVALID_HANDLE) SetFailState("Failed to create Call for CBaseAnimating::LookupPoseParameter"); 393 | 394 | //DHooks 395 | g_hGetSolidMask = DHookCreateEx(hConf, "IBody::GetSolidMask", HookType_Raw, ReturnType_Int, ThisPointer_Address, IBody_GetSolidMask); 396 | g_hGetStepHeight = DHookCreateEx(hConf, "ILocomotion::GetStepHeight", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetStepHeight); 397 | g_hGetGravity = DHookCreateEx(hConf, "ILocomotion::GetGravity", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetGravity); 398 | g_hGetGroundNormal = DHookCreateEx(hConf, "ILocomotion::GetGroundNormal", HookType_Raw, ReturnType_VectorPtr, ThisPointer_Address, ILocomotion_GetGroundNormal); 399 | g_hGetMaxAcceleration = DHookCreateEx(hConf, "ILocomotion::GetMaxAcceleration", HookType_Raw, ReturnType_Float, ThisPointer_Address, ILocomotion_GetMaxAcceleration); 400 | 401 | g_hShouldCollideWith = DHookCreateEx(hConf, "ILocomotion::ShouldCollideWith", HookType_Raw, ReturnType_Bool, ThisPointer_Address, ILocomotion_ShouldCollideWith); 402 | DHookAddParam(g_hShouldCollideWith, HookParamType_CBaseEntity); 403 | 404 | g_hHandleAnimEvent = DHookCreateEx(hConf, "CBaseAnimating::HandleAnimEvent", HookType_Entity, ReturnType_Void, ThisPointer_CBaseEntity, CBaseAnimating_HandleAnimEvent); 405 | DHookAddParam(g_hHandleAnimEvent, HookParamType_ObjectPtr, -1); 406 | 407 | delete hConf; 408 | } 409 | 410 | //I should of have done this long ago. 411 | Handle DHookCreateEx(Handle gc, const char[] key, HookType hooktype, ReturnType returntype, ThisPointerType thistype, DHookCallback callback) 412 | { 413 | int iOffset = GameConfGetOffset(gc, key); 414 | if(iOffset == -1) 415 | { 416 | SetFailState("Failed to get offset of %s", key); 417 | return null; 418 | } 419 | 420 | return DHookCreate(iOffset, hooktype, returntype, thistype, callback); 421 | } 422 | 423 | public bool AimTargetFilter(int entity, int contentsMask, any iExclude) 424 | { 425 | char class[64]; 426 | GetEntityClassname(entity, class, sizeof(class)); 427 | 428 | if(StrEqual(class, "entity_medigun_shield")) 429 | { 430 | if(GetEntProp(entity, Prop_Send, "m_iTeamNum") == GetClientTeam(iExclude)) 431 | { 432 | return false; 433 | } 434 | } 435 | else if(StrEqual(class, "func_respawnroomvisualizer")) 436 | { 437 | return false; 438 | } 439 | else if(StrContains(class, "tf_projectile_", false) != -1) 440 | { 441 | return false; 442 | } 443 | 444 | return !(entity == iExclude); 445 | } --------------------------------------------------------------------------------