Thanks, will look into that. Will do. After looking at the code, I tried: Code: evt_obj.attack_packet.set_flags(D20CAF_CRITICAL) which leads to the same behaviour as above, then I tried: Code: evt_obj.attack_packet.set_flags(D20CAF_HIT) which does lead to normal hits but does not confirm the crit automatically. I also considered just adding +100 to the roll, it just has the auto fail on a 1 problem (this screenshot also demonstrates the confirmation visual bug; the +100 is actually only added to the confirm roll, not to the attack roll. The Attack Roll window has actually a wrong information shown.) Looking at the code, I might just add the reroll crit query and set it 1, this would mean I fail 1 in about 400 confirmation rolls only) which might be the easiest solution. To be clear, I use the Code: dolorousBlowSpell.AddHook(ET_OnConfirmCriticalBonus, EK_NONE, dolorousBlowSpellBonusToConfirmCrit,()) hook.
@Sagenlicht I took a look at Dolorous Blow and noticed you directly manipulate the weapon's crit range field there. This approach is not recommended and can easily lead to bugs. Why did you choose not to use the Get_Keen_Bonus method?
Because it does not work, at least I have not found any way to get a keen bonus to work with any query. I tried to apply it to the weapon as well as to wielder and I also tried has_keen_bonus both with no effect. But I get your point, I was unsure if it's a good idea myself. So I tried some things and now I have found a way to get it work and not to stack with either Keen Edge spell and the Improved Crit Feat, which is actually makes me a happy panda. Code: def dolorousBlowSpellModifyThreatRange(attachee, args, evt_obj): appliedKeenRange = evt_obj.bonus_list.get_sum() print "Range old ", appliedKeenRange getKeenRange = attachee.item_worn_at(item_wear_weapon_primary).obj_get_int(obj_f_weapon_crit_range) if appliedKeenRange == getKeenRange: evt_obj.bonus_list.add(getKeenRange, 0 , "~Dolorous Blow~[TAG_SPELLS_DOLORUS_BLOW] Bonus") print "Range new ", evt_obj.bonus_list.get_sum() else: print "Already keen" return 0 def dolorousBlowSpellAnswerToKeenQuery(attachee, args, evt_obj): if args.get_arg(1): evt_obj.return_val = 1 return 0 def dolorousBlowSpellBonusToConfirmCrit(attachee, args, evt_obj): flags = evt_obj.attack_packet.get_flags() flags |= D20CAF_CRITICAL evt_obj.attack_packet.set_flags(flags) return 0 def dolorousBlowSpellTooltip(attachee, args, evt_obj): if args.get_arg(1) == 1: evt_obj.append("Dolorous Blow ({} round)".format(args.get_arg(1))) else: evt_obj.append("Dolorous Blow ({} rounds)".format(args.get_arg(1))) def dolorousBlowSpellEffectTooltip(attachee, args, evt_obj): if args.get_arg(1) == 1: evt_obj.append(tpdp.hash("DOLOROUS_BLOW"), -2, " ({} round)".format(args.get_arg(1))) else: evt_obj.append(tpdp.hash("DOLOROUS_BLOW"), -2, " ({} rounds)".format(args.get_arg(1))) return 0 def dolorousBlowSpellHasSpellActive(attachee, args, evt_obj): spellPacket = tpdp.SpellPacket(args.get_arg(0)) if evt_obj.data1 == spellPacket.spell_enum: evt_obj.return_val = 1 return 0 def dolorousBlowSpellKilled(attachee, args, evt_obj): args.remove_spell() args.remove_spell_mod() return 0 def dolorousBlowSpellSpellEnd(attachee, args, evt_obj): print "Dolorous BlowSpellEnd" return 0 dolorousBlowSpell = PythonModifier("sp-Dolorous Blow", 3) # spell_id, duration, keenFlag dolorousBlowSpell.AddHook(ET_OnConfirmCriticalBonus, EK_NONE, dolorousBlowSpellBonusToConfirmCrit,()) dolorousBlowSpell.AddHook(ET_OnGetCriticalHitRange, EK_NONE, dolorousBlowSpellModifyThreatRange,()) dolorousBlowSpell.AddHook(ET_OnD20Query, EK_Q_Item_Has_Keen_Bonus, dolorousBlowSpellAnswerToKeenQuery, ()) #dolorousBlowSpell.AddHook(ET_OnD20Query, EK_Q_Weapon_Get_Keen_Bonus, dolorousBlowSpellAnswerToKeenQuery, ()) dolorousBlowSpell.AddHook(ET_OnGetTooltip, EK_NONE, dolorousBlowSpellTooltip, ()) dolorousBlowSpell.AddHook(ET_OnGetEffectTooltip, EK_NONE, dolorousBlowSpellEffectTooltip, ()) dolorousBlowSpell.AddHook(ET_OnD20Signal, EK_S_Spell_End, dolorousBlowSpellSpellEnd, ()) dolorousBlowSpell.AddHook(ET_OnD20Query, EK_Q_Critter_Has_Spell_Active, dolorousBlowSpellHasSpellActive, ()) dolorousBlowSpell.AddHook(ET_OnD20Signal, EK_S_Killed, dolorousBlowSpellKilled, ()) dolorousBlowSpell.AddSpellDispelCheckStandard() dolorousBlowSpell.AddSpellTeleportPrepareStandard() dolorousBlowSpell.AddSpellTeleportReconnectStandard() dolorousBlowSpell.AddSpellCountdownStandardHook() Shall I redo the spell Keen Edge as well, so it does not stack with the feat improved crit too?
EDIT: Ok to be more clear: There is no way in Pyhton to access existing DR values of a critter right? I would need to lower existing DR values to a minimum of 5. Code: .def("add_physical_damage_res", [](DamagePacket& damPkt, int amount, int bypassingAttackPower, int damMesLine){ damPkt.AddPhysicalDR(amount, bypassingAttackPower, damMesLine); }, "Adds physical (Slashing/Piercing/Crushing) damage resistance.") *SNIP* .def("add_damage_resistance", [](DamagePacket& damPkt, int amount, int damType, int damMesLine) { auto _damType = (DamageType)damType; damPkt.AddDR(amount, _damType, damMesLine); }, "Adds damage resistance.") If I do know the DR of the critter I simply could add a negative value Now I think, I made my thought process clear, just took me about 3 edits :/
https://dndtools.net/spells/spell-compendium--86/vulnerability--4756/ I would like to modify existing DR values of critters. I could use this: Code: .def("add_physical_damage_res", [](DamagePacket& damPkt, int amount, int bypassingAttackPower, int damMesLine){ damPkt.AddPhysicalDR(amount, bypassingAttackPower, damMesLine); }, "Adds physical (Slashing/Piercing/Crushing) damage resistance.") *SNIP* .def("add_damage_resistance", [](DamagePacket& damPkt, int amount, int damType, int damMesLine) { auto _damType = (DamageType)damType; damPkt.AddDR(amount, _damType, damMesLine); }, "Adds damage resistance.") and add a negative value. But beforehand I would need to know if the critter has a DR and if yes what kind of DR it is (e.g.= DR 10/magic.) Basically I need access to the DR list of a critter. I think this is the part where the c++ checks if there is a DR (in damage.cpp): Code: int DamagePacket::AddPhysicalDR(int amount, int bypasserBitmask, int damageMesLine){ return damage.AddPhysicalDR(this, amount, bypasserBitmask, (unsigned)damageMesLine); } int DamagePacket::AddDR(int amount, DamageType damType, int damageMesLine){ if (this->damResCount < 5u){ this->damageResistances[this->damResCount].damageReductionAmount = amount; this->damageResistances[this->damResCount].dmgFactor = 0.0f; this->damageResistances[this->damResCount].type = damType; this->damageResistances[this->damResCount].attackPowerType = D20DAP_UNSPECIFIED; this->damageResistances[this->damResCount].typeDescription = damage.GetMesline(damageMesLine); this->damageResistances[this->damResCount++].causedBy = nullptr; return TRUE; } return FALSE;
That'll require extending the API for sure. Modifying modifiers is usually messy... I'd put it on the backburner for now.
Hey Sitra, had an idea for Temple+ - if you have multiple characters selected (eg the whole party) and you hit 'search', then everyone searches, not just the lead character. Useful for finding secret stuff quickly with whole party.
Huh, I always thought that's how it is, but it turns out your party only pitches in for a +2 bonus. Wouldn't it be more by the RAW to instead select the highest search skill member?
If they are, that's awesome and shouldn't be changed, but I was thinking of scenarios where the party is spread out and it would be nice to just hit one button and have everyone search a wide area. You may still need to send your highest Search skill guy around to double check, but you are going to do that anyway.
+1 to Ted. Also, if the party is focused on searching a small area, each party member and familiar and animal companion aiding should provide +2.