def RapidMMActionCostMod(attachee, args, evt_obj): if evt_obj.d20a.action_type != tpdp.D20ActionType.CastSpell: return 0 if evt_obj.cost_orig.action_cost <= 2: # original is already less than full round return 0 if evt_obj.cost_new.action_cost <= 0: # adjusted amount is already free action return 0 # check if the original spell is standard action or less - if so reduce action cost to standard action spData = evt_obj.d20a.spell_data spEntry = tpdp.SpellEntry(spData.spell_enum) if spEntry.spell_enum == 0: return 0 castingTimeType = spEntry.casting_time mmData = spData.get_metamagic_data() isQuicken = mmData.get_quicken() if isQuicken and not (evt_obj.turnbased_status.flags & TBSF_FreeActionSpellPerformed): evt_obj.cost_new.action_cost = 0 evt_obj.turnbased_status.flags |= TBSF_FreeActionSpellPerformed #print "reducing cost to 0" return 0 return 0
def MindBlankImmunity(attachee, args, evt_obj): sp_pkt = evt_obj.spell_packet spell_enum = sp_pkt.spell_enum if (spell_enum == 0): return 0 spell_entry = tpdp.SpellEntry(spell_enum) if spell_entry.descriptor & (1<<(D20STD_F_SPELL_DESCRIPTOR_MIND_AFFECTING-14)): attachee.float_text_line( "Mind Affecting Immunity", tf_red ) evt_obj.return_val = 1 return 0
def PhantasmImmunity(attachee, args, evt_obj): sp_pkt = evt_obj.spell_packet # Check if phantasm subschool spell_enum = sp_pkt.spell_enum if (spell_enum == 0): return 0 spell_entry = tpdp.SpellEntry(spell_enum) if (spell_entry.spell_school_enum != Illusion or spell_entry.spell_subschool_enum != Phantasm): return 0 evt_obj.return_val = 1 return 0
def ExtendAbjurationMetamagicUpdate(attachee, args, evt_obj): #Check for abjuration school spEntry = tpdp.SpellEntry(evt_obj.spell_enum) if spEntry.spell_school_enum != Abjuration: return 0 #Get the metamagic info metaMagicData = evt_obj.meta_magic #Don't Extend more than once if metaMagicData.get_extend_count() < 1: metaMagicData.set_extend_count(1) return 0
def IsAdvancedLearningSpell(obj, spell): spEntry = tpdp.SpellEntry(spell.spell_enum) #Don't add spells that are already known to the list if obj.is_spell_known(spell.spell_enum): return False #First get rid of everything in the warmage spell list for level, spell_list_level in spell_list.items(): if spell.spell_enum in spell_list_level: return False #Next, get rid of everything that is not evocation if spEntry.spell_school_enum == Evocation: return True return False
def PhantasmImmunitySaveBonus(attachee, args, evt_obj): flags = evt_obj.flags if not (flags & (1 << (D20STD_F_SPELL_LIKE_EFFECT - 1))): # 0x10 return 0 sp_pkt = evt_obj.spell_packet # Check if phantasm subschool spell_enum = sp_pkt.spell_enum if (spell_enum == 0): return 0 spell_entry = tpdp.SpellEntry(spell_enum) if (spell_entry.spell_school_enum != Illusion or spell_entry.spell_subschool_enum != Phantasm): return 0 evt_obj.return_val = 1 return 0
def QueryHealingBonus(attachee, args, evt_obj): #Note: This implementation effects only damage healed by effected spells. Damage done to undead is not increased. # Also empower will apply to this bonus. This seems to be the best interpretation of the feat. healingBonus = 0 #Argument is the spell id, 0 indicates non spell healing if evt_obj.data1 > 0: spPacket = tpdp.SpellPacket(evt_obj.data1) if spPacket.spell_enum > 0: spEntry = tpdp.SpellEntry(spPacket.spell_enum) #Is it a conjuration(healing) spell if spEntry.spell_school_enum == Conjuration and spEntry.spell_subschool_enum == Healing: #Bonus is twice the spell level healingBonus = 2 * spPacket.spell_known_slot_level #Return the bonus evt_obj.return_val += healingBonus return 0
def SwiftAbjurationMetamagicUpdate(attachee, args, evt_obj): #Check for abjuration school spEntry = tpdp.SpellEntry(evt_obj.spell_enum) if spEntry.spell_school_enum != Abjuration: return 0 #Check for spell level less than half of class level rounded update maxLevel = attachee.stat_level_get(classEnum) + 1 maxLevel = int(maxLevel / 2) if evt_obj.spell_level > maxLevel: return 0 #Get the metamagic info metaMagicData = evt_obj.meta_magic #Don't quicken more than once if metaMagicData.get_quicken() < 1: metaMagicData.set_quicken(1) return 0
def Immunity_Visual_OnSpellImmunityCheck(attachee, args, evt_obj): assert isinstance(attachee, toee.PyObjHandle) assert isinstance(args, tpdp.EventArgs) assert isinstance(evt_obj, tpdp.EventObjImmunityQuery) #print("Immunity_Visual_OnSpellImmunityCheck") spell_enum = evt_obj.spell_packet.spell_enum #print("evt_obj.spell_packet.spell_enum: {}".format(spell_enum)) if (not spell_enum): return 0 spell_entry = tpdp.SpellEntry(spell_enum) #print(spell_entry) if (not spell_entry): return 0 #print("spell_enum: {}, spell_school_enum: {}, spell_subschool_enum: {}, descriptor: {}".format(spell_entry.spell_enum, spell_entry.spell_school_enum, spell_entry.spell_subschool_enum, spell_entry.descriptor)) if (spell_entry.descriptor & (1 << (toee.D20STD_F_SPELL_DESCRIPTOR_LIGHT - toee.D20STD_F_SPELL_DESCRIPTOR_ACID))): attachee.float_text_line("Visual Affecting Immunity", toee.tf_red) evt_obj.return_val = 1 return 0
def RapidMMActionCostMod(attachee, args, evt_obj): if evt_obj.d20a.action_type != tpdp.D20ActionType.CastSpell: return 0 if not game.combat_is_active(): return 0 if evt_obj.cost_orig.action_cost <= 2: # original is already less than full round return 0 if evt_obj.cost_new.action_cost <= 0: # adjusted amount is already free action return 0 # check if the original spell is standard action or less - if so reduce action cost to standard action spData = evt_obj.d20a.spell_data spEntry = tpdp.SpellEntry(spData.spell_enum) if spEntry.spell_enum == 0: return 0 casting_time_type = spEntry.casting_time mmData = spData.get_metamagic_data() isQuicken = mmData.get_quicken() if isQuicken and not (evt_obj.turnbased_status.flags & TBSF_FreeActionSpellPerformed): evt_obj.cost_new.action_cost = 0 evt_obj.turnbased_status.flags |= TBSF_FreeActionSpellPerformed #print("RapidMM: reducing cost to 0") return 0 #print('RapidMM restore orig time: ') # restore the original spell's casting time action_err_code, action_cost_base = tpactions.action_cost_from_spell_casting_time( casting_time_type) if action_err_code != AEC_OK: # should only be AEC_OUT_OF_COMBAT... return 0 if action_cost_base < evt_obj.cost_orig.action_cost: #print('new action cost: ', action_cost_base) evt_obj.cost_new.action_cost = action_cost_base return 0
def Immunity_Illusion_OnSpellImmunityCheck(attachee, args, evt_obj): assert isinstance(attachee, toee.PyObjHandle) assert isinstance(args, tpdp.EventArgs) assert isinstance(evt_obj, tpdp.EventObjImmunityQuery) #print("Immunity_Illusion_OnSpellImmunityCheck") #spell_entry = evt_obj.spell_entry spell_enum = evt_obj.spell_packet.spell_enum #print("evt_obj.spell_packet.spell_enum: {}".format(spell_enum)) if (not spell_enum): return 0 spell_entry = tpdp.SpellEntry(spell_enum) #print(spell_entry) if (not spell_entry): return 0 #print("spell_enum: {}, spell_school_enum: {}, spell_subschool_enum: {}, descriptor: {}".format(spell_entry.spell_enum, spell_entry.spell_school_enum, spell_entry.spell_subschool_enum, spell_entry.descriptor)) if (spell_entry.spell_school_enum == ( toee.D20STD_F_SPELL_SCHOOL_ILLUSION - toee.D20STD_F_SPELL_SCHOOL_ABJURATION + 1)): attachee.float_text_line("Illusion Affecting Immunity", toee.tf_red) evt_obj.return_val = 1 return 0
def ObjMeetsPrereqs( obj ): #Maximum number of levels is 5 classLvl = obj.stat_level_get(classEnum) if classLvl >= 5: return 0 if obj.arcane_spell_level_can_cast() < 1: return 0 if obj.get_base_attack_bonus() < 5: return 0 if not obj.has_feat(feat_combat_casting): return 0 #Can Cast 1st level or greater abjuration can_cast_abjuration = false known_spells = obj.spells_known for knSp in known_spells: if knSp.spell_level > 0: spell_entry = tpdp.SpellEntry(knSp.spell_enum) if spell_entry.spell_school_enum == Abjuration: can_cast_abjuration = true break if not can_cast_abjuration: return 0 #Check for martial weapon proficiency if obj.has_feat(feat_martial_weapon_proficiency_all): return 1 has_martial_feat = false for i in range (feat_martial_weapon_proficiency_throwing_axe , feat_martial_weapon_proficiency_composite_longbow): if char_editor.has_feat(i): has_martial_feat = true return has_martial_feat
def WarmageEdgeOnSpellDamage(attachee, args, evt_obj): #Only effects warmage spells spellCastingClass = evt_obj.spell_packet.get_spell_casting_class() if spellCastingClass != stat_level_warmage: return 0 prevSpellID = args.get_arg(0) spellID = evt_obj.spell_packet.spell_id spEntry = tpdp.SpellEntry(evt_obj.spell_packet.spell_enum) multiTarget = spEntry.is_base_mode_target(MODE_TARGET_MULTI) target = evt_obj.target if multiTarget: #If the same multi target is doing damage again, no bonus if prevSpellID == spellID: return 0 elif evt_obj.spell_packet.spell_enum != spell_melfs_acid_arrow: #Always give the bonus to acid arrow if target.d20_query_with_data("Warmage Edge Damage Taken", spellID): return 0 int = attachee.stat_level_get(stat_intelligence) intMod = (int - 10)/2 #Increase warmage edge damage on a critical hit if evt_obj.damage_packet.critical_multiplier > 1: intMod = intMod * 2 if intMod > 0: evt_obj.damage_packet.bonus_list.add_from_feat(intMod, 0, 137, "Warmage Edge") args.set_arg(0, spellID) target.condition_add_with_args("Warmage Edge Damage", spellID) return 0