Temple+ Modding Question

Discussion in 'General Modification' started by _doug_, Feb 21, 2018.

Remove all ads!
  1. Pygmy

    Pygmy Established Member Supporter

    Joined:
    Oct 8, 2010
    Messages:
    377
    Likes Received:
    3
    I have just had a look at the future Changelog for 1.0.76 _doug_ and see that I owe you a big thank you
     
  2. _doug_

    _doug_ Established Member

    Joined:
    Jul 9, 2009
    Messages:
    108
    Likes Received:
    11
    Quick Question: What ID numbers should I use for new spells? Also is there a safe range of numbers that can be used for scrolls of new spells?
     
  3. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,758
    Likes Received:
    94
    The reserved spell enum ranges are listed here:

    https://github.com/GrognardsFromHell/TemplePlus/wiki/Spells

    Other than that make sure your spell doesn't have a pre-existing entry (they usually do for core material spells).

    Not sure what you mean about scrolls, do you intend to make a different spell for those or what?
     
  4. _doug_

    _doug_ Established Member

    Joined:
    Jul 9, 2009
    Messages:
    108
    Likes Received:
    11
    Thanks for the info! I will probably start at 1000 with Moment of Prescience which does not appear to have an entry in TOEE for whatever reason.

    For scrolls I think an item entry needs to be added before they can be crafted with scribe scroll. I was wondering how I should number the entry and what file I should add it to in Temple+.
     
  5. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,758
    Likes Received:
    94
    Are you talking about adding a protos.tab entry?
    If so I guess you can grab whatever is available. This is where mod compatibility can get hairy ;) keep rudy's mod and KotB in mind.
     
  6. _doug_

    _doug_ Established Member

    Joined:
    Jul 9, 2009
    Messages:
    108
    Likes Received:
    11
    Right. I was referring to the protos.tab entry. Is there an extended temple+ range or anywhere that is known to be safe?
     
  7. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,758
    Likes Received:
    94
    There's no extended range.
     
  8. _doug_

    _doug_ Established Member

    Joined:
    Jul 9, 2009
    Messages:
    108
    Likes Received:
    11
    Happy new year!

    What do you think is the best way to modify a save/skill check/AC/attack value only when it comes from a roll (not from the character sheet)?

    Thanks!
     
  9. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,758
    Likes Received:
    94
    IIRC the char sheet uses the query types, whereas actual checks use a different event type.
     
  10. _doug_

    _doug_ Established Member

    Joined:
    Jul 9, 2009
    Messages:
    108
    Likes Received:
    11
    Sorry, but I don't think I am quite following yet. Here is what I have in code and it seems to be getting called from the char sheet. What should I change?

    momentOfPrescience.AddHook(ET_OnGetSkillLevel, EK_NONE, MomentOfPrescienceSkillCheck, ())

    Thanks!
     
  11. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,758
    Likes Received:
    94
    I was going to say "look at Guidance spell", but I think that may actually be broken! (in that it may expend the guidance by going into the char sheet)

    So for skills it looks like there isn't a separate dispatch event.

    Likewise for AC, I was wrong about it using queries. Dodge feat for instance checks its args against the attacker handle to tell whether to apply it. I think you may utilize something similar, since the target needs to be specified?

    Attack bonus - Guidance checks the flag D20CAF_FINAL_ATTACK_ROLL
    Code:
    if ( evtObj->attackPacket.flags & D20CAF_FINAL_ATTACK_ROLL )
        {
          Float_Spell_mes_Message(args.objHndCaller, 0x4E20u, 0, 0, 0);
          *&v2[16] = args.dispKey;
          *&v2[8] = *(&args.objHndCaller.handle + 4);
          *v2 = *&args.subDispNode;
          Spell_remove_spell(*v2);
          *&v3[16] = args.dispKey;
          *&v3[8] = *(&args.objHndCaller.handle + 4);
          *v3 = *&args.subDispNode;
          Spell_remove_mod(*v3);
        }
    In short, there's no easy way I'm afraid... I'd round corners here wherever possible.
     
  12. WinstonShnozwick

    WinstonShnozwick Established Member

    Joined:
    Mar 2, 2011
    Messages:
    595
    Likes Received:
    10
    Has anybody used the FPF_MULTI_MASTER to create a custom list selection feat? I assume it goes with FPF_MULTI_SELECT_ITEM somehow based on the c++.

    edit: I think I've almost figured it out based on the code. Imagine my pleasant surprise when I found that multi selection feats and custom feat prerequisites are already supported :)
    I gotta hand it to you, the greatest strength of Temple+ is in being open source rather than the hell of a sourceless binary. There's so much power in having the ability to just write clean c++ code and python scripts.

    Ok based on testing,
    -FPF_MULTI_MASTER is needed for multi selection feats, but prereqs, custom or otherwise, are not detected. The feat master always is white as if you can select it in levelup, regardless of master prereqs, and even if you have taken one of the children already, which makes this a feat you can take more than once (like toughness) by default of being a multi master, with no way I can see of forcing it to be once only.
    -FPF_MULTI_SELECT_ITEM is not needed for multi selection feat children, only the "parent:" line in the feat rule file to name the master feat as its parent. prereqs work with these as expected and you will have to modify all children to check in their custom prereq that none of the other children are already learned if you want to prevent learning multiple children of the same multi select feat.

    FIX:
    Ok I just debugged, my journey began searching for a way to get the ability to have new mod feats linked to the in game help topics so you can click on the feat name and it goes to the page for that new feat, or press h and click on the feat name (these go to the TAG_ROOT of help currently for all new feats). I haven't figured this out yet, but along the way, I noticed the root cause of my vexation above. The code below is from ui_char_editor.cpp, in the function bool UiCharEditor::FeatCanPick(feat_enums feat), starting at line 2599.

    Code:
        if (!feats.IsFeatMultiSelectMaster(feat)) {
           return feats.FeatPrereqsCheck(handle, feat, featsPicked.size() > 0 ? &featsPicked[0] : nullptr, featsPicked.size(), selPkt.classCode, selPkt.statBeingRaised) != FALSE;
       }
    
    
       // Multiselect Master feats
    
       auto ftrLvl = objects.StatLevelGet(handle, stat_level_fighter);
       if (selPkt.classCode == stat_level_fighter)
           ftrLvl++;
       bool hasFocus = false;
       switch (feat) {
       case FEAT_EXOTIC_WEAPON_PROFICIENCY:
           return critterSys.GetBaseAttackBonus(handle, selPkt.classCode) >= 1;
       case FEAT_IMPROVED_CRITICAL:
           return critterSys.GetBaseAttackBonus(handle, selPkt.classCode) >= 8;
    
       case FEAT_MARTIAL_WEAPON_PROFICIENCY:
       case FEAT_SKILL_FOCUS:
           return true;
    
       case FEAT_WEAPON_FINESSE:
           if (critterSys.GetBaseAttackBonus(handle, selPkt.classCode) < 1)
               return false;
           for (auto i = (int)FEAT_WEAPON_FINESSE_GAUNTLET; i <= FEAT_WEAPON_FINESSE_NET; i++) {
               if (feats.HasFeatCountByClass(handle, (feat_enums)i, (Stat)0, 0))
                   return false;
           }
           for (auto it : featsPicked) {
               if (feats.IsFeatPropertySet(it, FPF_WEAP_FINESSE_ITEM))
                   return false;
           }
           return true;
    
       case FEAT_WEAPON_FOCUS:
           return critterSys.GetBaseAttackBonus(handle, selPkt.classCode) >= 1;
    
       case FEAT_WEAPON_SPECIALIZATION:
    
           return (ftrLvl >= 4);
     
    
       case FEAT_GREATER_WEAPON_FOCUS:
           if (ftrLvl < 8)
               return false;
    
    
           // check if has weapon focus
    
           for (auto i = (int)FEAT_WEAPON_FOCUS_GAUNTLET; i <= FEAT_WEAPON_FOCUS_RAY; i++) {
               if (feats.HasFeatCountByClass(handle, (feat_enums)i, (Stat)0, 0)) {
                   return true;
               }
               // if not, check if it's one of the picked ones
               for (auto it : featsPicked) {
                   if (it == (feat_enums)i)
                       return true;
               }
           }
           return false;
    
       case FEAT_GREATER_WEAPON_SPECIALIZATION:
           if (ftrLvl < 12)
               return false;
    
           for (auto i = (int)FEAT_GREATER_WEAPON_FOCUS_GAUNTLET; i <= FEAT_GREATER_WEAPON_FOCUS_RAY; i++) {
               hasFocus = false;
               if (feats.HasFeatCountByClass(handle, (feat_enums)i, (Stat)0, 0)) {
                   hasFocus = true;
               }
               // if not, check if it's one of the picked ones
               for (auto it : featsPicked) {
                   if (it == (feat_enums)i)
                       hasFocus =  true;
                   break;
               }
               // if has Greater Weapon Focus, check for Weapon Specialization
               if (hasFocus) {
           
                   for (auto j = (int)FEAT_WEAPON_SPECIALIZATION_GAUNTLET; j <= FEAT_WEAPON_SPECIALIZATION_GRAPPLE; j++) {
                       if (feats.HasFeatCountByClass(handle, (feat_enums)j, (Stat)0, 0))
                           return true;
                   }
               }
           }
    
       default:
           return true;
       }
    
    I saw the top if statement, where if the feat we're inspecting is NOT a multi master type, then we do the normal and check its prerequisites. So after that, we must surely be looking for prerequisites of multi master feats now, yes? Well, kind of. The switch statement does indeed go on to do that.. for the VANILLA multi master feats. Once all vanilla options in the switch statement are exhausted, we have determined that our feat is a multi master feat, but none of the vanilla ones - which deductively concludes that our feat being inspected must be a multi master feat that has been added through modding via a new rules/feats entry. Which is exactly what the default statement (at the bottom) is for. But it just returns true immediately! This foregoes checking any prerequisites for a custom multi master feat and says we are always true to be able to select this feat no matter what, leading to the defective behavior I described earlier where I was not gaining the prerequisites checking for my multi master. It should then be quite simple to enable this by doing the same as non multi masters in the first bit, by simply making the default statement (logically a feat that is a custom multi master) perform the prerequisite checking. Edit as below:

    Code:
        default:
           return feats.FeatPrereqsCheck(handle, feat, featsPicked.size() > 0 ? &featsPicked[0] : nullptr, featsPicked.size(), selPkt.classCode, selPkt.statBeingRaised) != FALSE;
       }
    
    I tested in game, and where before this, my new multi master (along with existing multi masters added by T+ like practiced spellcaster) feats were always white and selectable in the feat window on levelup, they now were greyed out and correctly used prerequisites defined for the custom multi master feats. (Shown, I added prerequisites my char does not have, and a print statement in the custom prereq function. Previously, the print statement would never show in console.. because it was never being called to begin with!)
    featdebug.PNG

    Ok, last check in on this. I just changed the feat descriptions so the children would have different descriptions from each other and the feat multi-master, and the previous image showed when all of the multi-master and children for the feat had the same descriptions. While I now have prereqs properly firing for the multi-master feat, hovering over it still does not display the prereq description/feat description text for the multi-master feat, instead it displays the description box text for one of the children of the multi-master feat. Depicted here, aligned attack multi master in levelup is displaying the text that should be for the aligned attack evil child version. The same occurs with practiced spellcaster, who has the arcane and divine child versions, and displays the description text for the arcane version when looking at the multi-master version in levelup.
    Also, it looks like they still have no block for taking multiple times by default, so you have to add a check in your custom feat reqs for having already learned any of the multi-children of that feat.
    featdebug.PNG
     
    Last edited: Jan 12, 2020
  13. _doug_

    _doug_ Established Member

    Joined:
    Jul 9, 2009
    Messages:
    108
    Likes Received:
    11
    That's some good detective work. I remember the multi feats working a bit odd when I added power critical but I didn't bother to track it down. Will you be uploading your change to github?
     
  14. WinstonShnozwick

    WinstonShnozwick Established Member

    Joined:
    Mar 2, 2011
    Messages:
    595
    Likes Received:
    10
    No, but you can, just follow the file/edit as described above. I'm going on a new feat binge for a bit now so I'm thinking I will edit the wiki's new feat page at some point with updated instructions for how to add new feats to the game to make it more comprehensive with the current possibilities. You'll definitely want the fix above to go into temple+ if you want to have full power over multi master feats, just take note for the two considerations I haven't figured out yet;
    1) Multi master and all of its children should keep the same description/prereq description text in the rule/feat files, because it appears to grab one of the children to display text for the master feat in levelup
    2) Multi master should have code in its custom prereq that returns 0 if the character has_feat any of the children feat of the multi master, because multi master is "can take multiple times" by default for some reason that I didn't find
     
  15. Sitra Achara

    Sitra Achara Senior Member

    Joined:
    Sep 1, 2003
    Messages:
    2,758
    Likes Received:
    94
    I don't see any of these issues as critical but if you intend to submit a fix it should be thoroughly tested.
    Also that last one seems WAI to me.
     
Our Host!