-
Notifications
You must be signed in to change notification settings - Fork 2
RemakeManual ‐ Spells
03-Spells
Definition : All abilities are technically spells. This includes spells from the spells list, and also many item effects on use like potions and scrolls, and ranged weapon attacks. They are defined in the "spells" folder,in a single JSON file named "spells_book.json".
CTRL+F : 1-That big annoying JSON file 2-What is in a spell : Variables 3-What is in a spell : Functions 4-How they work
1-That big annoying JSON file :
The "spells_book.json" file is just a big dictionary with spell godot scripts as values. For some reason, the "escape" character does not seem to work with the parser even though they are added automatically when saving a JSON with text. Spells are stored this way because they are also saved as part of a character's file, and this ensures they are properly saved as a JSON dictionary value. For this reason, you should be very careful only to use quotes ( " ) around the spell names and their script, but not inside the script around Strings. Use apostrophes instead ( ' ).
"Example Spell" : " var name : String = 'Example Spell' var attributes : Array = ['Physical', 'Ranged'] #ETC "
Unlike Items and Creatures, Spell data files do not refer to images on a big TextureAtlas PNG file. This is bcause I do not expect people to need that feature. However, if you really want to, you could store custom image data as a .zipped String in a spell's data, just like inventory item images are stored in a saved game file.
2-What is in a spell : Variables :
The variables : Almost all are necessary.
#The name displayed in-game, necessary. var name : String = 'Heal Minor Wounds'
#Its attributes, used for damage calculation, resistances, #whether it can be learned by a class, etc. necessary. var attributes : Array = ['Healing']
#whether the spell can be targeted at empty tiles, only creatures, anywhere, #or anywhere with no wall. var targettile : int = 1 #0=anywhere 1=creature 2=empty 3=nowall
#Mostly used to determine which class can learn this spell. var school : String = 'Priest'
#The "rank" of the spell, from 1 to 7. Higher = more advanced. var level : int = 1
var selection_cost : int = 1
#Max Power Level #some spells like SleepWalk or encounter only spells can only be cast at lvl1. var max_plevel : int = 7
#Whether this spell can be cast out of combat (field) / in combat var in_field : bool = true var in_combat : bool = true
#The description in the Cast menu. Use \n for new lines. var description : String = 'Instantly heals a single target in melee range\nHeal : 1-8 x Power\nSP cost : Power * 10'
#which resistances the spell bypasses.
#0 = ignores resistances and dodge
#1 = ignores dodge, Can be resisted
#2 = can be resisted but not dodged
#3 = proctected with resistances and dodge
var resist : int = 0 #ignores resistances and dodge
#Whether the spell requires line of sight (unobstructed view, no walls in path) var los : bool = true
#If this is true, the line of sight is added to the area of effect. var ray : bool = false
#if this is true, the Area of Effect is a rectangle rotated with the Return key. Like Walls. var rot : bool = false
#The name of the textures used for the projectile and the "explosion" on the target. #proj_tex is NOT mandatory, immitting it results in the spell having no visible projectile. #which is probably better for spells that target All Allies or Enemies, or only the caster. #defined in SpellAnimation.gd, images in BattleEffectsAnim.png
var proj_tex : String = 'Cloud' var proj_hit : String = 'Sphere'
#If the spells leaves a terrain effect, like Plane of Frost, the texture of the terrain.
var terrain_tex : String = 'Spk'
#the name of the sound effect files used for the Projectile and Explosion animation, #they are found in the sounds/ folder. #empty string means no sound effect. var sounds : Array = ['','slurpy.wav']
#The kind of Area of Effect, as defined in TargetingLayer.gd #'b1'-'b7' : ba is a single tile, bigger number = bigger explosions #'wh' 'wv' 'wl' 'wj' : wall shape, -- | \ / #'cr' : crown shape, same as b3+b4 #To be honest, I think the function get_aoe pretty much took this variable's job. var aoe : String = 'b1'
3-What is in a spell : Functions
#Default to 0 static func get_sp_cost(plvl : int, chara : creature) -> int
#(can be creatures for atatcks, or empty spaces for summons...) static func get_target_number(power : int, casterchar) : return 1
#These are only necessary to display info on the Spell Cast menu. static func get_min_duration(power : int, casterchar) -> int : return 0 static func get_max_duration(power : int, casterchar) -> int : return 0
#adds traits/status effects to target, NOT MANDATORY static func add_traits_to_target(caster : Creature, target : Creature, power : int) var traitscript = load('res://shared_assets/traits/'+'regen.gd') var traitarray : Array = [1,power] target.add_trait(traitscript, traitarray)
#Critical hit checks, NOT MANDATORY #a critical hit roll, returns true iff it's a crit. Some spells may or may not crit. static func get_is_critical(casterchar, defender, spellpower : int) -> bool : var is_crit : bool = casterchar.get_stat('Ranged_Crit_Rate') > randf() print('spellsbook bow sht is crit ? ', is_crit) return is_crit #returns the damage multiplayer of the critical hits, obviously necessary of the spell can. static func get_critical_mult(casterchar, defender, spellpower : int ) -> float : return casterchar.get_stat('Ranged_Crit_Mult')
#returns the maximum range of the spell static func get_range(power : int, casterchar) -> int : if casterchar.current_ammo_weapon != casterchar.ITEM_NO_AMMO_WEAPON : return 12 + casterchar.current_ammo_weapon['stats']['Range'] else : return 0
#two functions used to display the damage range in the Spell Cast menu, #and maybe actual calculations static func get_min_damage(power:int, casterchar) : return 1*power + floor( casterchar.get_stat('Strength') 0.05 ) static func get_max_damage(power:int, casterchar) : return 6power + floor( casterchar.get_stat('Strength') *0.3 )
#the actual damage roll. static func get_damage_roll(power : int, casterchar) : var dmg : int = 0 var mindmg : int = 1 var maxdmg : int = 6 var mindmgfromstats : int= floor( float( casterchar.get_stat('Strength') ) *0.05 ) var maxdmgfromstats : int = floor( float( casterchar.get_stat('Strength') ) *0.3 ) for i in range(power) : dmg += mindmg+ randi()%maxdmg + mindmgfromstats + randi_range(0,maxdmgfromstats) return dmg
#get the caster's accuracy stat used for this spell, and the defender's evasion stat. #(mandatory if the spell doesn't ignore evasion) static func get_accuracy(casterchar, defender,power : int) : return casterchar.get_stat('AccuracyRanged') static func get_evasion(casterchar, defender, power : int) : return defender.get_stat('EvasionRanged')
#returns the Area of Effect of this spell based on the caster and power level. #returns either a String (b7 wh cr etc) or an Array of Vector2 for a custom shape. static func get_aoe(power : int, casterchar) : return 'b1'
#NOT MANDATORY #if casting this spells causes multiple spells to be castat the target, returns an array of [spell_name, spell_power] static func get_chain(power : int, casterchar) : return 'Bow Shot',1],['Bow Shot',2],['Bow Shot',3
#NOT MANDATORY #if the spell has an unusual special effect like giving a Trait, add it here. static func special_effect(power : int, casterchar) : print('PHASE TELEPORT !!!') var newtpos : Vector2 = GameState.spell_picked_tiles.keys()[0] casterchar.combat_button.position = Utils.GRID_SIZE * newtpos casterchar.position = newtpos
#NOT ACTUALLY MANDATORY BUT NICE, FOR MENU SPELLS static func can_use(chara : creature) -> bool : returns (chara.get_sp_cost(self,1)>=chara.get_stat('curSP') and chara.focus_counter==0)
if picked_spell._has_method("can_use") :
castButton.disabled = picked_spell.can_use(picked_character)
else :
castButton.disabled = false