Пример #1
0
    public KnownSpellButton(Rectangle rect,
                            bool spellOpposesAlignment,
                            SpellStoreData spell) : base(rect)
    {
        _spellOpposesAlignment = spellOpposesAlignment;
        _spell = spell;

        var spellName = GameSystems.Spell.GetSpellName(spell.spellEnum);

        if (GameSystems.Spell.IsDomainSpell(spell.classCode))
        {
            var domainName = GameSystems.Spell.GetSpellDomainName(spell.classCode);
            spellName += " (" + domainName + ")";
        }

        var style = spellOpposesAlignment ? "char-spell-grey" : "char-spell-body";

        _nameLabel = new WidgetText(spellName, style);
        AddContent(_nameLabel);

        OnMouseEnter += ShowSpellHelp;
        OnMouseExit  += HideSpellHelp;

        if (spellOpposesAlignment)
        {
            TooltipText = "#{char_ui_spells:12}";
        }
        else
        {
            TooltipText   = GameSystems.Spell.GetSpellName(_spell.spellEnum);
            OnRightClick += (x, y) => OnMemorizeSpell?.Invoke(_spell, null);
        }
    }
Пример #2
0
 public D20SpellData(SpellStoreData spell)
     : this(spell.spellEnum, spell.classCode, spell.spellLevel, metaMagicData : spell.metaMagicData)
 {
 }
Пример #3
0
    private void SetSpontaneousCastingAltNode(GameObject obj, int nodeIdx, SpellStoreData spellData)
    {
        var spellClassCode = spellData.classCode;

        if (GameSystems.Spell.IsDomainSpell(spellClassCode))
        {
            // Domain slots cannot be used for spontaneous casting
            return;
        }

        var castingClassCode = GameSystems.Spell.GetCastingClass(spellClassCode);

        if (castingClassCode == Stat.level_cleric)
        {
            var alignmentChoice = obj.GetInt32(obj_f.critter_alignment_choice);
            var spellLevel      = spellData.spellLevel;

            var type = alignmentChoice == 1 ? SpontCastType.GoodCleric : SpontCastType.EvilCleric;
            if (!SpontaneousCastSpells.TryGet(type, spellLevel, out var spontSpellEnum))
            {
                return;
            }

            // NOTE: This clears metamagic (deliberately)
            var d20SpellData = new D20SpellData(spontSpellEnum, spellData.classCode, spellData.spellLevel);

            var radEntry = RadialMenuEntry.CreateSpellAction(d20SpellData, D20ActionType.CAST_SPELL);
            radEntry.d20ActionData1    = 0;
            radEntry.helpSystemHashkey = "TAG_CLASS_FEATURES_CLERIC_SPONTANEOUS_CASTING";

            SetMorphsTo(obj, nodeIdx, AddRootNode(obj, ref radEntry));
        }
        else if (castingClassCode == Stat.level_druid)
        {
            var spellLevel = spellData.spellLevel;
            if (!SpontaneousCastSpells.TryGet(SpontCastType.Druid, spellLevel, out var spontSpellEnum) ||
                !SpontaneousCastSpells.TryGetDruidOptionsKey(spellLevel, out var optionsKey))
            {
                return;
            }

            var radEntry  = RadialMenuEntry.CreateParent(GameSystems.Spell.GetSpellName(spontSpellEnum));
            var parentIdx = AddRootNode(obj, ref radEntry);
            SetMorphsTo(obj, nodeIdx, parentIdx);

            // Now add sub-entries for each summonable creature
            // TODO: Move this functionality into SpellSystem, since it's used in multiple places
            var numSummonsTxt = GameSystems.Spell.GetSpellsRadialMenuOptions(optionsKey);
            var numSummons    = int.Parse(numSummonsTxt);
            for (int i = 1; i <= numSummons; i++)
            {
                var protoNumTxt = GameSystems.Spell.GetSpellsRadialMenuOptions(i + optionsKey);
                var protoNum    = int.Parse(protoNumTxt);
                var protoHandle = GameSystems.Proto.GetProtoById(protoNum);

                var summonSpellData = new D20SpellData(spontSpellEnum, spellData.classCode, spellLevel);
                summonSpellData.spontCastType = SpontCastType.Druid;

                var summonRadEntry = RadialMenuEntry.CreateSpellAction(summonSpellData, D20ActionType.CAST_SPELL);
                summonRadEntry.text           = GameSystems.Description.Get(protoHandle.GetInt32(obj_f.description));
                summonRadEntry.d20ActionData1 = 0; // TODO Check if restting is necessary vs. CreateSpellAction
                SetCallbackCopyEntryToSelected(ref summonRadEntry);
                summonRadEntry.minArg = protoNum;
                summonRadEntry.AddAsChild(obj, parentIdx);
            }
        }
    }
