def OnSpellEffect(spell): print "Mirror Image OnSpellEffect" spell.duration = 10 * spell.caster_level target_item = spell.target_list[0] bonus = 1 + (spell.caster_level / 3) num_of_images = spell.roll_dice_with_metamagic(1, 4, bonus) spellPkt = tpdp.SpellPacket(spell.id) mmData = tpdp.MetaMagicData(spellPkt.get_metamagic_data()) #Maximum of 8 images from the spell description (empower to 12) if mmData.get_empower_count() > 0: ImageCap = 12 else: ImageCap = 8 num_of_images = min(ImageCap, num_of_images) print "num of images=", num_of_images, "bonus=", bonus game.particles('sp-Mirror Image', target_item.obj) target_item.obj.condition_add_with_args('sp-Mirror Image', spell.id, spell.duration, num_of_images)
def touchPre(args, evt_obj): action = evt_obj.get_d20_action() caster = action.performer target = action.target spell_id = args.get_arg(0) duration = args.get_arg(1) charges = args.get_arg(2) packet = tpdp.SpellPacket(spell_id) if charges > 0: args.set_arg(2, charges-1) resisted = packet.check_spell_resistance(target) if charges == 1: packet.end_target_particles(caster) packet.remove_target(caster) args.condition_remove() if resisted: game.particles('Fizzle', target) game.sound(7461,1) else: packet.add_target(target, 0) packet.update_registry() if packet.target_count <= 0: args.spell_remove() return resisted
def MomentOfPrescienceRadial(attachee, args, evt_obj): spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) bonus = min(spell_packet.caster_level, 25) bonusString = "+" + str(bonus) #Add the top level menu radial_parent = tpdp.RadialMenuEntryParent("Moment of Prescience") MomentOfPrescienceId = radial_parent.add_child_to_standard(attachee, tpdp.RadialMenuStandardNode.Feats) #Add a checkbox to turn on and off the various features of the spell checkboxACBonus = tpdp.RadialMenuEntryToggle(bonusString + " to AC next attack", "TAG_INTERFACE_HELP") checkboxACBonus.link_to_args(args, 2) checkboxACBonus.add_as_child(attachee, MomentOfPrescienceId) checkboxACBonus = tpdp.RadialMenuEntryToggle(bonusString + " to next save", "TAG_INTERFACE_HELP") checkboxACBonus.link_to_args(args, 3) checkboxACBonus.add_as_child(attachee, MomentOfPrescienceId) checkboxACBonus = tpdp.RadialMenuEntryToggle(bonusString + " to next Attack", "TAG_INTERFACE_HELP") checkboxACBonus.link_to_args(args, 4) checkboxACBonus.add_as_child(attachee, MomentOfPrescienceId) #checkboxACBonus = tpdp.RadialMenuEntryToggle(bonusString + " to next Skill Check", "TAG_INTERFACE_HELP") #checkboxACBonus.link_to_args(args, 5) #checkboxACBonus.add_as_child(attachee, MomentOfPrescienceId) return 0
def DeathAtkDamage(attachee, args, evt_obj): #print "Death Attack Sneak Attack Not active" if not args.get_arg(0): return 0 #print "DeathAtkDamage" if evt_obj.attack_packet.get_flags( ) & D20CAF_RANGED: # Death Attack is for Melee attacks only return 0 tgt = evt_obj.attack_packet.target if tgt == OBJ_HANDLE_NULL: return 0 #print "got target" spell_id = args.get_arg(2) if spell_id == 0: return 0 #print "got spell id" spell_packet = tpdp.SpellPacket(spell_id) if tgt != spell_packet.get_target(0): return 0 #print "target is spell target" if not tgt.d20_query("Is Death Attack Ready"): return 0 #print "DeathAtkDamage target ok" # check that target is unaware of assassin (and if it is, override it if it's helpless) if (tgt.is_active_combatant() and not tgt.d20_query(Q_Flatfooted) ) and tgt.can_see(attachee) and (not tgt.d20_query(Q_Helpless)): game.create_history_freeform(tgt.description + " notices " + attachee.description + ", Death Attack unsuccessful...\n\n") return 0 #print "Ending Death Attack Target" tgt.d20_send_signal( "Death Attack Target End", spell_id) # end the target's Death Attack Target status args.set_arg(0, 0) ass_level = attachee.stat_level_get(classEnum) int_level = attachee.stat_level_get(stat_intelligence) int_mod = (int_level - 10) / 2 game.create_history_freeform(attachee.description + " attempting Death Attack...\n\n") if tgt.saving_throw_spell(10 + ass_level + int_mod, D20_Save_Fortitude, D20STD_F_NONE, attachee, spell_id): tgt.float_mesfile_line('mes\\spell.mes', 30001) game.create_history_freeform("Death Attack failed.\n\n") else: attachee.float_text_line("Death Attack!") if not args.get_arg(1): # death effect tgt.critter_kill_by_effect(attachee) game.create_history_freeform("Killed by Death Attack!\n\n") else: # paralysis effect tgt.condition_add_with_args("Paralyzed", ass_level + game.random_range(1, 6), 0, 0) game.create_history_freeform("Target paralyzed.\n\n") return 0
def mirror_image_attack_roll(d20a, spell_id): performer = d20a.performer target = d20a.target #Target AC mi_ac_evt_obj = tpdp.EventObjAttack() mi_ac_evt_obj.attack_packet.attacker = performer mi_ac_evt_obj.attack_packet.target = target flags = d20a.flags flags |= D20CAF_TOUCH_ATTACK mi_ac_evt_obj.attack_packet.set_flags(flags) mi_ac_evt_obj.attack_packet.action_type = d20a.action_type mi_ac_evt_obj.dispatch(target, OBJ_HANDLE_NULL, ET_OnGetAC, EK_NONE) tgt_ac = mi_ac_evt_obj.bonus_list.get_sum() #Performer to Hit Bonus to_hit = tpdp.EventObjAttack() to_hit.dispatch(performer, OBJ_HANDLE_NULL, ET_OnToHitBonus2, EK_NONE) dc = 20 to_hit_dice = dice_new("1d{}".format(dc)) to_hit_roll = to_hit_dice.roll() to_hit_bonus = to_hit.bonus_list.get_sum() spell_enum = tpdp.SpellPacket(spell_id).spell_enum spell_name = game.get_spell_mesline(spell_enum) roll_id = tpdp.create_history_dc_roll(performer, tgt_ac, to_hit_dice, to_hit_roll, spell_name, to_hit.bonus_list) result = to_hit_roll - dc + to_hit_bonus d20a.roll_id_0 = roll_id return result
def sp_darkness_hit_OnLeaveAoE(attachee, args, evt_obj): assert isinstance(attachee, toee.PyObjHandle) assert isinstance(args, tpdp.EventArgs) assert isinstance(evt_obj, tpdp.EventObjObjectEvent) obj_evt_id = args.get_arg(2) if (obj_evt_id != evt_obj.evt_id): return 0 target = evt_obj.target if (not attachee or not target): return 0 f = target.object_flags_get() if ((f & toee.OF_OFF) or (f & toee.OF_DESTROYED) or (f & toee.OF_DONTDRAW)): return 0 spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) if (not spell_packet): print("spell_packet is null!") debug.breakp("spell_packet is null") return 0 spell_packet.end_target_particles(target) spell_packet.remove_target(target) args.remove_spell_mod() print("sp-Darkness removed from {} (sp_darkness_hit_OnLeaveAoE)".format(attachee)) return 0
def OnWallAoEEntered(attachee, args, evt_obj): #print "Wall of Fire entered event" obj_evt_id = args.get_arg(2) spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) duration = args.get_arg(1) caster = spell_packet.caster if obj_evt_id != evt_obj.evt_id: #print "Wall of Fire Entered: ID mismatch " + str(evt_obj.evt_id) + ", stored was: " + str(obj_evt_id) return 0 #print "Wall of Fire Entered, event ID: " + str(obj_evt_id) tgt = evt_obj.target if tgt == OBJ_HANDLE_NULL or attachee == OBJ_HANDLE_NULL or tgt == attachee: return 0 #print str(tgt) + " hit by wall of fire" spell_packet.trigger_aoe_hit() if spell_packet.check_spell_resistance(tgt): return 0 # apply sp-Wall of Fire hit condition (applies damage on beginning of round) partsys_id = game.particles( "sp-Wall of Fire-hit", tgt ) if spell_packet.add_target(tgt, partsys_id): tgt.condition_add_with_args('sp-Wall of Fire hit', spell_id, duration, obj_evt_id) return 0
def TouchOfFatigueSpellCast(attachee, args, evt_obj): #End the spell if the character casts another spell spell_id = evt_obj.data1 packet = tpdp.SpellPacket(spell_id) if packet.caster == attachee: args.condition_remove() args.remove_spell() return 0
def OnConcentrationBroken(attachee, args, evt_obj): #print "Concentration broken" spellId = args.get_arg(0) spell_packet = tpdp.SpellPacket(spellId) if spell_packet.spell_enum == 0: return 0 args.remove_spell() #args.remove_spell_mod() return 0
def OnCombatEnd(attachee, args, evt_obj): #print "Combat End" spellId = args.get_arg(0) spell_packet = tpdp.SpellPacket(spellId) if spell_packet.spell_enum == 0: return if spell_packet.caster != OBJ_HANDLE_NULL: spell_packet.float_spell_line(spell_packet.caster, 20000, tf_white) args.remove_spell() args.remove_spell_mod() return 0
def OnWallAoEExit(attachee, args, evt_obj): evt_id = args.get_arg(2) if evt_id != evt_obj.evt_id: return 0 print "Removing sp-Wall of fire hit on " + str(attachee) spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) spell_packet.end_target_particles(attachee) spell_packet.remove_target(attachee) args.remove_spell_mod() return 0
def MomentOfPrescienceSaveBonus(attachee, args, evt_obj): if not (evt_obj.flags & 1<<(D20STD_F_FINAL_ROLL-1)): return 0 enabled_flag = args.get_arg(3) if enabled_flag: spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) bonus = min(spell_packet.caster_level, 25) evt_obj.bonus_list.add(bonus, 0, "Moment of Prescience") # Insight Bonus args.condition_remove() args.remove_spell() return 0
def WallOfFireBeginRound(attachee, args, evt_obj): #print "Wall of Fire begin round" tgt = attachee spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) caster = spell_packet.caster damage_dice = dice_new( '2d4' ) undead_dice = dice_new('4d4') if tgt.is_category_type( mc_type_undead ): tgt.spell_damage(caster, D20DT_FIRE, undead_dice, D20DAP_UNSPECIFIED, D20A_CAST_SPELL, spell_id) else: tgt.spell_damage(caster, D20DT_FIRE, damage_dice, D20DAP_UNSPECIFIED, D20A_CAST_SPELL, spell_id) return 0
def MomentOfPrescienceAttackBonus(attachee, args, evt_obj): #Test to make sure it is not called from the character sheet if not (evt_obj.attack_packet.get_flags() & D20CAF_FINAL_ATTACK_ROLL): return 0 enabled_flag = args.get_arg(4) if enabled_flag: spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) bonus = min(spell_packet.caster_level, 25) evt_obj.bonus_list.add(bonus, 0, "Moment of Prescience") # Insight Bonus args.condition_remove() args.remove_spell() return 0
def MomentOfPrescienceAcBonus(attachee, args, evt_obj): #Test to make sure it is not called from the character sheet attacker = evt_obj.attack_packet.attacker if attacker == OBJ_HANDLE_NULL or attacker == attachee: return 0 enabled_flag = args.get_arg(2) if enabled_flag: spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) bonus = min(spell_packet.caster_level, 25) evt_obj.bonus_list.add(bonus, 0, "Moment of Prescience") # Insight Bonus args.condition_remove() args.remove_spell() return 0
def WallOfFireHitDamage(attachee, args, evt_obj): #print "Wall of Fire hit damage" tgt = attachee spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) caster = spell_packet.caster damage_dice = dice_new( '2d6' ) damage_dice.bonus = min( 1 * spell_packet.caster_level, 20 ) undead_dice = dice_new('4d6') undead_dice.bonus = min( 2 * spell_packet.caster_level, 40 ) if tgt.is_category_type( mc_type_undead ): tgt.spell_damage(caster, D20DT_FIRE, undead_dice, D20DAP_UNSPECIFIED, D20A_CAST_SPELL, spell_id) else: tgt.spell_damage(caster, D20DT_FIRE, damage_dice, D20DAP_UNSPECIFIED, D20A_CAST_SPELL, spell_id) return 0
def HasStudiedTarget(attachee, args, evt_obj): #print "Has Studied Target test:" spell_id = args.get_arg(2) #print "Spell ID: " + str(spell_id) if spell_id == 0: return 0 spell_packet = tpdp.SpellPacket(spell_id) #print "Spell packet obtained, checking target" tgt = spell_packet.get_target(0) #print "got target" if tgt == OBJ_HANDLE_NULL: return 0 #print "checking is death attack ready" if not tgt.d20_query("Is Death Attack Ready"): return 0 #print " returning ok" evt_obj.return_val = 1 return 0
def CondBeginRound(target, args, evt_obj): Debug(False, "CondBeginRound") spell_id = args.get_arg(0) duration = args.get_arg(1) dc = args.get_arg(2) ticks = evt_obj.data1 packet = tpdp.SpellPacket(spell_id) caster = packet.caster args.set_arg(1, duration - ticks) if WillSaveAndDamage(target, caster, spell_id, dc, duration, ticks): args.condition_remove() packet.remove_target(target) if packet.target_count <= 0: args.remove_spell() return 0
def OnEndProjectile(spell, projectile, index_of_target): Debug("OnEndProjectile") target_item = spell.target_list[index_of_target] target = target_item.obj caster = spell.caster packet = tpdp.SpellPacket(spell.id) dice = dice_new("1d6") if not packet.check_spell_resistance_force(target): dice.num = min(5, spell.caster_level) target.spell_damage( caster, D20DT_FIRE, dice, D20DAP_UNSPECIFIED, D20A_CAST_SPELL, spell.id) spell.num_of_projectiles -= 1 if spell.num_of_projectiles == 0: spell.spell_end(spell.id, 1)
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 sp_darkness_S_Combat_End(attachee, args, evt_obj): assert isinstance(attachee, toee.PyObjHandle) assert isinstance(args, tpdp.EventArgs) print("sp_darkness_S_Combat_End attachee: {}".format(attachee)) try: spellId = args.get_arg(0) spell_packet = tpdp.SpellPacket(spellId) if (spell_packet.spell_enum == 0): print("sp_darkness_S_Combat_End attachee: {} spell_packet.spell_enum == 0!!".format(attachee)) return print("sp_darkness_S_Combat_End attachee: {} removing spell!".format(attachee)) #args.remove_spell() spell_packet.end_target_particles(attachee) lst = list() for i in range(0, 20): target = spell_packet.get_target(i) if (not target): continue #if (target == attachee): continue lst.append(target) print(lst) for target in lst: print("target.d20_send_signal(toee.EK_S_Spell_End, {}) for {}".format(spellId, target)) spell_packet.end_target_particles(target) target.d20_send_signal(toee.EK_S_Spell_End-toee.EK_S_HP_Changed, spellId) spell_packet.remove_target(target) lst = None spell_packet.update_registry() #spell_packet.remove_target(attachee) args.remove_spell_with_key(toee.EK_S_Killed) args.remove_spell_mod() args.set_arg(1, 0) except Exception, e: print "sp_darkness_S_Combat_End error:" print '-'*60 traceback.print_exc(file=sys.stdout) print '-'*60 debug.breakp("error")
def AbjurantChampionArcaneBoostPerform(attachee, args, evt_obj): spell_packet = tpdp.SpellPacket(attachee, evt_obj.d20a.spell_data) #Count the spell as used up spell_packet.debit_spell() #Create the effect based on the level of the spell type = evt_obj.d20a.data1 amount = 0 if type == 1 or type == 3 or type == 4: amount = spell_packet.spell_known_slot_level #Hit, AC, Save Equal to Spell Level elif type == 2: amount = 2 * spell_packet.spell_known_slot_level #Damage Equal to Twice Spell Level else: amount = 5 * spell_packet.spell_known_slot_level #Energy Resistance Equal to Five Times Spell Level #Add the effect with two parameters: effect type and effect bonus attachee.condition_add_with_args("Arcane Boost Effect", type, amount, 0, 0) return 0
def sp_darkness_OnConditionAdd(attachee, args, evt_obj): assert isinstance(attachee, toee.PyObjHandle) assert isinstance(args, tpdp.EventArgs) radius = args.get_arg(3) if (not radius): radius = 20 radius_feet = radius + (attachee.radius / 12.0) obj_evt_id = attachee.object_event_append(toee.OLC_CRITTERS, radius_feet) args.set_arg(2, obj_evt_id) # store evt_id spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) spell_obj = attachee spell_partsys_id = toee.game.particles("sp-Solid Fog", spell_obj) spell_packet.add_spell_object(spell_obj, spell_partsys_id) # store the spell obj and the particle sys spell_packet.update_registry() return
def OnStudyTargetPerform(attachee, args, evt_obj): #print "Performing Death Attack - Study Target" if evt_obj.d20a.target == OBJ_HANDLE_NULL: print "no target! PLS HANDLE ME" old_spell_id = args.get_arg(2) if old_spell_id: spell_packet = tpdp.SpellPacket(old_spell_id) prev_tgt = spell_packet.get_target(0) if prev_tgt != OBJ_HANDLE_NULL and prev_tgt.d20_query("Is Death Attack Target"): prev_tgt.d20_send_signal("Death Attack Target End", old_spell_id) prev_tgt.float_text_line("Target removed", tf_white) # put the new spell_id in arg2 new_spell_id = tpactions.get_new_spell_id() args.set_arg(2, new_spell_id) # register the spell in the spells_cast repository so it triggers the spell scripts (Spell3210 - Death Attack.py) cur_seq = tpactions.get_cur_seq() tpactions.register_spell_cast(cur_seq.spell_packet, new_spell_id) tpactions.trigger_spell_effect(new_spell_id) return 0
def WallOfFireOnAdd(attachee, args, evt_obj): spell_id = args.get_arg(0) wall_angle_mrad = args.get_arg(3) wall_length_mft = args.get_arg(4) wall_angle_rad = wall_angle_mrad / 1000.0 wall_length_ft = wall_length_mft / 1000.0 evt_id = attachee.object_event_append_wall(OLC_CRITTERS, wall_length_ft, wall_angle_rad) args.set_arg(2, evt_id) # store the event ID # Update the spell packet spell_packet = tpdp.SpellPacket(spell_id) spell_obj = attachee #x,y = location_to_axis(spell_obj.location) #print "spell_obj loc x,y: " + str(x) + " " + str(y) #print "spell_obj loc off_x: " + str(spell_obj.off_x) #print "spell_obj loc off_y: " + str(spell_obj.off_y) spell_partsys_id = game.particles('sp-Wall of Fire3', spell_obj) spell_packet.add_spell_object(spell_obj, spell_partsys_id) # store the spell obj and the particle sys origin_loc = attachee.location_full N_sections = int(round(wall_length_ft / 5.0)) #print "Wall length(ft): " + str(wall_length_ft) + " sections: " + str(N_sections) for p in range(1, N_sections): spell_obj_loc = origin_loc.get_offset_loc(wall_angle_rad, p*5.0) spell_obj = game.obj_create(OBJECT_SPELL_GENERIC, spell_obj_loc.get_location(), spell_obj_loc.off_x, spell_obj_loc.off_y) spell_obj.move(spell_obj_loc.get_location(), spell_obj_loc.off_x, spell_obj_loc.off_y) spell_obj.turn_towards(attachee) spell_obj.rotation += 3.1415 x,y = location_to_axis(spell_obj.location) #print "spell_obj loc x,y: " + str(x) + " " + str(y) #print "spell_obj loc off_x: " + str(spell_obj.off_x) #print "spell_obj loc off_y: " + str(spell_obj.off_y) spell_partsys_id = game.particles('sp-Wall of Fire3', spell_obj) spell_packet.add_spell_object( spell_obj, spell_partsys_id) # store the spell obj and the particle sys spell_packet.update_registry() spell_packet.caster.condition_add_with_args('sp-Concentrating', spell_id) return 0
def sp_darkness_OnEnterAoE(attachee, args, evt_obj): assert isinstance(attachee, toee.PyObjHandle) assert isinstance(args, tpdp.EventArgs) assert isinstance(evt_obj, tpdp.EventObjObjectEvent) try: print("sp_darkness_OnEnterAoE attachee: {}, evt_obj.target: {}".format(attachee, evt_obj.target)) obj_evt_id = args.get_arg(2) if (obj_evt_id != evt_obj.evt_id): return 0 target = evt_obj.target if (not attachee or not target): return 0 f = target.object_flags_get() if ((f & toee.OF_OFF) or (f & toee.OF_DESTROYED) or (f & toee.OF_DONTDRAW)): return 0 spell_id = args.get_arg(0) spell_packet = tpdp.SpellPacket(spell_id) if (not spell_packet): print("spell_packet is null!") debug.breakp("spell_packet is null") return 0 spell_packet.trigger_aoe_hit() duration = args.get_arg(1) if (target != attachee): partsys_id = toee.game.particles( "sp-Solid Fog-hit", target) spell_packet.add_target(target, partsys_id) spell_packet.update_registry() target.condition_add_with_args('sp-Darkness hit', spell_id, duration, obj_evt_id) except Exception, e: print "sp_darkness_S_Combat_End error:" print '-'*60 traceback.print_exc(file=sys.stdout) print '-'*60 debug.breakp("error")
def MagicCircleOutwardEffDamageResistance(attachee, args, evt_obj): attacker = evt_obj.attack_packet.attacker if attacker == OBJ_HANDLE_NULL: return 0 if attacker.d20_query_has_condition("sp-Summoned"): type = args.get_arg(1) canAttack = SummonCanAttack(attacker, type) if not canAttack: wpn = evt_obj.attack_packet.get_weapon_used() if wpn != OBJ_HANDLE_NULL: return 0 spell_id = args.get_arg(2) spell_packet = tpdp.SpellPacket(spell_id) resisted = spell_packet.check_spell_resistance_force(attacker) if resisted: return 0 evt_obj.damage_packet.add_mod_factor(0.0, D20DT_UNSPECIFIED, 104) #Do no damage at all return 0
def addDismiss(attachee, args, evt_obj): spellPacket = tpdp.SpellPacket(args.get_arg(0)) spellPacket.caster.condition_add_with_args('Dismiss', args.get_arg(0)) return 0
def addConcentration(attachee, args, evt_obj): spellPacket = tpdp.SpellPacket(args.get_arg(0)) spellPacket.caster.condition_add_with_args('sp-Concentrating', args.get_arg(0)) return 0
def Descr(spell_id): packet = tpdp.SpellPacket(spell_id) return game.get_spell_mesline(packet.spell_enum)