public void CreateCircle(ushort circleSize) { CircleLocations = Functions.GetCircleLocations(StartingLocation, circleSize); for (int i = 0; i < CircleLocations.Count; i++) { if (CurrentMap.ValidPoint(CircleLocations[i])) { SpellObject ob = new SpellObject { Spell = Spell.FireWall, Value = 0, ExpireTime = ShrinkTime, //ExpireTime = Envir.Time + ( 10 + value / 2 ) * 1000, TickSpeed = 1000, CurrentLocation = CircleLocations[i], CurrentMap = CurrentMap, LMS_Circle = true }; CurrentMap.Cells[CircleLocations[i].X, CircleLocations[i].Y].Add(ob); ob.Spawned(); } } }
public override void Cast(GameActor caster, UnityEngine.Vector3 target) { Ray ray = Camera.main.ScreenPointToRay(target); RaycastHit hit; LayerMask layerMask = 1 << LayerMask.NameToLayer("Ground"); if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask.value)) { //hit.point.Set(hit.point.x, 1, hit.point.z); SpellObject spellObj = null; if (PhotonNetwork.offlineMode) { spellObj = GameObjectPool.Spawn(SpellObject.gameObject).GetComponent <SpellObject>(); } else { spellObj = PhotonNetwork.Instantiate(SpellObject.gameObject.name, Vector3.zero, Quaternion.identity, 0).GetComponent <SpellObject>(); } if (!spellObj.photonView.isMine) { spellObj.photonView.TransferOwnership(caster.photonView.ownerId); } spellObj.transform.position = hit.point; spellObj.transform.localScale = Vector3.one; spellObj.SetProps(this); spellObj.transform.LookAt(caster.transform.position); } }
public void CreateInnerCircle() { List <Point> nextCircle = new List <Point>(); nextCircle = Functions.GetCircleLocations(StartingLocation, NextSize); for (int i = 0; i < nextCircle.Count; i++) { if (CurrentMap.ValidPoint(nextCircle[i])) { SpellObject spell = new SpellObject { Spell = Spell.DigOutZombie, Value = 0, ExpireTime = ShrinkTime, //ExpireTime = Envir.Time + ( 10 + value / 2 ) * 1000, TickSpeed = 1000, CurrentLocation = nextCircle[i], CurrentMap = CurrentMap, LMS_Circle = true }; CurrentMap.Cells[nextCircle[i].X, nextCircle[i].Y].Add(spell); spell.Spawned(); } } }
public override void Cast(GameActor caster) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hit; if (Physics.Raycast(ray, out hit, 10000)) { SpellObject spellObj = null; if (PhotonNetwork.offlineMode) { spellObj = GameObjectPool.Spawn(SpellObject.gameObject).GetComponent <SpellObject>(); } else { spellObj = PhotonNetwork.Instantiate(SpellObject.gameObject.name, Vector3.zero, Quaternion.identity, 0).GetComponent <SpellObject>(); } if (!spellObj.photonView.isMine) { spellObj.photonView.TransferOwnership(caster.photonView.ownerId); } spellObj.transform.position = hit.point; spellObj.SetProps(this); spellObj.transform.LookAt(caster.transform.position); } }
static bool Prefix(ref Player __instance, int slotNum, ref int manaOverride, bool consumeOverride) { if (__instance.duelDisk.castSlots[slotNum].spellObj.spell.itemObj.paramDictionary.ContainsKey("KickerCast")) { Dictionary <string, string> pd = __instance.duelDisk.castSlots[slotNum].spellObj.spell.itemObj.paramDictionary; if (!pd.ContainsKey("KickerManaCost")) { Debug.Log("ERROR: Spell has KickerCast, but not KickerManaCost"); return(true); } if (!pd.ContainsKey("KickerSpell")) { Debug.Log("ERROR: Spell has KickerCast, but not KickerSpell"); return(true); } List <string> SpellNames = pd["KickerSpell"].Split(',').ToList(); List <string> ManaCosts = pd["KickerManaCost"].Split(',').ToList(); for (int i = SpellNames.Count - 1; i >= 0; i--) { if (__instance.duelDisk.currentMana >= (manaOverride < 0 ? Int32.Parse(ManaCosts[i]) : manaOverride)) { SpellObject Kicker = S.I.deCtrl.CreateSpellBase(SpellNames[i], __instance); Kicker.PlayerCast(); var manaCost = (manaOverride < 0 ? Int32.Parse(ManaCosts[i]) : manaOverride); __instance.duelDisk.currentMana -= (float)manaCost; __instance.duelDisk.LaunchSlot(slotNum, false, null); return(false); } } } return(true); }
private void Update() { foreach (var spell in spells) { if (Input.GetKeyDown(spell.castKey)) { if (activeSpell != spell) { EndCast(); StartCast(spell.range); activeSpell = spell; break; } } } if (Input.GetKey(cancelKey)) { EndCast(); } if (activeSpell) { CheckForCast(); } UpdateLine(); }
protected void CastMeditate() { isMeditateInProcess = true; SpellObject spellObject = null; StatList spellStat = null; spellObject = Data.SpellObjects.GetItemByName("meditate", false); if (spellObject != null) { spellStat = Data.AvatarSpells.GetItemByID(spellObject.ID); } if (spellObject == null || spellStat == null) { Log("WARN", "Can't find spell " + spellObject.Name + "."); return; } if (Data.IsResting) { SendUserCommandStand(); } SendReqCastMessage(spellObject); System.Threading.Thread.Sleep(21000); isMeditateInProcess = false; if (!Data.IsResting) { SendUserCommandRest(); } }
public void MassThunderAttack() { // Whilst Energy Shield is up, attack all players every few seconds. if (Envir.Time > ThunderAttackTime) { List <MapObject> targets = FindAllTargets(AttackRange, Target.CurrentLocation); if (targets.Count == 0) { return; } for (int i = 0; i < targets.Count; i++) { if (targets[i].IsAttackTarget(this)) { var spellObj = new SpellObject { Spell = Spell.GeneralMeowMeowThunder, Value = Envir.Random.Next(Stats[Stat.MinMC], Stats[Stat.MaxMC]), ExpireTime = Envir.Time + 1000, TickSpeed = 500, Caster = this, CurrentLocation = targets[i].CurrentLocation, CurrentMap = CurrentMap, Direction = MirDirection.Up }; DelayedAction action = new DelayedAction(DelayedType.Spawn, Envir.Time + 2000, spellObj); CurrentMap.ActionList.Add(action); } } } ThunderAttackTime = Envir.Time + Math.Max(Envir.Random.Next(2000), Envir.Random.Next(4000)); }
public Spell(int id, Wizard wizard, SpellDescriptor descriptor, SpellObject obj) { this.Id = id; this.Wizard = wizard; this.Descriptor = descriptor; this.Object = obj; this.RegionalSpells = new Dictionary<Region, RegionalSpell>(); }
static public void AddXMLToSpell(SpellObject spellObj, string XML) { XmlReader reader = XmlReader.Create(new StringReader("<Spell itemID=\"" + spellObj.itemID + "\">" + XML + "</Spell>")); if (reader.ReadToDescendant("Spell")) { spellObj.ReadXmlPrototype(reader); } }
private static void nerfSpell(SpellObject spell, BossSaffron boss) { if (!SPELLS_TO_NERF.Contains(spell.itemID)) { return; } spell.damage *= nerfValue(boss.tier); }
private void SpawnRoots() { if (Dead) { return; } int count = Envir.Random.Next(1, _rootCount); int distance = Envir.Random.Next(_rootSpreadMin, _rootSpreadMax); for (int j = 0; j < CurrentMap.Players.Count; j++) { Point playerLocation = CurrentMap.Players[j].CurrentLocation; bool hit = false; for (int i = 0; i < count; i++) { Point location = new Point(playerLocation.X + Envir.Random.Next(-distance, distance + 1), playerLocation.Y + Envir.Random.Next(-distance, distance + 1)); if (Envir.Random.Next(3) == 0) { location = playerLocation; hit = true; } if (!CurrentMap.ValidPoint(location)) { continue; } var start = Envir.Random.Next(2000); SpellObject spellObj = new SpellObject { Spell = Spell.TreeQueenRoot, Value = Envir.Random.Next(Envir.Random.Next(Stats[Stat.MinMC], Stats[Stat.MaxMC])), ExpireTime = Envir.Time + 1500 + start, TickSpeed = 2000, Caster = this, CurrentLocation = location, CurrentMap = CurrentMap, Direction = MirDirection.Up }; DelayedAction action = new DelayedAction(DelayedType.Spawn, Envir.Time + start, spellObj); CurrentMap.ActionList.Add(action); if (hit) { break; } } } }
protected override DamageRequest CreateDamageRequest( ICaster caster, Target target, Spell spell, SpellCast spellCast = default, SpellObject spellObject = default) { var damageAugments = !caster.System.Has(out AuraSystem auraSystem) ? new List <(DamageAugmentAura, AuraState)>() : auraSystem.ActiveAuras .Where(x => x.AuraType.GetType() == typeof(DamageAugmentAura)) .Select(auraState => ((DamageAugmentAura)auraState.AuraType, auraState)) .Where(x => x.Item1.AppliesTo(spell)) .ToList(); var attributeMultiplier = 1f; var isCriticalStrike = false; var damageAmountFromRange = Random.Range(0f, 1f) * (damageCeiling - damageAmount) + damageAmount; if (affectedBySpellPower) { attributeMultiplier *= caster.System.AttributeSystem.SpellPower.Remap(); } if (canCrit) { if (Random.Range(0f, 1f) < caster.System.AttributeSystem.CriticalStrikeRating.Remap() + damageAugments.Select(x => x.Item1.CalculateCritChanceAddition(x.Item2)).Sum()) { isCriticalStrike = true; attributeMultiplier *= criticalStrikeMultiplier; } } var damageSource = caster.System.Origin.gameObject; var augmentMultiplier = !damageAugments.Any() ? 1 : damageAugments .Select(x => x.Item1.CalculateBaseDamageMultiplier(x.Item2)) .Aggregate((x, y) => x * y); foreach (var(damageAugmentAura, auraState) in damageAugments) { damageAugmentAura.Used(auraState); } return(new DamageRequest( damageAmountFromRange * attributeMultiplier * augmentMultiplier, isCriticalStrike, damageSource, allowDamageMitigation ? DamageRequest.WithMitigation : DamageRequest.NoMitigation)); }
public override int ReadFrom(byte[] Buffer, int StartIndex = 0) { int cursor = StartIndex; cursor += base.ReadFrom(Buffer, cursor); NewSpellObject = new SpellObject(Buffer, cursor); cursor += NewSpellObject.ByteLength; return(cursor - StartIndex); }
public void FindSpells() { //Summoners foreach (var spell in this.Unit.SpellBook.Spells) { if (spell.Slot == SpellSlot.Summoner1 || spell.Slot == SpellSlot.Summoner2) { var summSpell = new SpellObject(spell, null, 25, 25); this.Summoners.Add(summSpell); } } var herodata = Utility.GetChampionData(Unit.ChampionName); if (herodata == null) { Console.WriteLine("Data not found"); return; } var spells = herodata.Spells; for (int i = 0; i < spells.Length; i++) { var jsp = spells[i]; Aimtec.Spell spell = null; if (i == 0) { spell = this.Unit.GetSpell(SpellSlot.Q); } else if (i == 1) { spell = this.Unit.GetSpell(SpellSlot.W); } else if (i == 2) { spell = this.Unit.GetSpell(SpellSlot.E); } else if (i == 3) { spell = this.Unit.GetSpell(SpellSlot.R); } if (spell != null) { var normalSpell = new SpellObject(spell, jsp, 25, 25); this.Spells.Add(normalSpell); } } }
public override unsafe void ReadFrom(ref byte* Buffer) { base.ReadFrom(ref Buffer); ushort len = *((ushort*)Buffer); Buffer += TypeSizes.SHORT; SpellObjects = new SpellObject[len]; for (int i = 0; i < len; i++) SpellObjects[i] = new SpellObject(ref Buffer); }
protected virtual HealRequest CreateHealRequest( ICaster caster, Target target, Spell spell, SpellCast spellCast = default, SpellObject spellObject = default) { var healAugments = !caster.System.Has(out AuraSystem auraSystem) ? new List <(HealAugmentAura, AuraState)>() : auraSystem.ActiveAuras .Where(x => x.AuraType.GetType() == typeof(HealAugmentAura)) .Select(auraState => ((HealAugmentAura)auraState.AuraType, auraState)) .Where(x => x.Item1.AppliesTo(spell)) .ToList(); var attributeMultiplier = 1f; var isCriticalStrike = false; if (affectedBySpellPower) { attributeMultiplier *= caster.System.AttributeSystem.SpellPower.Remap(); } if (canCrit) { if (Random.Range(0f, 1f) < caster.System.AttributeSystem.CriticalStrikeRating.Remap() + healAugments.Select(x => x.Item1.CalculateCritChanceAddition(x.Item2)).Sum()) { isCriticalStrike = true; attributeMultiplier *= criticalStrikeMultiplier; } } var healingSource = caster.System.Origin.gameObject; var augmentMultiplier = !healAugments.Any() ? 1 : healAugments .Select(x => x.Item1.CalculateBaseHealMultiplier(x.Item2)) .Aggregate((x, y) => x * y); foreach (var(healAugmentAura, auraState) in healAugments) { healAugmentAura.Used(auraState); } return(new HealRequest( healAmount * attributeMultiplier * augmentMultiplier, isCriticalStrike, healingSource, HealRequest.DefaultHealCalculator)); }
static void Prefix(SpellObject spellObj, Enhancement enhancement) { if ((int)enhancement >= LuaPowerData.baseGameEnumAmount[typeof(Enhancement)] && LuaPowerData.customUpgrades.ContainsKey(enhancement.ToString())) { Script mainscr = Traverse.Create(Traverse.Create <EffectActions>().Field("_Instance").GetValue <EffectActions>()).Field("myLuaScript").GetValue <Script>(); if (mainscr.Call(mainscr.Globals[LuaPowerData.customUpgrades[enhancement.ToString()].Item2], new object[] { spellObj }).Boolean) { mainscr.Call(mainscr.Globals[LuaPowerData.customUpgrades[enhancement.ToString()].Item3], new object[] { spellObj }); spellObj.nameString += U.I.Colorify(" " + LuaPowerData.customUpgrades[enhancement.ToString()].Item1, UIColor.Enhancement); spellObj.enhancements.Add(enhancement); } } }
static void GenerateEnhanceSpellPostFix(PostCtrl __instance, SpellObject spellObj, Enhancement enhancement) { foreach (ICustomEnhancement customZone in PostCtrlGenerateEnhancementPatches.customEnhancementsImpl) { try { customZone?.AddCustomEnhancement(__instance, spellObj, enhancement); } catch (Exception e) { Debug.LogException(e); } } }
protected void OnGridSpellsSelectionChanged(object sender, EventArgs e) { if (gridSpells.SelectedRows.Count > 0 && gridSpells.SelectedRows[0].DataBoundItem != null) { SpellObject spellObject = (SpellObject)gridSpells.SelectedRows[0].DataBoundItem; spellObject.SubOverlays.SyncContext = SynchronizationContext.Current; pictureBox.DataSource = spellObject; gridSubOverlays.DataSource = spellObject.SubOverlays; avAnimation.DataSource = spellObject.Animation; } }
public override void Execute(ICaster caster, Target target, Spell spell, SpellCast spellCast = default, SpellObject spellObject = default) { if (!target.IsCombatTarget) { return; } if (!target.CombatSystem.Has(out HealthSystem.HealthSystem healthComponent)) { return; } healthComponent.Heal(CreateHealRequest(caster, target, spell, spellCast, spellObject)); }
private void gridSpells_SelectionChanged(object sender, EventArgs e) { if (gridSpells.SelectedRows.Count > 0 && gridSpells.SelectedRows[0].DataBoundItem != null) { SpellObject spellObject = (SpellObject)gridSpells.SelectedRows[0].DataBoundItem; spellObject.SubOverlays.SyncContext = SynchronizationContext.Current; avAnimation.DataSource = null; avSubOverlayAnimation.DataSource = null; gridSubOverlays.DataSource = spellObject.SubOverlays; avAnimation.DataSource = spellObject.Animation; } }
static void StartUpgradePostFix(PostCtrl __instance, SpellObject spellObj, int siblingIndex) { Button button = Util.CreateRefreshUI(ref canvas); button.onClick.AddListener(() => { if (Time.time < lastRolledTime + 1) { return; } lastRolledTime = Time.time; __instance.StartUpgrade(spellObj, siblingIndex); }); }
static void Prefix(ref Player __instance, int slotNum, ref int manaOverride, bool consumeOverride) { if (slotNum >= __instance.duelDisk.castSlots.Count) { return; } slotNum = Traverse.Create(__instance).Method("GetSlotNum", slotNum).GetValue <int>(); if (__instance.duelDisk.castSlots[slotNum].cardtridgeFill == null) { return; } SpellObject spellToCast = __instance.duelDisk.castSlots[slotNum].cardtridgeFill.spellObj; if (spellToCast.spell.itemObj.paramDictionary.ContainsKey("DontDiscard") && spellToCast.spell.itemObj.paramDictionary["DontDiscard"] == "true") { if (spellToCast.spell.itemObj.paramDictionary.ContainsKey("ShotsRemaining")) { if (spellToCast.spell.itemObj.paramDictionary.ContainsKey("ManaCost")) { switch (spellToCast.spell.itemObj.paramDictionary["ManaCost"]) { case "Start": if (spellToCast.spell.itemObj.paramDictionary.ContainsKey("MaxShots") && spellToCast.spell.itemObj.paramDictionary["ShotsRemaining"] != spellToCast.spell.itemObj.paramDictionary["MaxShots"]) { manaOverride = 0; } break; case "End": if (Int32.Parse(spellToCast.spell.itemObj.paramDictionary["ShotsRemaining"]) > 1) { manaOverride = 0; } break; case "All": break; default: break; } } } } }
public void EndCast() { if (activeSpell) { activeSpell = null; isTargeting = false; Destroy(rangeInstance); rangeInstance = null; Destroy(lineInstance.gameObject); lineInstance = null; CursorManager.instance.SetCursorState("DEFAULT"); } }
public FireWallSpell() { SpellObject = Resources.Load <SpellObject>("FX_FireWall"); SpellProps = new SpellProperties { Damage = 15, SpellDuration = 20, CoolDownDuration = 15f, StaminaCost = 20f, CastTime = 0.5f, Type = ESpellType.TYPE_AREA, CoolDownTimer = 15f, Icon = Resources.Load <Sprite>("FireWall"), }; GameObjectPool.Initialize(SpellObject.gameObject); }
public MinorHealSpell() { SpellProps = new SpellProperties { Damage = 5, SpellDuration = 3, CoolDownDuration = 5f, StaminaCost = 10f, Type = ESpellType.TYPE_SELF, CastTime = 0.5f, CoolDownTimer = 5f, Icon = Resources.Load <Sprite>("MinorHeal"), }; SpellObject = Resources.Load <SpellObject>("FX_Fireball"); }
public override int ReadFrom(byte[] Buffer, int StartIndex = 0) { int cursor = StartIndex; cursor += base.ReadFrom(Buffer, cursor); ushort len = BitConverter.ToUInt16(Buffer, cursor); cursor += TypeSizes.SHORT; SpellObjects = new SpellObject[len]; for (int i = 0; i < len; i++) { SpellObjects[i] = new SpellObject(Buffer, cursor); cursor += SpellObjects[i].ByteLength; } return cursor - StartIndex; }
static bool Prefix(ref Player __instance, int slotNum, ref int manaOverride, bool consumeOverride) { if (__instance.duelDisk.castSlots[slotNum] != null && __instance.duelDisk.castSlots[slotNum].spellObj != null && __instance.duelDisk.castSlots[slotNum].spellObj.spell.itemObj.paramDictionary.ContainsKey("KickerCast")) { Dictionary <string, string> pd = __instance.duelDisk.castSlots[slotNum].spellObj.spell.itemObj.paramDictionary; if (!pd.ContainsKey("KickerSpell")) { Debug.Log("ERROR: Spell has KickerCast, but not KickerSpell"); return(true); } if (!pd.ContainsKey("KickerManaCost")) { Debug.Log("ERROR: Spell has KickerCast, but not KickerManaCost"); return(true); } List <string> SpellNames = pd["KickerSpell"].Split(',').ToList(); List <string> ManaCosts = pd["KickerManaCost"].Split(',').ToList(); for (int i = SpellNames.Count - 1; i >= 0; i--) { if (__instance.duelDisk.currentMana >= (manaOverride < 0 ? Int32.Parse(ManaCosts[i]) : manaOverride)) { SpellObject Kicker = S.I.deCtrl.CreateSpellBase(SpellNames[i], __instance); Kicker.castSlotNum = slotNum; foreach (Enhancement e in __instance.duelDisk.castSlots[slotNum].spellObj.enhancements) { S.I.poCtrl.EnhanceSpell(Kicker, e); } if (__instance.duelDisk.currentMana >= (manaOverride < 0 ? Kicker.mana : manaOverride)) { __instance.duelDisk.castSlots[slotNum].Launch(__instance.duelDisk.castSlots[slotNum].spellObj.consume, null); Cardtridge KickerCardt = SimplePool.Spawn(S.I.deCtrl.cardtridgePrefab, Vector3.one * 1000f, __instance.transform.rotation, null, false).GetComponent <Cardtridge>().Set(Kicker, __instance.duelDisk); __instance.duelDisk.castSlots[slotNum].Load(KickerCardt); UnityEngine.Object.Destroy(KickerCardt, 1); return(true); } } } } return(true); }
protected override void ProcessAI() { if (!Dead && Envir.Time > VisibleTime) { VisibleTime = Envir.Time + 2000; bool visible = FindNearby(4); if (!Visible && visible) { Visible = true; CellTime = Envir.Time + 500; Broadcast(GetInfo()); Broadcast(new S.ObjectShow { ObjectID = ObjectID }); ActionTime = Envir.Time + 2000; DigOutTime = Envir.Time; DigOutLocation = CurrentLocation; DigOutDirection = Direction; } } if (Visible && Envir.Time > DigOutTime + 800 && !DoneDigOut) { SpellObject ob = new SpellObject { Spell = Spell.Armadilo, Value = 1, ExpireTime = Envir.Time + (5 * 60 * 1000), TickSpeed = 2000, Caster = null, CurrentLocation = DigOutLocation, CurrentMap = this.CurrentMap, Direction = DigOutDirection }; CurrentMap.AddObject(ob); ob.Spawned(); DoneDigOut = true; } base.ProcessAI(); }
public override void Execute(ICaster source, Target target, Spell spell, SpellCast spellCast = default, SpellObject spellObject = default) { if (spawn == default) { return; } SpellObject newSpellObject = default; switch (at) { case TargetType.Target: newSpellObject = Instantiate(spawn, target.TargetObject.transform); newSpellObject.transform.position = target.Position; newSpellObject.Source = source; newSpellObject.Target = target; newSpellObject.SpellCast = spellCast; newSpellObject.Spell = spell; newSpellObject.Initialize(); break; case TargetType.SelfCastOrigin: newSpellObject = Instantiate(spawn, source.CastOrigin); newSpellObject.Source = source; newSpellObject.Target = target; newSpellObject.SpellCast = spellCast; newSpellObject.Spell = spell; newSpellObject.Initialize(); break; case TargetType.SelfOrigin: newSpellObject = Instantiate(spawn, source.System.Origin); newSpellObject.Source = source; newSpellObject.Target = target; newSpellObject.SpellCast = spellCast; newSpellObject.Spell = spell; newSpellObject.Initialize(); break; default: throw new ArgumentOutOfRangeException(); } }
protected override void ProcessAI() { if (!Dead && Envir.Time > VisibleTime) { VisibleTime = Envir.Time + 2000; bool visible = FindNearby(3); if (!Visible && visible) { Visible = true; CellTime = Envir.Time + 500; Broadcast(GetInfo()); Broadcast(new S.ObjectShow { ObjectID = ObjectID }); ActionTime = Envir.Time + 2000; DigOutTime = Envir.Time; DigOutLocation = CurrentLocation; DigOutDirection = Direction; } } if (Visible && Envir.Time > DigOutTime + 1000 && !DoneDigOut) { SpellObject ob = new SpellObject { Spell = Spell.DigOutZombie, Value = 1, ExpireTime = Envir.Time + (5 * 60 * 1000), TickSpeed = 2000, Caster = null, CurrentLocation = DigOutLocation, CurrentMap = this.CurrentMap, Direction = DigOutDirection }; CurrentMap.AddObject(ob); ob.Spawned(); DoneDigOut = true; } base.ProcessAI(); }
public float GetOpinion(SpellObject obj) { return obj.GetOpinion(this); }
public double GetOpinion(SpellObject obj) { return obj.GetOpinion(this); }
public Spell(string wizardName, SpellDescriptor descriptor, SpellObject obj) { this.wizardName = wizardName; this.Descriptor = descriptor; this.Object = obj; }