[POC/WIP] Killstreaks
Featured Replies
Сейчас на странице 0
- Нет пользователей, просматривающих эту страницу
A better way to browse. Learn more.
A full-screen app on your home screen with push notifications, badges and more.
Используя этот сайт, вы соглашаетесь Условия использования.
Since people keep saying killstreaks are not possible in InfinityScript I made a POC of the predator missile. It took me around 2hours but the big part were actually the commonly used functions from _killstreaks.gsc and _utility.gsc.
Example video:
If you want to test it here is the code:
#define DEV using System; using System.Collections.Generic; using System.Linq; using System.Text; using InfinityScript; namespace Predator { public class Missile : BaseScript { int missileRemoteLaunchVert = 14000; int missileRemoteLaunchHorz = 30000; int missileRemoteLaunchTargetDist = 1500; //int remotemissile_fx = 0; List RidingPred = new List(); bool GameEnded = false; public Missile() { //remotemissile_fx = Call("loadfx", "explosions/aerial_explosion"); PlayerConnected += new Action(entity => { #if DEV entity.Call("notifyonplayercommand", "3", "+actionslot 3"); entity.OnNotify("3", ent => { giveKillstreakWeapon(ent, "predator_missile"); }); #endif entity.SetField("laptopWait", string.Empty); entity.OnNotify("weapon_switch_started", (ent, weapon) => { if (ent.GetField("laptopWait") == "get") entity.SetField("laptopWait", "weapon_switch_started"); }); entity.OnNotify("weapon_change", (ent, newWeap) => { if (mayDropWeapon((string)newWeap)) ent.SetField("lastDroppableWeapon", (string)newWeap); KillstreakUseWaiter(ent, (string)newWeap); }); entity.OnNotify("joined_team", ent => { if (!RidingPred.Contains(ent)) return; if (ent.GetField("sessionteam") != "spectator") Player_ClearUp(ent); ClearUsingRemote(ent); }); entity.OnNotify("joined_spectators", ent => { if (!RidingPred.Contains(ent)) return; if (ent.GetField("sessionteam") != "spectator") Player_ClearUp(ent); ClearUsingRemote(ent); }); OnNotify("game_ended", (level /*??*/) => { GameEnded = true; foreach (Entity player in RidingPred) { Player_ClearUp(player); } RidingPred.Clear(); }); }); } public override void OnPlayerKilled(Entity player, Entity inflictor, Entity attacker, int damage, string mod, string weapon, Vector3 dir, string hitLoc) { if (player.GetField("laptopWait") == "get") player.SetField("laptopWait", "death"); } //Common utility and killstreak functions #region common private static void SetUsingRemote(Entity ent, string remote = "") { ent.Call("DisableOffhandWeapons"); //ent.SetField("usingRemote", remote); ent.Notify("using_remote"); } private int getKillstreakIndex(string streakName) { int ret = 0; ret = Call("tableLookupRowNum", "mp/killstreakTable.csv", 1, streakName) - 1; return ret; } private string getKillstreakWeapon(string streakName) { string ret = string.Empty; ret = Call("tableLookup", "mp/killstreakTable.csv", 1, streakName, 12); #if DEV Log.Write(LogLevel.Info, "Killstreak weapon: " + ret); #endif return ret; } private void giveKillstreakWeapon(Entity ent, string streakName) { string wep = getKillstreakWeapon(streakName); if (string.IsNullOrEmpty(wep)) return; ent.SetField("customStreak", streakName); ent.Call("giveWeapon", wep, 0, false); ent.Call("setActionSlot", 4, "weapon", wep); //assign icon... (fuck you IW for your new ks system) ent.Call("SetPlayerData", "killstreaksState", "hasStreak", 0, true); //not sure if slot 0 is even used, if yes we should get the old icon first and save it ent.Call("SetPlayerData", "killstreaksState", "icons", 0, getKillstreakIndex("predator_missile")); } private void KillstreakUseWaiter(Entity ent, string weapon) { //unfinished //add more //probably switch if enough if (weapon == "killstreak_predator_missile_mp") { tryUsePredator(ent); ent.Call("playLocalSound", "weap_c4detpack_trigger_plr"); } #if DEV else Log.Write(LogLevel.Info, "KillstreakUseWaiter: " + weapon); #endif } private string GetThermalVision() { string str = Call("getMapCustom", "thermal"); if (str == "invert") return "thermal_snowlevel_mp"; else return "thermal_mp"; } private void Player_ClearUp(Entity player) { player.Call("ThermalVisionFOFOverlayOff"); player.Call("ControlsUnlink"); player.Call("CameraUnlink"); if (Call("getdvarint", "camera_thirdPerson") == 1) setThirdPersonDOF(player, true); } private static void setThirdPersonDOF(Entity ent, bool Enabled) { if (Enabled) ent.Call("setDepthOfField", 0f, 110f, 512f, 4096f, 6f, 1.8f); else ent.Call("setDepthOfField", 0f, 0f, 512f, 512f, 4f, 0f); } private void ClearUsingRemote(Entity ent) { ent.Call("enableOffhandWeapons"); string curWeapon = ent.CurrentWeapon; if (curWeapon == "none" || isKillstreakWeapon(curWeapon)) { //added taking away the weapon ent.TakeWeapon(curWeapon); ent.Call("SwitchToWeapon", ent.GetField("lastDroppableWeapon")); } ent.Call("freezeControls", false); ent.Notify("stopped_using_remote"); } private bool mayDropWeapon(string weapon) { if (weapon == "none") return false; if (weapon.Contains("ac130")) return false; string invType = Call("WeaponInventoryType", weapon); if (invType != "primary") return false; return true; } public static bool isAirdropMarker(string weaponName) { switch (weaponName) { case "airdrop_marker_mp": case "airdrop_mega_marker_mp": case "airdrop_sentry_marker_mp": case "airdrop_juggernaut_mp": case "airdrop_juggernaut_def_mp": return true; default: return false; } } public static bool isAssaultKillstreak(string refString) { switch (refString) { case "uav": case "airdrop_assault": case "predator_missile": case "ims": case "airdrop_sentry_minigun": case "precision_airstrike": case "helicopter": case "littlebird_flock": case "littlebird_support": case "remote_mortar": case "airdrop_remote_tank": case "helicopter_flares": case "ac130": case "airdrop_juggernaut": case "osprey_gunner": return true; default: return false; } } public static bool isSupportKillstreak(string refString) { switch (refString) { case "uav_support": case "counter_uav": case "deployable_vest": case "airdrop_trap": case "sam_turret": case "remote_uav": case "triple_uav": case "remote_mg_turret": case "stealth_airstrike": case "emp": case "airdrop_juggernaut_recon": case "escort_airdrop": return true; default: return false; } } public static bool isSpecialistKillstreak(string refString) { switch (refString) { case "specialty_longersprint_ks": case "specialty_fastreload_ks": case "specialty_scavenger_ks": case "specialty_blindeye_ks": case "specialty_paint_ks": case "specialty_hardline_ks": case "specialty_coldblooded_ks": case "specialty_quickdraw_ks": case "specialty_assists_ks": case "_specialty_blastshield_ks": case "specialty_detectexplosive_ks": case "specialty_autospot_ks": case "specialty_bulletaccuracy_ks": case "specialty_quieter_ks": case "specialty_stalker_ks": case "all_perks_bonus": return true; default: return false; } } private bool isKillstreakWeapon(string wep) { if (string.IsNullOrEmpty(wep)) return false; wep = wep.ToLower(); if (wep == "none") return false; string[] split = wep.Split('_'); bool foundSuffix = false; if (wep != "destructible_car" && wep != "barrel_mp") { foreach (string str in split) { if (str == "mp") { foundSuffix = true; break; } } if (!foundSuffix) wep += "_mp"; } if (wep.Contains("destructible")) return false; if (wep.Contains("killstreak")) return true; if (isAirdropMarker(wep)) return true; if ((wep != "destructible_car" && wep != "barrel_mp") && !string.IsNullOrEmpty(Call("weaponInventoryType", wep)) && Call("weaponInventoryType", wep) == "exclusive") return true; //added if (wep.Contains("remote")) return true; return false; } private void initRideKillstreak(Entity ent, string streakName = "") { if (!string.IsNullOrEmpty(streakName) && (streakName == "osprey_gunner" || streakName == "remote_uav" || streakName == "remote_tank")) { ent.SetField("laptopWait", "timeout"); initRideKillstreak2(ent); } else { ent.SetField("laptopWait", "get"); //laptopWait = self waittill_any_timeout( 1.0, "disconnect", "death", "weapon_switch_started" ); int counter = 0; //maybe smarter to use 50 interval? ent.OnInterval(100, entity => { counter++; if (entity == null) return false; if (counter > 10 || entity.GetField("laptopWait") != "get") { //reset ks icon if (entity.GetField("customStreak") == streakName) { entity.Call("SetPlayerData", "killstreaksState", "hasStreak", 0, false); entity.Call("SetPlayerData", "killstreaksState", "icons", 0, 0); entity.SetField("customStreak", string.Empty); } initRideKillstreak2(entity); return false; } return true; }); } } private void initRideKillstreak2(Entity entity) { if (entity.GetField("laptopWait") == "get") entity.SetField("laptopWait", string.Empty); else if (entity.GetField("laptopWait") == "weapon_switch_started") { ClearUsingRemote(entity); return; } if ((!entity.IsAlive) || (entity.GetField("laptopWait") == "death" && entity.GetField("sessionteam") == "spectator")) { ClearUsingRemote(entity); return; } //Can't check for emp/nuke entity.Call("VisionSetNakedForPlayer", "black_bw", 0.75f); int Count = 0; entity.SetField("laptopWait", "get"); //maybe smarter to use 50 interval? entity.OnInterval(100, player => { Count++; if (player == null) return false; if (Count > 8 || player.GetField("laptopWait") != "get") { clearRideIntro(player, 1.0f); if (player.GetField("sessionteam") == "spectator") { ClearUsingRemote(entity); return false; } //Can't check if on ladder FirePredator(player); //need to modify if adding more killstreaks return false; } return true; }); } private static void clearRideIntro(Entity ent, float delay = 0.0f) { if (delay >= 0.1) { ent.AfterDelay(Convert.ToInt32(delay * 1000), entity => { entity.Call("VisionSetNakedForPlayer", string.Empty, 0); }); } else ent.Call("VisionSetNakedForPlayer", string.Empty, 0); } #endregion public void tryUsePredator(Entity ent) { SetUsingRemote(ent, "remotemissile"); initRideKillstreak(ent, "predator_missile"); } private void FirePredator(Entity ent) { //Entity[] remoteMissileSpawnArray = Call("getEntArray", "remoteMissileSpawn", "targetname"); Entity remoteMissileSpawn = null; //non working as of r28 (getEntArray) /*foreach (Entity spawn in remoteMissileSpawnArray) { if (spawn.HasField("target") && !string.IsNullOrEmpty(spawn.GetField("target"))) spawn.SetField("targetEnt", Call("getent", spawn.GetField("target"), "targetname")); } if (remoteMissileSpawnArray.Length > 0) { getBestSpawnPoint... not implemented yet } else Log.Write(LogLevel.Info, "Entity Array is empty..");*/ Vector3 startPos = Vector3.RandomXY(), targetPos = Vector3.RandomXY(); if (remoteMissileSpawn != null) { Entity targetEnt = remoteMissileSpawn.GetField("targetEnt"); targetPos = targetEnt.Origin; Vector3 vec = Call("vectorNormalize", remoteMissileSpawn.Origin, targetPos); startPos = (vec * missileRemoteLaunchVert) + targetPos; } else { Vector3 forward = Call("AnglesToForward", ent.GetField("angles")); startPos = ent.Origin + (forward * -1 * missileRemoteLaunchHorz) + new Vector3(0, 0, missileRemoteLaunchVert); targetPos = ent.Origin + (forward * missileRemoteLaunchTargetDist); } Entity rocket = Call("MagicBullet", "remotemissile_projectile_mp", startPos, targetPos, ent); if (rocket == null) { ClearUsingRemote(ent); return; } rocket.Call("setCanDamage", true); MissileEyes(ent, rocket); } private void MissileEyes(Entity player, Entity rocket) { player.Call("VisionSetMissilecamForPlayer", "black_bw", 0f); if (rocket == null) ClearUsingRemote(player); RidingPred.Add(player); player.Call("VisionSetMissilecamForPlayer", GetThermalVision(), 1.0f); player.AfterDelay(150, ent => { ent.Call("ThermalVisionFOFOverlayOn"); }); player.Call("CameraLinkTo", rocket, "tag_origin"); player.Call("ControlsLinkTo", rocket); if (Call("getdvarint", "camera_thirdPerson") == 1) setThirdPersonDOF(player, false); rocket.OnNotify("death", _rocket => { if (RidingPred.Contains(player)) RidingPred.Remove(player); player.Call("ControlsUnlink"); player.Call("freezeControls", true); //unfinished if (!GameEnded) staticEffect(player, 0.5f); AfterDelay(500, () => { player.Call("ThermalVisionFOFOverlayOff"); player.Call("CameraUnlink"); if (Call("getdvarint", "camera_thirdPerson") == 1) setThirdPersonDOF(player, true); if (isKillstreakWeapon(player.CurrentWeapon)) { player.TakeWeapon(player.CurrentWeapon); player.Call("SwitchToWeapon", player.GetField("lastDroppableWeapon")); } ClearUsingRemote(player); }); }); } private static void staticEffect(Entity ent, float duration) { HudElem staticBG = HudElem.NewClientHudElem(ent); staticBG.HorzAlign = "fullscreen"; staticBG.VertAlign = "fullscreen"; staticBG.SetShader("white", 640, 480); staticBG.Archived = true; staticBG.Sort = 10; HudElem _static = HudElem.NewClientHudElem(ent); _static.HorzAlign = "fullscreen"; _static.VertAlign = "fullscreen"; _static.SetShader("ac130_overlay_grain", 640, 480); _static.Archived = true; _static.Sort = 20; ent.AfterDelay(Convert.ToInt32(duration * 1000), entity => { staticBG.Call("destroy"); _static.Call("destroy"); }); } } }Pressing 3 ("+actionslot 3") will give you a predator missile which you can call by pressing 4 (see icon on the killstreak bar).
Problems:
- Missing check for nuke/emp
- Missing splash notify for killstreak
- Noncomplete spawn system for predator (because of 'GetEntArray' not working as in r28) (the current default spawn is most of the time too far away)
It's probably more useful and smarter to put the common functions into a _Utility.dll (or whatever) which can then be used as a reference by various killstreak dlls, but I haven't done this yet.