NWN2-AI-Server/nwn2ai_onmoduleload/Agent.cs

194 lines
5.8 KiB
C#

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
{
class Agent : CLRScriptBase{
public uint objref;
public Agent(uint obj){
objref = obj;
}
public float facing{
get{
return _facing;
}
set{
_facing = value;
AssignCommand(objref, ()=>{SetFacing(_facing, TRUE);});
}
}
public NWLocation loc{
get{
return _loc;
}
set{
_loc = value;
AssignCommand(objref, ()=>{ActionForceMoveToLocation(_loc, TRUE, 6f);});
//Link effect
RemoveSEFFromObject(objref, "nwai_beam_loc");
ApplyEffectToObject(DURATION_TYPE_PERMANENT, EffectNWN2SpecialEffectFile("nwai_beam_loc", OBJECT_INVALID, GetPositionFromLocation(_loc)), objref, -1f);
}
}
//Detection
//=======================================================================
public bool hasWallFront(float distance=10f){
Vector3 pointFront = Add(GetPositionFromLocation(loc), Multiply(AngleToVector(facing), distance));
return LineOfSightVector(GetPosition(objref), pointFront)==1;
}
public bool isInCombat(){
return 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 = GetNearestCreature(
CREATURE_TYPE_REPUTATION, REPUTATION_TYPE_ENEMY,
objref, 1,
CREATURE_TYPE_PERCEPTION, PERCEPTION_SEEN_AND_HEARD,
CREATURE_TYPE_IS_ALIVE, CREATURE_ALIVE_TRUE);
float dist = GetDistanceBetween(nearestEnemy, objref);
return JsonConvert.DeserializeObject<dynamic>("{"
+ "\"valid\":\""+(GetIsObjectValid(nearestEnemy)==TRUE && dist<=distanceMax).ToString()+"\","
+ "\"id\":\""+(nearestEnemy).ToString()+"\","
+ "\"name\":\""+GetName(nearestEnemy)+"\""
+ "\"distance\":\""+(dist).ToString()+"\","
+ "\"difficulty\":\""+GetChallengeRating(nearestEnemy)+"\""
+ "\"hp\":\""+GetCurrentHitPoints(nearestEnemy)+"\""
+ "}");
}
//Json containing
// {"valid":"true", "id":"366642", "name":"Guethenoc", "distance":"13.37"}
public dynamic getNearestPlayer(float distanceMax=15f){
uint pc = GetNearestCreature(CREATURE_TYPE_PLAYER_CHAR, PLAYER_CHAR_IS_PC, objref, 1, -1,-1,-1,-1);
float dist = GetDistanceBetween(pc, objref);
return JsonConvert.DeserializeObject<dynamic>("{"
+ "\"valid\":\""+(GetIsObjectValid(pc)==TRUE && dist<=distanceMax).ToString()+"\","
+ "\"id\":\""+(pc).ToString()+"\","
+ "\"name\":\""+GetName(pc)+"\""
+ "\"distance\":\""+(dist).ToString()+"\","
+ "}");
}
//Actions
//=======================================================================
public bool moveForward(float distance=10f){
if(hasWallFront(distance))
return false;
//See NWN2DataLib.AreaSurfaceMesh.PathExists
Vector3 pointFront = Add(GetPositionFromLocation(loc), Multiply(AngleToVector(facing), distance));
loc = Location(GetAreaFromLocation(loc), pointFront, facing);
return true;
}
public bool attackNearest(float distanceMax=15f){
var nearest = getNearestEnemy(distanceMax);
if(!nearest.valid)
return false;
AssignCommand(objref, ()=>{ActionAttack(nearest.id, FALSE);});
return true;
}
public bool turn(float angleDeg){
facing+=angleDeg;
return true;
}
public bool say(string message){
AssignCommand(objref, ()=>{SpeakString(message, 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<string> unparsedParams = new List<string>();
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<Object> parsedParams = new List<Object>();
for(int i=0 ; i<methodParams.Length ; i++){
//Handle defaults?
var typeConverter = TypeDescriptor.GetConverter(methodParams[i].ParameterType);
parsedParams.Add(typeConverter.ConvertFromString(unparsedParams[i]));
}
return method.Invoke(this, parsedParams.ToArray()).ToString();
}
private float _facing;
private NWLocation _loc;
private Vector3 Multiply(Vector3 v, float f) {
v.x*=f; v.y*=f; v.z*=f;
return v;
}
private Vector3 Add(Vector3 v, Vector3 w) {
v.x*=w.x; v.y*=w.y; v.z*=w.z;
return v;
}
}
}