using System; using System.Reflection; using System.Text.RegularExpressions; using System.Collections.Generic; using System.ComponentModel; using CLRScriptFramework; using NWScript; using NWScript.ManagedInterfaceLayer.NWScriptManagedInterface; using NWEffect = NWScript.NWScriptEngineStructure0; using NWEvent = NWScript.NWScriptEngineStructure1; using NWLocation = NWScript.NWScriptEngineStructure2; using NWTalent = NWScript.NWScriptEngineStructure3; using NWItemProperty = NWScript.NWScriptEngineStructure4; using Newtonsoft.Json; namespace CLRScript { using NWScript = nwn2ai_onmoduleload; class Agent{ public uint objref; public Agent(uint obj){ objref = obj; } public float facing{ get{ return _facing; } set{ _facing = value; NWScript.get.AssignCommand(objref, ()=>{NWScript.get.SetFacing(_facing, 1);}); } } public NWLocation loc{ get{ return _loc; } set{ _loc = value; NWScript.get.AssignCommand(objref, ()=>{NWScript.get.ActionForceMoveToLocation(_loc, 1, 6f);}); //Link effect NWScript.get.RemoveSEFFromObject(objref, "nwai_beam_loc"); NWScript.get.ApplyEffectToObject( NWScript.DURATION_TYPE_PERMANENT, NWScript.get.EffectNWN2SpecialEffectFile("nwai_beam_loc", NWScript.OBJECT_INVALID, NWScript.get.GetPositionFromLocation(_loc)), objref, -1f); } } //Detection //======================================================================= public bool hasWallFront(float distance=10f){ Vector3 pointFront = Add(NWScript.get.GetPositionFromLocation(loc), Multiply(NWScript.get.AngleToVector(facing), distance)); return NWScript.get.LineOfSightVector(NWScript.get.GetPosition(objref), pointFront)==1; } public bool isInCombat(){ return NWScript.get.GetIsInCombat(objref)==1; } //Json containing // {"valid":"true", "id":"366642", "name":"Goblin", "distance":"13.37", "difficulty":"13", "hp":"12"} public dynamic getNearestEnemy(float distanceMax=15f){ uint nearestEnemy = NWScript.get.GetNearestCreature( NWScript.CREATURE_TYPE_REPUTATION, NWScript.REPUTATION_TYPE_ENEMY, objref, 1, NWScript.CREATURE_TYPE_PERCEPTION, NWScript.PERCEPTION_SEEN_AND_HEARD, NWScript.CREATURE_TYPE_IS_ALIVE, NWScript.CREATURE_ALIVE_TRUE); float dist = NWScript.get.GetDistanceBetween(nearestEnemy, objref); return JsonConvert.DeserializeObject("{" + "\"valid\":\""+(NWScript.get.GetIsObjectValid(nearestEnemy)==1 && dist<=distanceMax).ToString()+"\"," + "\"id\":\""+(nearestEnemy).ToString()+"\"," + "\"name\":\""+NWScript.get.GetName(nearestEnemy)+"\"" + "\"distance\":\""+(dist).ToString()+"\"," + "\"difficulty\":\""+NWScript.get.GetChallengeRating(nearestEnemy)+"\"" + "\"hp\":\""+NWScript.get.GetCurrentHitPoints(nearestEnemy)+"\"" + "}"); } //Json containing // {"valid":"true", "id":"366642", "name":"Guethenoc", "distance":"13.37"} public dynamic getNearestPlayer(float distanceMax=15f){ uint pc = NWScript.get.GetNearestCreature(NWScript.CREATURE_TYPE_PLAYER_CHAR, NWScript.PLAYER_CHAR_IS_PC, objref, 1, -1,-1,-1,-1); float dist = NWScript.get.GetDistanceBetween(pc, objref); return JsonConvert.DeserializeObject("{" + "\"valid\":\""+(NWScript.get.GetIsObjectValid(pc)==1 && dist<=distanceMax).ToString()+"\"," + "\"id\":\""+(pc).ToString()+"\"," + "\"name\":\""+NWScript.get.GetName(pc)+"\"" + "\"distance\":\""+(dist).ToString()+"\"," + "}"); } //Actions //======================================================================= public bool moveForward(float distance=10f){ if(hasWallFront(distance)) return false; //See NWN2DataLib.AreaSurfaceMesh.PathExists Vector3 pointFront = Add(NWScript.get.GetPositionFromLocation(loc), Multiply(NWScript.get.AngleToVector(facing), distance)); loc = NWScript.get.Location(NWScript.get.GetAreaFromLocation(loc), pointFront, facing); return true; } public bool attackNearest(float distanceMax=15f){ var nearest = getNearestEnemy(distanceMax); if(!nearest.valid) return false; NWScript.get.AssignCommand(objref, ()=>{NWScript.get.ActionAttack(nearest.id, 0);}); return true; } public bool turn(float angleDeg){ facing+=angleDeg; return true; } public bool say(string message){ NWScript.get.AssignCommand(objref, ()=>{NWScript.get.SpeakString(message, NWScript.TALKVOLUME_TALK);}); return getNearestPlayer().valid; } public string callCommand(string command) { Regex regexMethod = new Regex(@"([a-zA-Z_]+?)\s*\((.*?)\)"); Regex regexParam = new Regex("(\".*?\"|[0-9\\.]+)"); string methodName; List unparsedParams = new List(); MatchCollection matches = regexMethod.Matches(command); if(matches.Count == 1){ //Match name methodName = matches[0].Groups[1].ToString(); //March parameters string methodParamList = matches[0].Groups[2].ToString(); MatchCollection paramMatches = regexParam.Matches(methodParamList); foreach(var p in paramMatches){ unparsedParams.Add(p.ToString().Trim('"')); } } else{ //Failed to parse command return ""; } MethodInfo method = this.GetType().GetMethod(methodName); ParameterInfo[] methodParams = method.GetParameters(); if(methodParams.Length != unparsedParams.Count){ //Incorrect number of parameters return ""; } List parsedParams = new List(); for(int i=0 ; i