io.stderr:write("Magic init\n");
magic_syllable_tbl = {a = "An", b = "Bet", c = "Corp", d = "Des", e = "Ex", f = "Flam", g = "Grav", h = "Hur",
                      i = "In", j = "Jux", k = "Kal", l = "Lor", m = "Mani", n = "Nox", o = "Ort", p = "Por",
                      q = "Quas", r = "Rel", s = "Sanct", t = "Tym", u = "Uus", v = "Vas", w = "Wis", x = "Xen",
                      y = "Ylem", z = "Zu"}
magic = {}
magic_invocations = {}

function magic_print_invocation_string(spell_num)
	local i
	local invocation = magic_spell_invocation(spell_num)
	
	for i = 1,#invocation do
		if i ~= 1 then
			print(" ")
		end
		print(magic_syllable_tbl[string.sub(invocation, i, i)])
	end
end

run_magic_script = function(invocation)
	local spell_num = magic_invocations[invocation]
    if spell_num == nil then
      io.stderr:write("No magic script found for invocation \"" .. invocation .. "\"\n");
      return
    end

--io.stderr:write("Running script \"" .. magic_invocations[invocation].script .."\"\n");
	
    --run_script(magic_invocations[invocation].script)
    magic_cast_spell(spell_num, nil, nil)
    return
end

g_magic_target = nil
g_magic_caster = nil
g_magic_spell_num = nil

function magic_cast_spell(spell_num, caster, target)
	g_magic_target = target
	g_magic_caster = caster
	g_magic_spell_num = spell_num
	if magic[spell_num+1] ~= nil then
		run_script(magic[spell_num+1].script)
	end
	g_magic_caster = nil
	g_magic_target = nil
	if g_avatar_died == true then
		actor_avatar_death()
	end
end

function magic_spell_name(spell_num)
	if magic[spell_num+1] ~= nil then
		return magic[spell_num+1].name
	end
	
	return "Unknown"
end

function magic_spell_invocation(spell_num)
	if magic[spell_num+1] ~= nil then
		return magic[spell_num+1].invocation
	end

	return ""
end

function magic_get_spell_list()
	local list = {}
	local insert = table.insert
	local k,v
	for k,v in pairs(magic) do
			insert(list, v)
	end
	
	return list
end

magic_init = function(name, invocation, reagents, circle, num, script)
	local spell_num = (circle-1) * 16 + (num-1); 
    local spell = {name=name,invocation=invocation,reagents=reagents,circle=circle,spell_num=spell_num,script=script}

    magic[spell_num+1] = spell
    magic_invocations[string.lower(invocation)] = spell_num

    io.stderr:write("Init Magic: " .. name .. " I: " .. invocation .. "\n")
end

function select_location_with_prompt(prompt)
if g_magic_target ~= nil then return g_magic_target end

print(prompt)
return get_target()
end

function select_location()
	return select_location_with_prompt("Location: ")
end

select_actor = function()
	if g_magic_target ~= nil then return map_get_actor(g_magic_target) end
	
	print("On whom: ");

	local loc = get_target()
	local actor
	
	if loc ~= nil then
		actor = map_get_actor(loc)
	end
	
	if actor == nil then
		print("nothing\n");
	else
		print(actor.name.."\n");
		if out_of_spell_range(actor.x, actor.y) then return end
	end

	return actor
end

select_obj = function()
	if g_magic_target ~= nil then return map_get_obj(g_magic_target) end
	
	print("On what: ");

	local obj = get_obj()
	
	if obj == nil then
		print("nothing\n");
	else
		print(obj.name .. "\n");
		if obj.on_map and out_of_spell_range(obj.x, obj.y) then return end
	end

	return obj 
end

function select_actor_or_obj()
	if g_magic_target ~= nil then return map_get_obj(g_magic_target) end

	local is_player = caster_is_player()

	local loc = select_location_with_prompt("On Whom: ")
	local actor = map_get_actor(loc)
	local obj
	if actor == nil then
		obj = map_get_obj(loc)
		actor = obj
		if is_player == true then
			if obj ~= nil then
				print(obj.name.."\n")
			else
				print("nothing\n")
			end
		end
	elseif is_player == true then
		print(actor.name.."\n")
	end

	magic_casting_fade_effect(caster)
	if loc == nil or actor == nil then magic_no_effect() return end
	if (obj == nil or obj.on_map) and out_of_spell_range(loc.x, loc.y) then return end

	return actor
end

