public void Apply(VMAvatar avatar) { avatar.SkinTone = (AppearanceType)SkinTone; for (int i = 0; i < PersonDataMap.Length; i++) { avatar.ForceEnableSkill = true; avatar.SetPersonData((VMPersonDataVariable)PersonDataMap[i], PersonData[i]); avatar.ForceEnableSkill = false; } avatar.SetPersonData(VMPersonDataVariable.SkinColor, SkinTone); avatar.DefaultSuits = DefaultSuits; avatar.BodyOutfit = new VMOutfitReference(BodyOutfit); avatar.HeadOutfit = new VMOutfitReference(HeadOutfit); avatar.Name = Name; avatar.AvatarState.Permissions = Permissions; ((VMTSOAvatarState)avatar.TSOState).Flags = AvatarFlags; avatar.TSOState.Budget.Value = Budget; avatar.PersistID = PersistID; avatar.ReplaceMotiveData(MotiveData); avatar.MeToPersist = new Dictionary <uint, List <short> >(); foreach (var obj in Relationships) { avatar.MeToPersist[obj.Target] = new List <short>(obj.Values); } ((VMTSOAvatarState)avatar.TSOState).JobInfo = OnlineJobInfo; if (IsWorker) { avatar.SetPersonData(VMPersonDataVariable.OnlineJobStatusFlags, 1); //validated immediately. } avatar.SkillLocks = SkillLock; ((VMTSOAvatarState)avatar.TSOState).IgnoredAvatars = IgnoredAvatars; }
public NetworkClient Client; //REPLACE WHEN MOVING OFF GONZONET!! public override bool Execute(VM vm) { Name = Name.Substring(0, Math.Min(Name.Length, 64)); var sim = vm.Context.CreateObjectInstance(VMAvatar.TEMPLATE_PERSON, LotTilePos.OUT_OF_WORLD, Direction.NORTH, false).Objects[0]; var mailbox = vm.Entities.FirstOrDefault(x => (x.Object.OBJ.GUID == 0xEF121974 || x.Object.OBJ.GUID == 0x1D95C9B0 || x.Object.OBJ.GUID == 0x865A6812)); LotTilePos pos = mailbox.Position; pos.x = (short)(mailbox.Position.x + 1); pos.y = (short)(mailbox.Position.y + 1); if (VM.UseWorld) { TSO.HIT.HITVM.Get().PlaySoundEvent("lot_enter"); } if (mailbox != null) { VMFindLocationFor.FindLocationFor(sim, mailbox, vm.Context); } ((VMAvatar)sim).Visitor = ActorUID == 0 ? true : false; sim.PersistID = ActorUID; VMAvatar avatar = (VMAvatar)sim; avatar.SkinTone = (Vitaboy.AppearanceType)SkinTone; avatar.SetPersonData(VMPersonDataVariable.Gender, (short)((Gender) ? 1 : 0)); avatar.DefaultSuits = new VMAvatarDefaultSuits(Gender); avatar.DefaultSuits.Daywear = BodyID; avatar.BodyOutfit = BodyID; avatar.HeadOutfit = HeadID; avatar.Name = Name; ((VMTSOAvatarState)avatar.TSOState).Budget.Value = 999999; ((VMTSOAvatarState)avatar.TSOState).Permissions = Permissions; avatar.SetPosition(pos, Direction.WEST, vm.Context); if (ActorUID == uint.MaxValue - 1) { avatar.SetValue(VMStackObjectVariable.Hidden, 1); avatar.SetPosition(LotTilePos.OUT_OF_WORLD, Direction.NORTH, vm.Context); avatar.SetFlag(VMEntityFlags.HasZeroExtent, true); avatar.SetPersonData(VMPersonDataVariable.IsGhost, 1); //oooooOOooooOo } if (RequesterID == vm.MyUID) { vm.MyUID = ActorUID; //we're this sim! try send commands as them. } vm.SignalChatEvent(new VMChatEvent(avatar.PersistID, VMChatEventType.Join, avatar.Name)); return(true); }
public override bool Execute(VM vm, VMAvatar caller) { //need caller to be present if (caller == null) { return(false); } var limit = caller.SkillLocks; SkillID = Math.Min(SkillID, (byte)5); //must be 0-5 int otherLocked = 0; for (int i = 0; i < 6; i++) //sum other skill locks to see what we can feasibly put in this skill { if (i == SkillID) { continue; } otherLocked += caller.GetPersonData((VMPersonDataVariable)((int)VMPersonDataVariable.SkillLockBase + i)) / 100; } if (otherLocked >= limit) { return(false); //cannot lock this skill at all } LockLevel = (short)Math.Min(caller.GetPersonData(LockToSkill[SkillID]) / 100, Math.Min(LockLevel, (short)(limit - otherLocked))); //can only lock up to the limit caller.SetPersonData((VMPersonDataVariable)((int)VMPersonDataVariable.SkillLockBase + SkillID), (short)(LockLevel * 100)); return(true); }
public override bool Execute(VM vm) { var sim = vm.Context.CreateObjectInstance(VMAvatar.TEMPLATE_PERSON, LotTilePos.OUT_OF_WORLD, Direction.NORTH).Objects[0]; var mailbox = vm.Entities.FirstOrDefault(x => (x.Object.OBJ.GUID == 0xEF121974 || x.Object.OBJ.GUID == 0x1D95C9B0)); if (VM.UseWorld) { FSO.HIT.HITVM.Get().PlaySoundEvent("lot_enter"); } if (mailbox != null) { VMFindLocationFor.FindLocationFor(sim, mailbox, vm.Context); } sim.PersistID = SimID; VMAvatar avatar = (VMAvatar)sim; avatar.SkinTone = (Vitaboy.AppearanceType)SkinTone; avatar.SetPersonData(VMPersonDataVariable.Gender, (short)((Gender) ? 1 : 0)); avatar.DefaultSuits = new VMAvatarDefaultSuits(Gender); avatar.DefaultSuits.Daywear = BodyID; avatar.BodyOutfit = BodyID; avatar.HeadOutfit = HeadID; avatar.Name = Name; vm.SignalChatEvent(new VMChatEvent(avatar.PersistID, VMChatEventType.Join, avatar.Name)); return(true); }
public NetworkClient Client; //REPLACE WHEN MOVING OFF GONZONET!! public override bool Execute(VM vm) { Name = Name.Substring(0, Math.Min(Name.Length, 64)); var sim = vm.Context.CreateObjectInstance(VMAvatar.TEMPLATE_PERSON, LotTilePos.OUT_OF_WORLD, Direction.NORTH).Objects[0]; var mailbox = vm.Entities.FirstOrDefault(x => (x.Object.OBJ.GUID == 0xEF121974 || x.Object.OBJ.GUID == 0x1D95C9B0)); if (VM.UseWorld) { TSO.HIT.HITVM.Get().PlaySoundEvent("lot_enter"); } if (mailbox != null) { VMFindLocationFor.FindLocationFor(sim, mailbox, vm.Context); } sim.PersistID = ActorUID; VMAvatar avatar = (VMAvatar)sim; avatar.SkinTone = (Vitaboy.AppearanceType)SkinTone; avatar.SetPersonData(VMPersonDataVariable.Gender, (short)((Gender) ? 1 : 0)); avatar.BodyOutfit = BodyID; avatar.HeadOutfit = HeadID; avatar.Name = Name; ((VMTSOAvatarState)avatar.TSOState).Permissions = Permissions; return(true); }
public override bool Execute(VM vm, VMAvatar avatar) { if (Message.Length == 0) { return(false); } if (Message.Length > 200) { Message = Message.Substring(0, 200); } if (avatar == null) { return(false); } if (Message[0] == '/' && Message.Length > 1) { var spaceIndex = Message.IndexOf(' '); if (spaceIndex == -1) { spaceIndex = Message.Length; } if ((FromNet && avatar.AvatarState.Permissions < VMTSOAvatarPermissions.Admin) || !(vm.Driver is VMServerDriver)) { return(false); } //commands are only run from the server sim right now var cmd = Message.Substring(1, spaceIndex - 1); var args = Message.Substring(Math.Min(Message.Length, spaceIndex + 1), Math.Max(0, Message.Length - (spaceIndex + 1))); var server = (VMServerDriver)vm.Driver; VMEntity sim; switch (cmd.ToLowerInvariant()) { case "ban": server.BanUser(vm, args); break; case "banip": server.BanIP(args); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Added " + args + " to the IP ban list.")); break; case "unban": server.SandboxBans.Remove(args.ToLowerInvariant().Trim(' ')); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Removed " + args + " from the IP ban list.")); break; case "banlist": string result = ""; foreach (var ban in server.SandboxBans.List()) { result += ban + "\r\n"; } vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "==== BANNED IPS: ==== \r\n" + result)); break; case "builder": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.BuildBuyRoommate, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " a build-roommate.")); } break; case "admin": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.Admin, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " an admin.")); } break; case "roomie": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.Roommate, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " a roommate.")); } break; case "visitor": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.Visitor, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " a visitor.")); } break; case "close": if (FromNet) { return(false); } vm.CloseNet(VMCloseNetReason.ServerShutdown); break; case "qtrday": var count = int.Parse(args); for (int i = 0; i < count; i++) { vm.ProcessQTRDay(); } vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Ran " + count + " quarter days.")); break; case "setjob": var jobsplit = args.Split(' '); if (jobsplit.Length < 2) { return(true); } var jobid = short.Parse(jobsplit[0]); var jobgrade = short.Parse(jobsplit[1]); avatar.SetPersonData(SimAntics.Model.VMPersonDataVariable.OnlineJobID, jobid); avatar.SetPersonData(SimAntics.Model.VMPersonDataVariable.OnlineJobGrade, jobgrade); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Set " + avatar.ToString() + " job grade/type to " + jobgrade + "/" + jobid + ".")); break; case "trace": //enables desync tracing vm.UseSchedule = false; vm.Trace = new Engine.Debug.VMSyncTrace(); break; case "reload": //enables desync tracing var servD = vm.Driver as VMServerDriver; vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Debug, "Manually requested self resync.")); if (servD != null) { servD.SelfResync = true; } break; case "time": var timesplit = args.Split(' '); if (timesplit.Length < 2) { return(true); } vm.Context.Clock.Hours = int.Parse(timesplit[0]); vm.Context.Clock.Minutes = int.Parse(timesplit[1]); vm.Context.Clock.MinuteFractions = 0; break; } return(true); } else { vm.SignalChatEvent(new VMChatEvent(avatar, VMChatEventType.Message, (byte)(ChannelID & 0x7f), avatar.Name, Message)); if ((ChannelID & 0x80) == 0) { avatar.Message = Message; } return(true); } }
//variables used locally for deferred avatar loading public override bool Execute(VM vm) { if (vm.TS1) { if (vm.CurrentFamily == null) { return(true); } var gameState = Content.Content.Get().Neighborhood.GameState; var control = vm.Entities.FirstOrDefault(x => x is VMAvatar && !((VMAvatar)x).IsPet && ((VMAvatar)x).GetPersonData(VMPersonDataVariable.TS1FamilyNumber) == vm.CurrentFamily?.ChunkID); if (control == null) { control = vm.Context.CreateObjectInstance((gameState.DowntownSimGUID == 0)?0x32AA2056:gameState.DowntownSimGUID, LotTilePos.OUT_OF_WORLD, Direction.NORTH)?.BaseObject; control?.SetPosition(LotTilePos.FromBigTile(1, 1, 1), Direction.NORTH, vm.Context); } if (control != null) { var ava = (VMAvatar)control; ava.PersistID = ActorUID; ((VMTSOAvatarState)(ava.TSOState)).Permissions = VMTSOAvatarPermissions.Admin; ava.TSOState.Budget.Value = 1000000; vm.Context.ObjectQueries.RegisterAvatarPersist(ava, ava.PersistID); vm.SetGlobalValue(3, control.ObjectID); } return(true); } var name = AvatarState.Name.Substring(0, Math.Min(AvatarState.Name.Length, 64)); var sim = vm.Context.CreateObjectInstance(VMAvatar.TEMPLATE_PERSON, LotTilePos.OUT_OF_WORLD, Direction.NORTH).Objects[0]; var mailbox = vm.Entities.FirstOrDefault(x => (x.Object.OBJ.GUID == 0xEF121974 || x.Object.OBJ.GUID == 0x1D95C9B0)); if (VM.UseWorld) { FSO.HIT.HITVM.Get().PlaySoundEvent("lot_enter"); } if (mailbox != null) { VMFindLocationFor.FindLocationFor(sim, mailbox, vm.Context, VMPlaceRequestFlags.Default); } else { sim.SetPosition(LotTilePos.FromBigTile(3, 3, 1), Direction.NORTH, vm.Context); } sim.PersistID = ActorUID; VMAvatar avatar = (VMAvatar)sim; AvatarState.Apply(avatar); var oldRoomCount = vm.TSOState.Roommates.Count; //some off lot changes may have occurred. Keep things up to date if we're caught between database sync points (TODO: right now never, but should happen on every roomie change). if (AvatarState.Permissions > VMTSOAvatarPermissions.Visitor && AvatarState.Permissions < VMTSOAvatarPermissions.Admin) { if (!vm.TSOState.Roommates.Contains(AvatarState.PersistID)) { vm.TSOState.Roommates.Add(AvatarState.PersistID); if (AvatarState.Permissions > VMTSOAvatarPermissions.Roommate) { vm.TSOState.BuildRoommates.Add(AvatarState.PersistID); } else { vm.TSOState.BuildRoommates.Remove(AvatarState.PersistID); } VMBuildableAreaInfo.UpdateOverbudgetObjects(vm); } } else if (AvatarState.Permissions != VMTSOAvatarPermissions.Admin) { if (vm.TSOState.Roommates.Contains(AvatarState.PersistID)) { vm.TSOState.Roommates.Remove(AvatarState.PersistID); vm.TSOState.BuildRoommates.Remove(AvatarState.PersistID); VMBuildableAreaInfo.UpdateOverbudgetObjects(vm); } } if (oldRoomCount != vm.TSOState.Roommates.Count) { //mark objects not owned by roommates for inventory transfer foreach (var ent in vm.Entities) { if (ent is VMGameObject && ent.PersistID > 0 && ((VMTSOObjectState)ent.TSOState).OwnerID == avatar.PersistID) { var old = ((VMGameObject)ent).Disabled; if (AvatarState.Permissions < VMTSOAvatarPermissions.Roommate) { ((VMGameObject)ent).Disabled |= VMGameObjectDisableFlags.PendingRoommateDeletion; } else { ((VMGameObject)ent).Disabled &= ~VMGameObjectDisableFlags.PendingRoommateDeletion; } if (old != ((VMGameObject)ent).Disabled) { vm.Scheduler.RescheduleInterrupt(ent); } ((VMGameObject)ent).RefreshLight(); } } } vm.Context.ObjectQueries.RegisterAvatarPersist(avatar, avatar.PersistID); if (ActorUID == uint.MaxValue - 1) { avatar.SetValue(VMStackObjectVariable.Hidden, 1); avatar.SetPosition(LotTilePos.OUT_OF_WORLD, Direction.NORTH, vm.Context); avatar.SetFlag(VMEntityFlags.HasZeroExtent, true); avatar.SetPersonData(VMPersonDataVariable.IsGhost, 1); //oooooOOooooOo } vm.SignalChatEvent(new VMChatEvent(avatar.PersistID, VMChatEventType.Join, avatar.Name)); return(true); }
public override bool Execute(VM vm, VMAvatar avatar) { if (Message.Length == 0) { return(false); } if (Message.Length > 200) { Message = Message.Substring(0, 200); } if (avatar == null) { return(false); } if (Message[0] == '/' && Message.Length > 1) { var spaceIndex = Message.IndexOf(' '); if (spaceIndex == -1) { spaceIndex = Message.Length; } if ((FromNet && avatar.AvatarState.Permissions < VMTSOAvatarPermissions.Admin) || !(vm.Driver is VMServerDriver)) { return(false); } //commands are only run from the server sim right now var cmd = Message.Substring(1, spaceIndex - 1); var args = Message.Substring(Math.Min(Message.Length, spaceIndex + 1), Math.Max(0, Message.Length - (spaceIndex + 1))); var server = (VMServerDriver)vm.Driver; VMEntity sim; switch (cmd.ToLowerInvariant()) { case "ban": server.BanUser(vm, args); break; case "banip": server.BanIP(args); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Added " + args + " to the IP ban list.")); break; case "unban": server.SandboxBans.Remove(args.ToLowerInvariant().Trim(' ')); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Removed " + args + " from the IP ban list.")); break; case "banlist": string result = ""; foreach (var ban in server.SandboxBans.List()) { result += ban + "\r\n"; } vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "==== BANNED IPS: ==== \r\n" + result)); break; case "builder": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.BuildBuyRoommate, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " a build-roommate.")); } break; case "admin": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.Admin, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " an admin.")); } break; case "roomie": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.Roommate, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " a roommate.")); } break; case "visitor": sim = vm.Entities.Where(x => x is VMAvatar && x.ToString().ToLowerInvariant().Trim(' ') == args.ToLowerInvariant().Trim(' ')).FirstOrDefault(); if (sim != null) { vm.ForwardCommand(new VMChangePermissionsCmd() { TargetUID = sim.PersistID, Level = VMTSOAvatarPermissions.Visitor, Verified = true }); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Made " + sim.Name + " a visitor.")); } break; case "close": if (FromNet) { return(false); } vm.CloseNet(VMCloseNetReason.ServerShutdown); break; case "qtrday": var count = int.Parse(args); for (int i = 0; i < count; i++) { vm.ProcessQTRDay(); } vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Ran " + count + " quarter days.")); break; case "setjob": var jobsplit = args.Split(' '); if (jobsplit.Length < 2) { return(true); } var jobid = short.Parse(jobsplit[0]); var jobgrade = short.Parse(jobsplit[1]); avatar.SetPersonData(SimAntics.Model.VMPersonDataVariable.OnlineJobID, jobid); avatar.SetPersonData(SimAntics.Model.VMPersonDataVariable.OnlineJobGrade, jobgrade); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Set " + avatar.ToString() + " job grade/type to " + jobgrade + "/" + jobid + ".")); break; case "trace": //enables desync tracing vm.UseSchedule = false; vm.Trace = new Engine.Debug.VMSyncTrace(); break; case "reload": //enables desync tracing var servD = vm.Driver as VMServerDriver; vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Debug, "Manually requested self resync.")); if (servD != null) { servD.SelfResync = true; } break; case "time": var timesplit = args.Split(' '); if (timesplit.Length < 2) { return(true); } vm.Context.Clock.Hours = int.Parse(timesplit[0]); vm.Context.Clock.Minutes = int.Parse(timesplit[1]); vm.Context.Clock.MinuteFractions = 0; break; case "tuning": var tuningsplit = args.Split(' '); if (tuningsplit.Length < 4) { return(true); } vm.Tuning.AddTuning(new Common.Model.DynTuningEntry() { tuning_type = tuningsplit[0], tuning_table = int.Parse(tuningsplit[1]), tuning_index = int.Parse(tuningsplit[2]), value = float.Parse(tuningsplit[3]), }); vm.ForwardCommand(new VMNetTuningCmd() { Tuning = vm.Tuning }); break; case "fixall": var fixCount = 0; foreach (var ent in vm.Entities) { if (ent is VMGameObject && ent == ent.MultitileGroup.BaseObject) { var state = (VMTSOObjectState)ent.TSOState; if (state.Broken) { foreach (var objr in ent.MultitileGroup.Objects) { ((VMGameObject)objr).DisableParticle(256); } fixCount++; } state.QtrDaysSinceLastRepair = 0; state.Wear = 0; } } vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Generic, "Fixed " + fixCount + " objects.")); break; case "testcollision": vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Debug, $"Scanning collision for lot { vm.TSOState.Name }.")); try { var collisionValidator = new CollisionTestUtils(); collisionValidator.VerifyAllCollision(vm); vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Debug, "No issue detected with collision.")); } catch (Exception e) { vm.SignalChatEvent(new VMChatEvent(null, VMChatEventType.Debug, e.Message)); } break; } return(true); } else { vm.SignalChatEvent(new VMChatEvent(avatar, VMChatEventType.Message, (byte)(ChannelID & 0x7f), avatar.Name, Message)); if ((ChannelID & 0x80) == 0) { avatar.Message = Message; } UpdateTalkingHeadSeek(vm, avatar); return(true); } }
public override VMPrimitiveExitCode Execute(VMStackFrame context, VMPrimitiveOperand args) { var operand = (VMLookTowardsOperand)args; //TODO: primitive fails if object calls it VMAvatar sim = (VMAvatar)context.Caller; var result = new VMFindLocationResult(); result.Position = new LotTilePos(sim.Position); LotTilePos pos = new LotTilePos(); switch (operand.Mode) { case VMLookTowardsMode.HeadTowardsObject: //set default state sim.SetPersonData(VMPersonDataVariable.HeadSeekObject, context.StackObjectID); sim.SetPersonData(VMPersonDataVariable.HeadSeekState, 1); //in progress flag only sim.SetPersonData(VMPersonDataVariable.HeadSeekLimitAction, 1); //look back on limit? sim.SetPersonData(VMPersonDataVariable.HeadSeekFinishAction, 0); //unknown sim.SetPersonData(VMPersonDataVariable.HeadSeekTimeout, 0); //forever return(VMPrimitiveExitCode.GOTO_TRUE); //TODO: turning head towards things, with head seek timeout case VMLookTowardsMode.BodyTowardsCamera: return(VMPrimitiveExitCode.GOTO_TRUE); //does not work in TSO case VMLookTowardsMode.BodyTowardsStackObj: result.RadianDirection = (float)GetDirectionTo(sim.Position, context.StackObject.Position); break; case VMLookTowardsMode.BodyAwayFromStackObj: result.RadianDirection = (float)GetDirectionTo(sim.Position, context.StackObject.Position); result.RadianDirection = (float)((result.RadianDirection + Math.PI) % (Math.PI * 2)); break; case VMLookTowardsMode.BodyTowardsAverageStackObj: foreach (var obj in context.StackObject.MultitileGroup.Objects) { pos += obj.Position; } pos /= context.StackObject.MultitileGroup.Objects.Count; result.RadianDirection = (float)GetDirectionTo(sim.Position, pos); break; case VMLookTowardsMode.BodyAwayFromAverageStackObj: foreach (var obj in context.StackObject.MultitileGroup.Objects) { pos += obj.Position; } pos /= context.StackObject.MultitileGroup.Objects.Count; result.RadianDirection = (float)GetDirectionTo(sim.Position, pos); result.RadianDirection = (float)((result.RadianDirection + Math.PI) % (Math.PI * 2)); break; } if (context.Thread.IsCheck) { return(VMPrimitiveExitCode.GOTO_FALSE); } var pathFinder = context.Thread.PushNewRoutingFrame(context, false); //use the path finder to do the turn animation. pathFinder.InitRoutes(new List <VMFindLocationResult>() { result }); return(VMPrimitiveExitCode.CONTINUE); }