Пример #4
0
    private void AddSpell(GameObject caster, SpellStoreData spData)
    {
        if (spData.spellStoreState.usedUp)
        {
            return;
        }

        if (!GameSystems.Spell.spellCanCast(caster, spData.spellEnum, spData.classCode, spData.spellLevel))
        {
            return;
        }

        if (spData.classCode == SpellSystem.GetSpellClass(Stat.level_paladin) &&
            GameSystems.D20.D20Query(caster, D20DispatcherKey.QUE_IsFallenPaladin))
        {
            return;
        }

        if (!TryGetParentNodeForSpell(caster, spData.classCode, spData.spellLevel, out var specNode))
        {
            return;
        }

        RadialMenuEntry entry;

        if (!GameSystems.Spell.SpellHasMultiSelection(spData.spellEnum))
        {
            var d20SpellData = new D20SpellData(spData.spellEnum, spData.classCode, spData.spellLevel, -1,
                                                spData.metaMagicData);
            entry = RadialMenuEntry.CreateSpellAction(d20SpellData, D20ActionType.CAST_SPELL);
            entry.d20ActionData1 = 0; // TODO: Check the CAST_SPELL action whether this is needed

            var nodeIdx = GameSystems.D20.RadialMenu.AddToStandardNode(caster, ref entry, specNode);
            SetSpontaneousCastingAltNode(caster, nodeIdx, spData);
            return;
        }

        // Multiselection spells section
        entry = RadialMenuEntry.CreateParent(GameSystems.Spell.GetSpellName(spData.spellEnum));

        // the parent node
        var parentNodeIdx = AddParentChildNode(caster, ref entry, GetStandardNode(specNode));

        SetSpontaneousCastingAltNode(caster, parentNodeIdx, spData);

        // the options
        if (!GameSystems.Spell.TryGetMultiSelectOptions(spData.spellEnum, out var multiOptions))
        {
            Logger.Error("Spell multiselect options not found!");
            return;
        }

        // populate options
        for (var i = 0; i < multiOptions.Count; i++)
        {
            var op = multiOptions[i];

            var d20SpellData = new D20SpellData(spData.spellEnum, spData.classCode, spData.spellLevel, -1, spData.metaMagicData);
            var castEntry    = RadialMenuEntry.CreateSpellAction(d20SpellData, D20ActionType.CAST_SPELL);
            castEntry.d20ActionData1 = 0; // TODO: Check if this is really necessary or if it's okay what CreateSpellAction does
            SetCallbackCopyEntryToSelected(ref castEntry);

            if (op.isProto)
            {
                var protoId = op.value;
                entry.minArg = protoId;

                var protoObj = GameSystems.Proto.GetProtoById(protoId);
                entry.text = GameSystems.Description.Get(protoObj.GetInt32(obj_f.description));
            }
            else
            {
                entry.text   = GameSystems.Spell.GetSpellsRadialMenuOptions(op.value);
                entry.minArg = i + 1;
            }

            entry.AddAsChild(caster, parentNodeIdx);
        }
    }