function select_actor_with_projectile(projectile_tile, caster)

	if caster == nil then caster = magic_get_caster() end

	local is_player = caster_is_player()
	
	local loc = select_location_with_prompt("On Whom: ")
	local actor = map_get_actor(loc)
	if actor == nil then
		local obj = map_get_obj(loc)
		if is_player == true then
			if obj ~= nil then
				print(obj.name.."\n")
			else
				print("nothing\n")
			end
		end
	elseif is_player == true then
		print(actor.name.."\n")
	end
	
	magic_casting_fade_effect(caster)
	if loc == nil then magic_no_effect() return end
	if out_of_spell_range(loc.x, loc.y) then return end

	local hit_x, hit_y =  map_line_hit_check(caster.x, caster.y, loc.x, loc.y, loc.z)
	projectile(projectile_tile, caster.x, caster.y, hit_x, hit_y, 4)

	if hit_x ~= loc.x or hit_y ~= loc.y then magic_blocked() return end

	if actor == nil then magic_no_effect() return end

	return actor
end

function select_actor_or_obj_with_projectile(projectile_tile, caster)

	if caster == nil then caster = magic_get_caster() end

	local loc = select_location_with_prompt("On what: ")
	local item = map_get_actor(loc)
	if item == nil then
		item = map_get_obj(loc)
	end
	
	if item ~= nil then
		print(item.name)
	else
		print("nothing")
	end

	print("\n")

	magic_casting_fade_effect(caster)

	if loc == nil then magic_no_effect() return end
	if out_of_spell_range(loc.x, loc.y) then return end

	local hit_x, hit_y =  map_line_hit_check(caster.x, caster.y, loc.x, loc.y, loc.z)
	projectile(projectile_tile, caster.x, caster.y, hit_x, hit_y, 4)

	if hit_x ~= loc.x or hit_y ~= loc.y then magic_blocked() return end

	if item == nil then magic_no_effect() return end

	return item
end

function select_obj_with_projectile(projectile_tile, caster)

	if caster == nil then caster = magic_get_caster() end

	local loc = select_location_with_prompt("On What: ")
	local obj = map_get_obj(loc)
	if obj == nil then
		print("nothing\n");
	else
		print(obj.name.."\n");
	end

	magic_casting_fade_effect(caster)
	if loc == nil then magic_no_effect() return end
	if out_of_spell_range(loc.x, loc.y) then return end

	local hit_x, hit_y =  map_line_hit_check(caster.x, caster.y, loc.x, loc.y, loc.z)
	projectile(projectile_tile, caster.x, caster.y, hit_x, hit_y, 4)

	if hit_x ~= loc.x or hit_y ~= loc.y then magic_blocked() return end

	if obj == nil then magic_no_effect() return end

	return obj
end

function select_location_with_projectile(projectile_tile, caster)

if caster == nil then caster = magic_get_caster() end

local loc = select_location_with_prompt("Location: ")

magic_casting_fade_effect(caster)
if loc == nil then magic_no_effect() return end
if out_of_spell_range(loc.x, loc.y) then return end

local hit_x, hit_y =  map_line_hit_check(caster.x, caster.y, loc.x, loc.y, loc.z)
projectile(projectile_tile, caster.x, caster.y, hit_x, hit_y, 4)

if hit_x ~= loc.x or hit_y ~= loc.y then magic_blocked() return end

return loc
end

function select_spell()
	return get_spell()
end

function out_of_spell_range(target_x, target_y)
	if Actor.get_range(magic_get_caster(), target_x, target_y) > 7 then
		print("\nout of range\n")
		return true
	else
		return false
	end
end

function caster_get_location()	  
	 if g_magic_caster ~= nil then
	  	return {x = g_magic_caster.x, y = g_magic_caster.y, z = g_magic_caster.z}
	  end
	  
	  return player_get_location()
end

function magic_get_caster()
	if g_magic_caster ~= nil then return g_magic_caster end

	return Actor.get_player_actor()
end

function caster_is_player()
	if g_magic_caster == nil then return true end
	
	return false
end

function magic_casting_effect()
	local magic_level = math.floor(g_magic_spell_num / 0x10);

	play_sfx(SFX_CASTING_MAGIC_P1 + magic_level, true)
	play_sfx(SFX_CASTING_MAGIC_P2 + magic_level)
	xor_effect(1700)
end

function magic_casting_fade_effect(caster)
	if caster == nil then caster = magic_get_caster() end
	
	Actor.black_fade_effect(caster, 12, 20) -- 12 = colour red. 20 = fade_speed
end

