| 56 | } |
| 57 | |
| 58 | void CobraControl(short itemNumber) |
| 59 | { |
| 60 | if (!CreatureActive(itemNumber)) |
| 61 | return; |
| 62 | |
| 63 | auto* item = &g_Level.Items[itemNumber]; |
| 64 | auto* creature = GetCreatureInfo(item); |
| 65 | |
| 66 | short angle = 0; |
| 67 | short tilt = 0; |
| 68 | short vertTilt = 0; |
| 69 | |
| 70 | if (item->HitPoints <= 0 && item->HitPoints != NOT_TARGETABLE) |
| 71 | { |
| 72 | if (item->Animation.ActiveState != COBRA_STATE_DEATH) |
| 73 | SetAnimation(item, COBRA_ANIM_DEATH); |
| 74 | } |
| 75 | else |
| 76 | { |
| 77 | AI_INFO AI; |
| 78 | CreatureAIInfo(item, &AI); |
| 79 | |
| 80 | AI.angle += ANGLE(16.8f); |
| 81 | |
| 82 | bool isEnemyMoving = false; |
| 83 | bool isEnemyVisible = false; |
| 84 | |
| 85 | if (creature->Enemy && item->Animation.ActiveState != COBRA_STATE_SLEEP) |
| 86 | { |
| 87 | auto enemyPos = creature->Enemy->Pose.Position; |
| 88 | enemyPos.y -= CLICK(1.5f); |
| 89 | |
| 90 | auto origin = GameVector(enemyPos, creature->Enemy->RoomNumber); |
| 91 | auto target = GameVector(GetJointPosition(item, 10), item->RoomNumber); // Cobra's origin of LOS check. |
| 92 | |
| 93 | isEnemyVisible = LOS(&origin, &target); |
| 94 | |
| 95 | // A little trick to prevent Cobra jerking: after losing LOS, `EnemyIsVisible` working few more frames. |
| 96 | if (isEnemyVisible) |
| 97 | { |
| 98 | item->ItemFlags[3] = 6; |
| 99 | } |
| 100 | else if (item->ItemFlags[3] > 0) |
| 101 | { |
| 102 | item->ItemFlags[3]--; |
| 103 | isEnemyVisible = true; |
| 104 | } |
| 105 | |
| 106 | if (creature->Enemy->Animation.Velocity.z > COBRA_DISTURBANCE_VELOCITY || |
| 107 | abs(creature->Enemy->Animation.Velocity.y) > COBRA_DISTURBANCE_VELOCITY) |
| 108 | { |
| 109 | isEnemyMoving = true; |
| 110 | } |
| 111 | |
| 112 | creature->Target.x = creature->Enemy->Pose.Position.x; |
| 113 | creature->Target.z = creature->Enemy->Pose.Position.z; |
| 114 | } |
| 115 |
nothing calls this directly
no test coverage detected