public override void Update(GuidedVob vob, long now) { if (Target == null) { return; } if (!Cast.Try(vob.ScriptObject, out NPCInst npc)) { throw new Exception("Vob used with GoToVobLookAtCommand is no NPC!"); } if (npc.IsDead) { return; } var gNpc = npc.BaseInst.gVob; gNpc.RbtTimer = 500; gNpc.RbtTargetVob = Target.BaseInst.gVob; gNpc.RbtBitfield = gNpc.RbtBitfield | (1 << 4); // stand when reached Target.GetPosition().SetGVec(gNpc.RbtTargetPos); gNpc.RbtMaxTargetDist = Distance * Distance; gNpc.RbtGotoFollowPosition(); Vec3f npcPos = npc.GetPosition(); Vec3f targetPos = Target.GetPosition(); if (npcPos.GetDistance(targetPos) <= Distance) { const float maxTurnFightSpeed = 0.08f; float bestYaw = Angles.GetYawFromAtVector(targetPos - npcPos); Angles curAngles = npc.GetAngles(); float yawDiff = Angles.Difference(bestYaw, curAngles.Yaw); curAngles.Yaw += Alg.Clamp(-maxTurnFightSpeed, yawDiff, maxTurnFightSpeed); npc.SetAngles(curAngles); } }
private void CalcHit() { try { if (IsDead || FightAnimation == null || IsUnconscious) { return; } Vec3f attPos = GetPosition(); Angles attAng = GetAngles(); int baseDamage = 5 + Damage; ItemInst weapon; if ((weapon = GetDrawnWeapon()) != null) { baseDamage += weapon.Damage; } // two weapons if ((weapon = GetLeftHand()) != null && weapon.ItemType == ItemTypes.Wep1H) { baseDamage += weapon.Damage / 4; } float weaponRange = GetFightRange(); BaseInst.World.ForEachNPCRough(attPos, GUCScripts.BiggestNPCRadius + weaponRange, npc => // fixme: enemy model radius { NpcInst target = (NpcInst)npc.ScriptObject; if (target == this || target.IsDead || target.IsUnconscious) { return; } if (!AllowHitEvent.TrueForAll(this, target) || !AllowHitAttacker.TrueForAll(this, target) || !target.AllowHitTarget.TrueForAll(this, target)) { return; } float realRange = weaponRange + target.ModelDef.Radius; if (target.CurrentFightMove == FightMoves.Dodge) { realRange /= 3.0f; // decrease radius if target is backing up } Vec3f targetPos = npc.Position + npc.GetAtVector() * target.ModelDef.CenterOffset; if ((targetPos - attPos).GetLength() > realRange) { return; // not in range } float hitHeight; float hitYaw; if (CurrentFightMove == FightMoves.Left || CurrentFightMove == FightMoves.Right) { hitHeight = target.ModelDef.HalfHeight; hitYaw = Angles.PI * 0.4f; } else { hitHeight = target.ModelDef.HalfHeight + ModelDef.HalfHeight; hitYaw = Angles.PI * 0.2f; } if (Math.Abs(targetPos.Y - attPos.Y) > hitHeight) { return; // not same height } float yaw = Angles.GetYawFromAtVector(targetPos - attPos); if (Math.Abs(Angles.Difference(yaw, attAng.Yaw)) > hitYaw) { return; // target is not in front of attacker } float tdiff = Math.Abs(Angles.Difference(target.GetAngles().Yaw, yaw)); if (target.CurrentFightMove == FightMoves.Parry && tdiff > Angles.PI / 2) // parry 180 degrees { var strm = BaseInst.GetScriptVobStream(); strm.Write((byte)ScriptVobMessageIDs.ParryMessage); strm.Write((ushort)npc.ID); BaseInst.SendScriptVobStream(strm); } else // HIT { int damage = baseDamage; if (CurrentFightMove == FightMoves.Left || CurrentFightMove == FightMoves.Right) { damage -= 2; } else if (CurrentFightMove == FightMoves.Fwd) { damage += (ComboNum - 1) * 2; } else if (CurrentFightMove == FightMoves.Run) { damage += 6; if (Environment.InAir) // super jump attack { damage += 2; // not too much because you can always jump } if (target.Environment.InAir) { damage += 2; } } bool frontAttack; if (tdiff < Angles.PI / 4) // backstab { damage += 4; frontAttack = false; } else { frontAttack = true; } target.Hit(this, damage, frontAttack); } }); } catch (Exception e) { Logger.Log("CalcHit of npc " + ID + " " + BaseInst.HP + " " + e); } }
static void Update() { NPCInst hero = currentPlayer; if (hero == null) { Deactivate(); return; } float maxYaw = Angles.Deg2Rad(60); bool fightMode = hero.IsInFightMode; ItemInst wep = hero.GetDrawnWeapon(); float maxRange = (fightMode && wep != null && wep.IsWepRanged) ? 3000 : 400; Vec3f heroPos = hero.GetPosition(); Angles heroAng = hero.GetAngles(); float bestFit = 2.0f; BaseVobInst bestVob = null; if (hero?.World?.BaseWorld != null) { hero.World.BaseWorld.ForEachVob(v => { BaseVobInst vob = (BaseVobInst)v.ScriptObject; if (vob == hero) { return; } bool hasPriority = false; if (fightMode) { if (!(vob is NPCInst npc)) { return; } if (npc.IsDead) { return; } if (bestVob != null) { NPCInst bestNPC = (NPCInst)bestVob; if (npc.IsUnconscious) { if (!bestNPC.IsUnconscious) { return; // alive targets are more important } } else { if (bestNPC.IsUnconscious) { hasPriority = true; } } if (npc.TeamID == hero.TeamID) { if (bestNPC.TeamID != hero.TeamID) { return; } } else { if (bestNPC.TeamID == hero.TeamID) { hasPriority = true; } } } } Vec3f targetPos; using (zVec3 z = zVec3.Create()) { vob.BaseInst.gVob.BBox3D.GetCenter(z); targetPos = (Vec3f)z; } float distance = heroPos.GetDistance(targetPos); if (distance > maxRange) { return; } float yaw = Angles.GetYawFromAtVector(targetPos - heroPos); yaw = Math.Abs(Angles.Difference(yaw, heroAng.Yaw)); if (yaw > maxYaw) { return; // target is not in front of hero } if (!CanSee(heroPos, targetPos, vob)) { return; } float fit = distance / maxRange + yaw / maxYaw; if (hasPriority || fit < bestFit) { bestVob = vob; bestFit = fit; } }); SetFocus(bestVob); } }
static void DoTurning(NPCInst hero) { if (hero.BaseInst.gAI.GetFoundLedge()) { return; } const float maxTurnFightSpeed = 0.07f; NPCInst enemy = PlayerFocus.LockedTarget; if (enemy != null) { Vec3f heroPos = hero.GetPosition(); Vec3f enemyPos = enemy.GetPosition(); float bestYaw = Angles.GetYawFromAtVector(enemyPos - heroPos); Angles curAngles = hero.GetAngles(); float yawDiff = Angles.Difference(bestYaw, curAngles.Yaw); curAngles.Yaw += Alg.Clamp(-maxTurnFightSpeed, yawDiff, maxTurnFightSpeed); hero.SetAngles(curAngles); CheckCombineAim(hero, enemyPos - heroPos); return; } const float maxLookupSpeed = 2f; float rotSpeed = 0; if (InputHandler.MouseDistY != 0) { rotSpeed = Alg.Clamp(-maxLookupSpeed, InputHandler.MouseDistY * 0.35f * MouseSpeed, maxLookupSpeed); if (hero.Environment.WaterLevel >= 1) { hero.BaseInst.gAI.DiveRotateX(rotSpeed); } else { var cam = zCAICamera.CurrentCam; cam.BestElevation = Alg.Clamp(-50, cam.BestElevation + rotSpeed, 85); } } // Fixme: do own turning const float maxTurnSpeed = 2f; if (!KeyBind.Action.IsPressed()) { float turn = 0; if (KeyBind.TurnLeft.IsPressed()) { turn = -maxTurnSpeed; } else if (KeyBind.TurnRight.IsPressed()) { turn = maxTurnSpeed; } else if (Math.Abs(InputHandler.MouseDistX) > ((rotSpeed > 0.5f && hero.Movement == NPCMovement.Stand) ? 18 : 2)) { turn = Alg.Clamp(-maxTurnSpeed, InputHandler.MouseDistX * 0.45f * MouseSpeed, maxTurnSpeed); } if (turn != 0) { hero.BaseInst.gAI.Turn(turn, !hero.ModelInst.IsInAnimation()); return; } } hero.BaseInst.gVob.AniCtrl.StopTurnAnis(); }