function magic_remove_actor_enchantments(actor)
	local success = false
	fade_actor_blue(actor)
	if actor.asleep == true then
		actor.asleep = false
		success = true
	end
	if actor.poisoned == true then
		actor.poisoned = false
		success = true
	end
	if actor.paralysed == true then
		actor.paralyzed = false
		success = true
	end

	if actor_remove_charm(actor) == true then
		success = true
	end

	return success
end


function magic_wind(tile_num, caster, target_x, target_y)

	local target_z = caster.z

	local index = ((caster.y - target_y + 5) * 11) + (caster.x - target_x + 5) + 1

	local offset_x_low = movement_offset_x_tbl[g_projectile_offset_tbl[1][index]+1]
	local offset_x_high = movement_offset_x_tbl[g_projectile_offset_tbl[2][index]+1]

	local offset_y_low = movement_offset_y_tbl[g_projectile_offset_tbl[1][index]+1]
	local offset_y_high = movement_offset_y_tbl[g_projectile_offset_tbl[2][index]+1]

	local targets = {
		{x=target_x,
		y=target_y,
		z=target_z}, 
		{x=target_x + offset_x_low,
		y=target_y + offset_y_low,
		z=target_z},
		{x=target_x + offset_x_low + offset_x_low,
		y=target_y + offset_y_low + offset_y_low,
		z=target_z},
		{x=target_x + offset_x_high,
		y=target_y + offset_y_high,
		z=target_z},
		{x=target_x + offset_x_high + offset_x_high,
		y=target_y + offset_y_high + offset_y_high,
		z=target_z}
	}

	return projectile_anim_multi(tile_num, caster.x, caster.y, targets, 3, 1, 0)
end

function magic_wind_spell(spell_num, tile_num)

	local caster = magic_get_caster()
	local loc = select_location()

	if loc == nil then return end

	print("\n")

	if loc.x == caster.x and loc.y == caster.y then return magic_no_effect() end

	local hit_items = magic_wind(tile_num, caster, loc.x, loc.y)

	local k, v
	for k,v in pairs(hit_items) do
		if v.luatype == "actor" and v.actor_num ~= caster.actor_num then
			if spell_num == 83 then --flame wind
				spell_take_fire_dmg(caster, v)
				
			elseif spell_num == 87 then --poison wind
				spell_poison_actor(caster, v)
				
			elseif spell_num == 98 then --energy wind
				local exp = actor_hit(v, math.random(1, 0x1e))
				if exp ~= 0 then         
					caster.exp = caster.exp + exp
				end
						
				actor_yell_for_help(caster, v, 1)
				actor_hit_msg(v)
				
			elseif spell_num == 113 then --death wind
				spell_kill_actor(caster, v)
			end
			if g_avatar_died == true then
				break -- don't keep casting once Avatar is dead
			end
		end
	end
end

function magic_success()
	if caster_is_player() then
		print("\nSuccess\n")
		play_sfx(SFX_SUCCESS)
	end
end

function magic_no_effect()
	if caster_is_player() then
		print("\nNo effect\n")
		play_sfx(SFX_FAILURE)
	end
end

function magic_blocked()
	if caster_is_player() then
		print("\nBlocked!\n")
		play_sfx(SFX_FAILURE)
	end
end

function magic_failed()
	if caster_is_player() then
		print("\nFailed\n")
		play_sfx(SFX_FAILURE)
	end
end

function magic_not_possible()
	if caster_is_player() then
		print("\nNot possible\n")
		play_sfx(SFX_FAILURE)
	end
end

do
local init
--name, cast directly keys, reagents, level, level index, spell file
--MANDRAKE_ROOT 0x01, NIGHTSHADE 0x02, BLACK_PEARL 0x04, BLOOD_MOSS 0x08, SPIDER_SILK 0x10, GARLIC 0x20, GINSENG 0x40, SULFUROUS_ASH 0x80
--add reagent numbers together for reagents argument
magic_init("Create Food", "imy", 0x61, 1, 1, "u6/magic/circle_01/create_food.lua");
magic_init("Detect Magic", "wo", 0x82, 1, 2, "u6/magic/circle_01/detect_magic.lua");
magic_init("Detect Trap", "wj", 0x82, 1, 3, "u6/magic/circle_01/detect_trap.lua");
magic_init("Dispel Magic", "ajo", 0x60, 1, 4, "u6/magic/circle_01/dispel_magic.lua");
magic_init("Douse", "af", 0x24, 1, 5, "u6/magic/circle_01/douse.lua");
magic_init("Harm", "am", 0x12, 1, 6, "u6/magic/circle_01/harm.lua");
magic_init("Heal", "im", 0x50, 1, 7, "u6/magic/circle_01/heal.lua");
magic_init("Help", "kl", 0x00, 1, 8, "u6/magic/circle_01/help.lua");
magic_init("Ignite", "if", 0x84, 1, 9, "u6/magic/circle_01/ignite.lua");
magic_init("Light", "il", 0x80, 1, 10, "u6/magic/circle_01/light.lua");

