public InventoryGrid(Actor owner, int rows, int columns, int slot = 0) { this._backpack = new uint[rows, columns]; this._owner = owner; this.Items = new Dictionary<uint, Item>(); this.EquipmentSlot = slot; }
public bool RunPower(Actor user, PowerScript power, Actor target = null, Vector3D targetPosition = null, TargetMessage targetMessage = null) { // replace power with existing channel instance if one exists if (power is ChanneledSkill) { var existingChannel = _FindChannelingSkill(user, power.PowerSNO); if (existingChannel != null) { power = existingChannel; } else // new channeled skill, add it to the list { _channeledSkills.Add((ChanneledSkill)power); } } // copy in context params power.User = user; power.Target = target; power.World = user.World; power.TargetPosition = targetPosition; power.TargetMessage = targetMessage; _StartScript(power); return true; }
// generates a random item from given type category. // we can also set a difficulty mode parameter here, but it seems current db doesnt have nightmare or hell-mode items with valid snoId's /raist. public static Item GenerateRandom(Actor player, ItemType type) { var validDefinitions = ItemDefinitions[type].Where(definition => definition.SNOId != 0).ToList(); // only find item definitions with snoId!=0 for given itemtype. var itemDefinition = GetRandom(validDefinitions); return CreateItem(player, itemDefinition); }
// get nearest target of targetType public static Actor GetNearestTarget(World world, Actor attacker, Vector3D centerPosition, float range, ActorType targetType = ActorType.Monster) { Actor result = null; List<Actor> actors = world.QuadTree.Query<Actor>(new Circle(centerPosition.X, centerPosition.Y, range)); if (actors.Count > 1) { float distanceNearest = range; // max. range float distance = 0f; foreach (var target in actors.Where(target => ((target.ActorType == targetType) && (target != attacker) && !target.Attributes[GameAttribute.Is_NPC]))) { if ((target.World == null) || (world.GetActorByDynamicId(target.DynamicID) == null)) { // leaving world continue; } distance = ActorUtils.GetDistance(centerPosition, target.Position); if ((result == null) || (distance < distanceNearest)) { result = target; distanceNearest = distance; } } } return result; }
public void PlayAnimation(Actor actor, int animationId) { if (actor == null) return; foreach (Mooege.Core.GS.Player.Player player in actor.World.GetPlayersInRange(actor.Position, 150f)) { //Stop actor current animation player.InGameClient.SendMessage(new ANNDataMessage(Opcodes.ANNDataMessage13) { ActorID = actor.DynamicID }); player.InGameClient.SendMessage(new PlayAnimationMessage() { ActorID = actor.DynamicID, Field1 = 0xb, Field2 = 0, tAnim = new PlayAnimationMessageSpec[1] { new PlayAnimationMessageSpec() { Field0 = 0x2, Field1 = animationId, Field2 = 0x0, Field3 = 0.6f } } }); } }
//This submits a request for a path to the pathfinder thread. This is the main point of entry for usage. - DarkLotus public PathRequestTask GetPath(Actor owner, Vector3D vector3D, Vector3D heading) { if (aipather == null) aipather = new Pathfinder(); var pathRequestTask = new PathRequestTask(aipather, owner, owner.Position, heading); _queuedPathTasks.TryAdd(owner.DynamicID, pathRequestTask); return pathRequestTask; }
public HitPayload(AttackPayload attackPayload, bool criticalHit, Actor target) : base(attackPayload.Context, target) { this.IsCriticalHit = criticalHit; // TODO: select these values based on element type? float weaponMinDamage = this.Context.User.Attributes[GameAttribute.Damage_Weapon_Min_Total, 0]; float weaponDamageDelta = this.Context.User.Attributes[GameAttribute.Damage_Weapon_Delta_Total, 0]; // calculate and add up damage amount for each element type this.ElementDamages = new Dictionary<DamageType, float>(); foreach (var entry in attackPayload.DamageEntries) { if (!this.ElementDamages.ContainsKey(entry.DamageType)) this.ElementDamages[entry.DamageType] = 0f; if (entry.IsWeaponBasedDamage) this.ElementDamages[entry.DamageType] += entry.WeaponDamageMultiplier * (weaponMinDamage + (float)PowerContext.Rand.NextDouble() * weaponDamageDelta); else this.ElementDamages[entry.DamageType] += entry.MinDamage + (float)PowerContext.Rand.NextDouble() * entry.DamageDelta; this.ElementDamages[entry.DamageType] *= 1.0f + this.Target.Attributes[GameAttribute.Amplify_Damage_Percent]; } // apply critical damage boost if (criticalHit) { // TODO: probably will calculate this off of GameAttribute.Crit_Damage_Percent, but right now that attribute is never set var damTypes = this.ElementDamages.Keys.ToArray(); foreach (var type in damTypes) this.ElementDamages[type] *= 1.5f + this.Target.Attributes[GameAttribute.Crit_Percent_Bonus_Capped]; } // TODO: reduce element damage amounts according to target's resistances // TODO: reduce total damage by target's armor // ~weltmeyer Using WOW Calculation till we find the correct formula :) this.TotalDamage = this.ElementDamages.Sum(kv => kv.Value) ; var targetArmor = target.Attributes[GameAttribute.Armor_Total]; var attackerLevel = attackPayload.Context.User.Attributes[GameAttribute.Level]; var reduction = TotalDamage * (0.1f * targetArmor) / ((8.5f * attackerLevel) + 40); reduction /= 1+reduction; reduction = Math.Min(0.75f, reduction); this.TotalDamage = TotalDamage*(1 - reduction); this.DominantDamageType = this.ElementDamages.OrderByDescending(kv => kv.Value).FirstOrDefault().Key; if (this.DominantDamageType == null) this.DominantDamageType = DamageType.Physical; // default to physical if no other damage type calced }
public bool ActorExists(Actor actor) { return Actors.Any( t => t.SnoId == actor.SnoId && t.Position.X == actor.Position.X && t.Position.Y == actor.Position.Y && t.Position.Z == actor.Position.Z); }
public void Chase(Actor actor) { if (this.Heading == actor.Position) return; this.Target = actor; this.Heading = this.Target.Position; this.Move(this.Target); }
public Minion(World world, int snoId, Actor master, TagMap tags) : base(world, snoId, tags) { // The following two seems to be shared with monsters. One wonders why there isn't a specific actortype for minions. this.Master = master; this.Field2 = 0x8; this.GBHandle.Type = (int)GBHandleType.Monster; this.GBHandle.GBID = 1; this.Attributes[GameAttribute.Summoned_By_ACDID] = (int)master.DynamicID; this.Attributes[GameAttribute.TeamID] = master.Attributes[GameAttribute.TeamID]; }
public void BroadcastIfRevealed(GameMessage message, Actor actor) { foreach (var player in this.Players.Values) { if (player.RevealedObjects.ContainsKey(actor.DynamicID)) { player.InGameClient.SendMessageNow(message); } } }
// shhots projectile at 2D angle public static void ShootAtAngle(World world, Actor projectile, float angle, float speed) { float[] delta = ActorUtils.GetDistanceDelta(speed, angle); world.BroadcastInclusive(new ACDTranslateFixedMessage() { Id = 113, // needed ActorId = unchecked((int)projectile.DynamicID), Velocity = new Vector3D { X = delta[0], Y = delta[1], Z = 0 }, Field2 = 1, AnimationTag = 1,//walkAnimationSNO Field4 = 1, }, projectile); }
public MonsterBrain(Actor body) : base(body) { this.PresetPowers = new List<int>(); // build list of powers defined in monster mpq data if (body.ActorData.MonsterSNO > 0) { var monsterData = (Mooege.Common.MPQ.FileFormats.Monster)MPQStorage.Data.Assets[SNOGroup.Monster][body.ActorData.MonsterSNO].Data; foreach (var monsterSkill in monsterData.SkillDeclarations) { if (monsterSkill.SNOPower > 0) this.PresetPowers.Add(monsterSkill.SNOPower); } } }
public bool UsePower(Actor user, PowerScript power, Actor target = null, Vector3D targetPosition = null, TargetMessage targetMessage = null) { // replace power with existing channel instance if one exists if (power is ChanneledPower) { var chanpow = _FindChannelingPower(user, power.PowerSNO); if (chanpow != null) power = chanpow; } // copy in context params power.User = user; power.Target = target; power.World = user.World; power.TargetPosition = targetPosition; power.TargetMessage = targetMessage; // process channeled power events var channeledPower = power as ChanneledPower; if (channeledPower != null) { if (channeledPower.ChannelOpen) { channeledPower.OnChannelUpdated(); } else { channeledPower.OnChannelOpen(); channeledPower.ChannelOpen = true; _channeledPowers.Add(channeledPower); } } var powerEnum = power.Run().GetEnumerator(); // actual power will first run here, if it yielded a timer process it in the waiting list if (powerEnum.MoveNext() && powerEnum.Current != PowerScript.StopExecution) { _waitingPowers.Add(new WaitingPower { PowerEnumerator = powerEnum, Implementation = power }); } return true; }
public void PlayEffectGroupActorToActor(int effectId, Actor from, Actor target) { if (target == null) return; foreach (Mooege.Core.GS.Player.Player player in from.World.GetPlayersInRange(from.Position, 150f)) { player.InGameClient.SendMessage(new EffectGroupACDToACDMessage() { Id = 0xaa, effectSNO = effectId, fromActorID = from.DynamicID, toActorID = target.DynamicID }); SendDWordTick(player.InGameClient); } }
public void PlayHitEffect(HitEffect id, Actor target, Actor from) { if (target == null) return; foreach (Mooege.Core.GS.Player.Player player in target.World.GetPlayersInRange(target.Position, 150f)) { player.InGameClient.SendMessage(new PlayHitEffectMessage() { Id = 0x7b, ActorID = target.DynamicID, HitDealer = from.DynamicID, Field2 = (int)id, Field3 = false }); SendDWordTick(player.InGameClient); } }
public MonsterBrain(Actor body) : base(body) { this.PresetPowers = new List<int>(); // build list of powers defined in monster mpq data if (body.ActorData.MonsterSNO > 0) { var monsterData = (Mooege.Common.MPQ.FileFormats.Monster)MPQStorage.Data.Assets[SNOGroup.Monster][body.ActorData.MonsterSNO].Data; _mpqPowerCount = monsterData.SkillDeclarations.Count(e => e.SNOPower != -1); foreach (var monsterSkill in monsterData.SkillDeclarations) { if (Powers.PowerLoader.HasImplementationForPowerSNO(monsterSkill.SNOPower)) { this.PresetPowers.Add(monsterSkill.SNOPower); } } } }
public HitPayload(AttackPayload attackPayload, bool criticalHit, Actor target) { this.Context = attackPayload.Context; this.Target = target; this.IsCriticalHit = criticalHit; // TODO: select these values based on element type? float weaponMinDamage = this.Context.User.Attributes[GameAttribute.Damage_Weapon_Min_Total, 0]; float weaponDamageDelta = this.Context.User.Attributes[GameAttribute.Damage_Weapon_Delta_Total, 0]; // calculate and add up damage amount for each element type this.ElementDamages = new Dictionary<DamageType, float>(); foreach (var entry in attackPayload.DamageEntries) { if (!this.ElementDamages.ContainsKey(entry.DamageType)) this.ElementDamages[entry.DamageType] = 0f; if (entry.IsWeaponBasedDamage) this.ElementDamages[entry.DamageType] += entry.WeaponDamageMultiplier * (weaponMinDamage + (float)PowerContext.Rand.NextDouble() * weaponDamageDelta); else this.ElementDamages[entry.DamageType] += entry.MinDamage + (float)PowerContext.Rand.NextDouble() * entry.DamageDelta; } // apply critical damage boost if (criticalHit) { // TODO: probably will calculate this off of GameAttribute.Crit_Damage_Percent, but right now that attribute is never set var damTypes = this.ElementDamages.Keys.ToArray(); foreach (var type in damTypes) this.ElementDamages[type] *= 1.0f + 0.25f; } // TODO: reduce element damage amounts according to target's resistances // TODO: reduce total damage by target's armor this.TotalDamage = this.ElementDamages.Sum(kv => kv.Value); this.DominantDamageType = this.ElementDamages.OrderByDescending(kv => kv.Value).FirstOrDefault().Key; }
protected HirelingBrain(Actor body) : base(body) { }
public DeathPayload(PowerContext context, DamageType deathDamageType, Actor target) { this.Context = context; this.DeathDamageType = deathDamageType; this.Target = target; }
private void DrawActor(Actor actor, Graphics graphics, Brush brush, int radius) { var rect = new Rectangle((int)actor.Bounds.X, (int)actor.Bounds.Y, (int)actor.Bounds.Width + radius, (int)actor.Bounds.Height + radius); graphics.FillEllipse(brush, rect); }
private void _SetHiddenAttribute(Actor actor, bool active) { actor.Attributes[GameAttribute.Hidden] = active; actor.Attributes.BroadcastChangedIfRevealed(); }
protected FollowerBrain(Actor body) : base(body) { }
// TODO: add an actor mover helper function! /raist. public void OnActorMove(Actor actor, Vector3D prevPosition) { // TODO: Unreveal from players that are now outside the actor's range. /komiga }
public ActorMover(Actor target) { this.Target = target; }
protected Brain(Actor body) { this.Body = body; this.State = BrainState.Idle; this.Actions = new Queue<ActorAction>(); }
public List<Vector3D> FindPath(Actor actor, Vector3D Start, Vector3D Destination) { _baseX = 0; _baseY = 0; // reset to 0 // Should only be null first time a path is requested. if (_curScene == null) { _curScene = actor.CurrentScene; if(!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id,out mPathFinder)) // Attempts to pull the pathfinder which matches the scenes SNO from the patherlist { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); // Create a new pather, using the current scenes grid. listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); // add it to our patherlist, with the SNO as key. } InitPathFinder(); } // Checks if our path start location is inside current scene, if it isnt, we reset curScene and set mPathfinder to the corrent grid. if (!_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Start.X, Start.Y, 1, 1))) { _curScene = actor.CurrentScene;// TODO- THIS CAN RETURN PARENT RATHER THAN SUBSCENE - DarkLotus if (!listOfPathFinderInstances.TryGetValue(_curScene.SceneSNO.Id, out mPathFinder)) { mPathFinder = new PathFinderFast(_curScene.NavMesh.WalkGrid); listOfPathFinderInstances.TryAdd(_curScene.SceneSNO.Id, mPathFinder); } InitPathFinder(); } _baseX = _curScene.Position.X; //Our base location for working out world > SceneLocal coordinates. _baseY = _curScene.Position.Y; // Path's start and destination are both in same scene. if (_curScene.Bounds.IntersectsWith(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1))) { _destScene = _curScene; } else { //Builds a new grid on the fly containing both the start and destination scenes. This is not really optimal, but its a trade off. // Keeping grids Scene based means they can be used cross game even when laid out different in a seperate world. This keeps memory usage down substantially. // Also limited to a max distance of scene > scene. Again this keeps memory usage low. _destScene = _curScene.World.QuadTree.Query<Scene>(new System.Windows.Rect(Destination.X, Destination.Y, 1, 1)).FirstOrDefault(); mPathFinder = new PathFinderFast(BuildOutOfSceneGrid(_curScene, _destScene, ref _baseX, ref _baseY)); InitPathFinder(); } //2.5f is because Scene navmesh's are based on 96x96 for a 240x240 scene - Darklotus _startSceneLocal.X = (int)((Start.X - _baseX) / 2.5f); _startSceneLocal.Y = (int)((Start.Y - _baseY) / 2.5f); _destinationSceneLocal.X = (int)((Destination.X - _baseX) / 2.5f); _destinationSceneLocal.Y = (int)((Destination.Y - _baseY) / 2.5f); //Possibily add a check to ensure start/dest local coords are valid. Unneeded so far. nodePathList = mPathFinder.FindPath(_startSceneLocal, _destinationSceneLocal); // The actual pathfind request, the path is found here. vectorPathList.Clear(); // Clear the previous path. if (nodePathList == null) { //TODO: Sometimes Mobs are require to spawn outside current walkable boundaries, with the current implementation //Pathfinder is unable to return a valid path if the mob is outside this boundaries. //This is just a hackish way to force a path over the mob. Logger.Debug("Pathfinding forced hack activated due Mob outside walkable area"); vectorPathList.Insert(0, new Vector3D(Destination.X,Destination.Y,Destination.Z)); return vectorPathList; }// No Path Found. if (nodePathList.Count < 1) { return vectorPathList; } // Safety net Incase start/dest are the same. for (int i = 0; i < nodePathList.Count; i++) { // Convert the path into world coordinates for use in Movement. // TODO Objectpool maybe? vectorPathList.Insert(0, new Vector3D(nodePathList[i].X * 2.5f + _baseX, nodePathList[i].Y * 2.5f + _baseY, 0)); } //new System.Threading.Thread(c => System.Windows.Forms.Application.Run(new PatherDebug.PatherDebug(actor, vectorPathList))).Start(); return vectorPathList; }
public override void OnChannelOpen() { EffectsPerSecond = ScriptFormula(18); _calcTargetPosition(); _target = SpawnEffect(RuneSelect(52687, 52687, 93544, -1, 52687, 215723), TargetPosition, 0, WaitInfinite()); User.AddComplexEffect(RuneSelect(18792, 18792, 93529, -1, 93593, 216368), _target); }
public PathRequestTask(Pathfinder pathing, Actor actor, Vector3D Start, Vector3D Destination) { this._pathfinder = pathing; this._actor = actor; this._start = Start; this._destination = Destination; this.Path = new List<Vector3D>(); }
public override void OnChannelOpen() { EffectsPerSecond = 0.2f; _targetProxy = SpawnEffect(RuneSelect(134595, 170443, 170285, 170830, 170590, 134595), TargetPosition, 0, WaitInfinite()); _userProxy = SpawnProxy(User.Position, WaitInfinite()); _userProxy.PlayEffectGroup(RuneSelect(134442, 170263, 170264, 170569, 170572, 164077), _targetProxy); }