magic_init("Infravision", "ql", 0x82, 2, 1, "u6/magic/circle_02/infravision.lua");
magic_init("Magic Arrow", "oj", 0x84, 2, 2, "u6/magic/circle_02/magic_arrow.lua");
magic_init("Poison", "inp", 0x0e, 2, 3, "u6/magic/circle_02/poison.lua");
magic_init("Reappear", "iy", 0x1c, 2, 4, "u6/magic/circle_02/reappear.lua");
magic_init("Sleep", "iz", 0x16, 2, 5, "u6/magic/circle_02/sleep.lua");
magic_init("Telekinesis", "opy", 0x0d, 2, 6, "u6/magic/circle_02/telekinesis.lua");
magic_init("Trap", "ij", 0x12, 2, 7, "u6/magic/circle_02/trap.lua");
magic_init("Unlock Magic", "ep", 0x88, 2, 8, "u6/magic/circle_02/unlock_magic.lua");
magic_init("Untrap", "aj", 0x88, 2, 9, "u6/magic/circle_02/untrap.lua");
magic_init("Vanish", "ay", 0x2c, 2, 10, "u6/magic/circle_02/vanish.lua");

magic_init("Curse", "as", 0xa2, 3, 1, "u6/magic/circle_03/curse.lua");
magic_init("Dispel Field", "ag", 0x84, 3, 2, "u6/magic/circle_03/dispel_field.lua");
magic_init("Fireball", "pf", 0x84, 3, 3, "u6/magic/circle_03/fireball.lua");
magic_init("Great Light", "vl", 0x81, 3, 4, "u6/magic/circle_03/great_light.lua");
magic_init("Lock", "ap", 0xa8, 3, 5, "u6/magic/circle_03/magic_lock.lua");
magic_init("Mass Awaken", "avz", 0x60, 3, 6, "u6/magic/circle_03/mass_awaken.lua");
magic_init("Mass Sleep", "vz", 0x52, 3, 7, "u6/magic/circle_03/mass_sleep.lua");
magic_init("Peer", "vwy", 0x03, 3, 8, "u6/magic/circle_03/peer.lua");
magic_init("Protection", "is", 0xe0, 3, 9, "u6/magic/circle_03/protection.lua");
magic_init("Repel Undead", "axc", 0xa0, 3, 10, "u6/magic/circle_03/repel_undead.lua");

magic_init("Animate", "oy", 0x89, 4, 1, "u6/magic/circle_04/animate.lua");
magic_init("Conjure", "kx", 0x11, 4, 2, "u6/magic/circle_04/conjure.lua");
magic_init("Disable", "avm", 0x13, 4, 3, "u6/magic/circle_04/disable.lua");
magic_init("Fire Field", "ifg", 0x94, 4, 4, "u6/magic/circle_04/fire_field.lua");
magic_init("Great Heal", "vm", 0x51, 4, 5, "u6/magic/circle_04/great_heal.lua");
magic_init("Locate", "iw", 0x02, 4, 6, "u6/magic/circle_04/locate.lua");
magic_init("Mass Dispel", "vajo", 0x60, 4, 7, "u6/magic/circle_04/mass_dispel.lua"); -- The original engine uses 0x16
magic_init("Poison Field", "ing", 0x16, 4, 8, "u6/magic/circle_04/poison_field.lua"); -- The original engine uses 0x54
magic_init("Sleep Field", "izg", 0x54, 4, 9, "u6/magic/circle_04/sleep_field.lua"); -- The original engine uses 0x60
magic_init("Wind Change", "rh", 0x88, 4, 10, "u6/magic/circle_04/wind_change.lua");

magic_init("Energy Field", "isg", 0x15, 5, 1, "u6/magic/circle_05/energy_field.lua");
magic_init("Explosion", "vpf", 0x8d, 5, 2, "u6/magic/circle_05/explosion.lua");
magic_init("Insect Swarm", "kbx", 0x98, 5, 3, "u6/magic/circle_05/insect_swarm.lua");
magic_init("Invisibility", "sl", 0x0a, 5, 4, "u6/magic/circle_05/invisibility.lua");
magic_init("Lightning", "og", 0x85, 5, 5, "u6/magic/circle_05/lightning.lua");
magic_init("Paralyze", "axp", 0x96, 5, 6, "u6/magic/circle_05/paralyze.lua");
magic_init("Pickpocket", "py", 0x1a, 5, 7, "u6/magic/circle_05/pickpocket.lua");
magic_init("Reveal", "asl", 0x13, 5, 8, "u6/magic/circle_05/reveal.lua");
magic_init("Seance", "kmc", 0x9b, 5, 9, "u6/magic/circle_05/seance.lua");
magic_init("X-ray", "wy", 0x81, 5, 10, "u6/magic/circle_05/xray.lua");

magic_init("Charm", "axe", 0x16, 6, 1, "u6/magic/circle_06/charm.lua");
magic_init("Clone", "iqx", 0xdb, 6, 2, "u6/magic/circle_06/clone.lua");
magic_init("Confuse", "vq", 0x03, 6, 3, "u6/magic/circle_06/confuse.lua");
magic_init("Flame Wind", "fh", 0x89, 6, 4, "u6/magic/circle_06/flame_wind.lua");
magic_init("Hail Storm", "kdy", 0x0d, 6, 5, "u6/magic/circle_06/hail_storm.lua");
magic_init("Mass Protect", "vis", 0xe1, 6, 6, "u6/magic/circle_06/mass_protect.lua");
magic_init("Negate Magic", "ao", 0xa1, 6, 7, "u6/magic/circle_06/negate_magic.lua");
magic_init("Poison Wind", "nh", 0x8a, 6, 8, "u6/magic/circle_06/poison_wind.lua");
magic_init("Replicate", "iqy", 0xda, 6, 9, "u6/magic/circle_06/replicate.lua");
magic_init("Web", "idp", 0x10, 6, 10, "u6/magic/circle_06/web.lua");

magic_init("Chain Bolt", "vog", 0x8d, 7, 1, "u6/magic/circle_07/chain_bolt.lua");
magic_init("Enchant", "ioy", 0x91, 7, 2, "u6/magic/circle_07/enchant.lua");
magic_init("Energy Wind", "gh", 0x8b, 7, 3, "u6/magic/circle_07/energy_wind.lua");
magic_init("Fear", "qc", 0x23, 7, 4, "u6/magic/circle_07/fear.lua");
magic_init("Gate Travel", "vrp", 0x85, 7, 5, "u6/magic/circle_07/gate_travel.lua");
magic_init("Kill", "ic", 0x86, 7, 6, "u6/magic/circle_07/kill.lua");
magic_init("Mass Curse", "vas", 0xa3, 7, 7, "u6/magic/circle_07/mass_curse.lua");
magic_init("Mass Invis", "vsl", 0x0f, 7, 8, "u6/magic/circle_07/mass_invisibility.lua");
magic_init("Wing Strike", "kox", 0x99, 7, 9, "u6/magic/circle_07/wing_strike.lua");
magic_init("Wizard Eye", "pow", 0x9f, 7, 10, "u6/magic/circle_07/wizard_eye.lua");

magic_init("Armageddon", "vcbm", 0x00, 8, 1, "u6/magic/circle_08/armageddon.lua");
magic_init("Death Wind", "ch", 0x8b, 8, 2, "u6/magic/circle_08/death_wind.lua");
magic_init("Eclipse", "val", 0xab, 8, 3, "u6/magic/circle_08/eclipse.lua");
magic_init("Mass Charm", "vaxe", 0x17, 8, 4, "u6/magic/circle_08/mass_charm.lua");
magic_init("Mass Kill", "vc", 0x87, 8, 5, "u6/magic/circle_08/mass_kill.lua");
magic_init("Resurrect", "imc", 0xf9, 8, 6, "u6/magic/circle_08/resurrect.lua");
magic_init("Slime", "vrx", 0xb, 8, 7, "u6/magic/circle_08/slime.lua");
magic_init("Summon", "kxc", 0x39, 8, 8, "u6/magic/circle_08/summon.lua");
magic_init("Time Stop", "at", 0x29, 8, 9, "u6/magic/circle_08/time_stop.lua");
magic_init("Tremor", "vpy", 0x89, 8, 10, "u6/magic/circle_08/tremor.lua");

magic_init("Monster Invisible", "", 0x00, 8, 17, "u6/magic/circle_08/monster_invisible.lua");

end

magic_load = nil
